nsd-4.12.0/0000755000175000017500000000000015002373060011772 5ustar mozziemozziensd-4.12.0/configparser.c0000644000175000017500000040254315002373060014630 0ustar mozziemozzie/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse c_parse #define yylex c_lex #define yyerror c_error #define yydebug c_debug #define yynerrs c_nerrs #define yylval c_lval #define yychar c_char /* First part of user prologue. */ #line 10 "configparser.y" #include "config.h" #include #include #include #include #include "options.h" #include "util.h" #include "dname.h" #include "tsig.h" #include "rrl.h" int yylex(void); #ifdef __cplusplus extern "C" #endif /* these need to be global, otherwise they cannot be used inside yacc */ extern config_parser_state_type *cfg_parser; static void append_acl(struct acl_options **list, struct acl_options *acl); static void add_to_last_acl(struct acl_options **list, char *ac); static int parse_boolean(const char *str, int *bln); static int parse_catalog_role(const char *str, int *role); static int parse_expire_expr(const char *str, long long *num, uint8_t *expr); static int parse_number(const char *str, long long *num); static int parse_range(const char *str, long long *low, long long *high); struct component { struct component *next; char *str; }; #line 116 "configparser.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif #include "configparser.h" /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_STRING = 3, /* STRING */ YYSYMBOL_VAR_SERVER = 4, /* VAR_SERVER */ YYSYMBOL_VAR_SERVER_COUNT = 5, /* VAR_SERVER_COUNT */ YYSYMBOL_VAR_IP_ADDRESS = 6, /* VAR_IP_ADDRESS */ YYSYMBOL_VAR_IP_TRANSPARENT = 7, /* VAR_IP_TRANSPARENT */ YYSYMBOL_VAR_IP_FREEBIND = 8, /* VAR_IP_FREEBIND */ YYSYMBOL_VAR_REUSEPORT = 9, /* VAR_REUSEPORT */ YYSYMBOL_VAR_SEND_BUFFER_SIZE = 10, /* VAR_SEND_BUFFER_SIZE */ YYSYMBOL_VAR_RECEIVE_BUFFER_SIZE = 11, /* VAR_RECEIVE_BUFFER_SIZE */ YYSYMBOL_VAR_DEBUG_MODE = 12, /* VAR_DEBUG_MODE */ YYSYMBOL_VAR_IP4_ONLY = 13, /* VAR_IP4_ONLY */ YYSYMBOL_VAR_IP6_ONLY = 14, /* VAR_IP6_ONLY */ YYSYMBOL_VAR_DO_IP4 = 15, /* VAR_DO_IP4 */ YYSYMBOL_VAR_DO_IP6 = 16, /* VAR_DO_IP6 */ YYSYMBOL_VAR_PORT = 17, /* VAR_PORT */ YYSYMBOL_VAR_USE_SYSTEMD = 18, /* VAR_USE_SYSTEMD */ YYSYMBOL_VAR_VERBOSITY = 19, /* VAR_VERBOSITY */ YYSYMBOL_VAR_USERNAME = 20, /* VAR_USERNAME */ YYSYMBOL_VAR_CHROOT = 21, /* VAR_CHROOT */ YYSYMBOL_VAR_ZONESDIR = 22, /* VAR_ZONESDIR */ YYSYMBOL_VAR_ZONELISTFILE = 23, /* VAR_ZONELISTFILE */ YYSYMBOL_VAR_DATABASE = 24, /* VAR_DATABASE */ YYSYMBOL_VAR_LOGFILE = 25, /* VAR_LOGFILE */ YYSYMBOL_VAR_LOG_ONLY_SYSLOG = 26, /* VAR_LOG_ONLY_SYSLOG */ YYSYMBOL_VAR_PIDFILE = 27, /* VAR_PIDFILE */ YYSYMBOL_VAR_DIFFFILE = 28, /* VAR_DIFFFILE */ YYSYMBOL_VAR_XFRDFILE = 29, /* VAR_XFRDFILE */ YYSYMBOL_VAR_XFRDIR = 30, /* VAR_XFRDIR */ YYSYMBOL_VAR_HIDE_VERSION = 31, /* VAR_HIDE_VERSION */ YYSYMBOL_VAR_HIDE_IDENTITY = 32, /* VAR_HIDE_IDENTITY */ YYSYMBOL_VAR_VERSION = 33, /* VAR_VERSION */ YYSYMBOL_VAR_IDENTITY = 34, /* VAR_IDENTITY */ YYSYMBOL_VAR_NSID = 35, /* VAR_NSID */ YYSYMBOL_VAR_TCP_COUNT = 36, /* VAR_TCP_COUNT */ YYSYMBOL_VAR_TCP_REJECT_OVERFLOW = 37, /* VAR_TCP_REJECT_OVERFLOW */ YYSYMBOL_VAR_TCP_QUERY_COUNT = 38, /* VAR_TCP_QUERY_COUNT */ YYSYMBOL_VAR_TCP_TIMEOUT = 39, /* VAR_TCP_TIMEOUT */ YYSYMBOL_VAR_TCP_MSS = 40, /* VAR_TCP_MSS */ YYSYMBOL_VAR_OUTGOING_TCP_MSS = 41, /* VAR_OUTGOING_TCP_MSS */ YYSYMBOL_VAR_IPV4_EDNS_SIZE = 42, /* VAR_IPV4_EDNS_SIZE */ YYSYMBOL_VAR_IPV6_EDNS_SIZE = 43, /* VAR_IPV6_EDNS_SIZE */ YYSYMBOL_VAR_STATISTICS = 44, /* VAR_STATISTICS */ YYSYMBOL_VAR_XFRD_RELOAD_TIMEOUT = 45, /* VAR_XFRD_RELOAD_TIMEOUT */ YYSYMBOL_VAR_LOG_TIME_ASCII = 46, /* VAR_LOG_TIME_ASCII */ YYSYMBOL_VAR_LOG_TIME_ISO = 47, /* VAR_LOG_TIME_ISO */ YYSYMBOL_VAR_ROUND_ROBIN = 48, /* VAR_ROUND_ROBIN */ YYSYMBOL_VAR_MINIMAL_RESPONSES = 49, /* VAR_MINIMAL_RESPONSES */ YYSYMBOL_VAR_CONFINE_TO_ZONE = 50, /* VAR_CONFINE_TO_ZONE */ YYSYMBOL_VAR_REFUSE_ANY = 51, /* VAR_REFUSE_ANY */ YYSYMBOL_VAR_RELOAD_CONFIG = 52, /* VAR_RELOAD_CONFIG */ YYSYMBOL_VAR_ZONEFILES_CHECK = 53, /* VAR_ZONEFILES_CHECK */ YYSYMBOL_VAR_ZONEFILES_WRITE = 54, /* VAR_ZONEFILES_WRITE */ YYSYMBOL_VAR_RRL_SIZE = 55, /* VAR_RRL_SIZE */ YYSYMBOL_VAR_RRL_RATELIMIT = 56, /* VAR_RRL_RATELIMIT */ YYSYMBOL_VAR_RRL_SLIP = 57, /* VAR_RRL_SLIP */ YYSYMBOL_VAR_RRL_IPV4_PREFIX_LENGTH = 58, /* VAR_RRL_IPV4_PREFIX_LENGTH */ YYSYMBOL_VAR_RRL_IPV6_PREFIX_LENGTH = 59, /* VAR_RRL_IPV6_PREFIX_LENGTH */ YYSYMBOL_VAR_RRL_WHITELIST_RATELIMIT = 60, /* VAR_RRL_WHITELIST_RATELIMIT */ YYSYMBOL_VAR_TLS_SERVICE_KEY = 61, /* VAR_TLS_SERVICE_KEY */ YYSYMBOL_VAR_TLS_SERVICE_PEM = 62, /* VAR_TLS_SERVICE_PEM */ YYSYMBOL_VAR_TLS_SERVICE_OCSP = 63, /* VAR_TLS_SERVICE_OCSP */ YYSYMBOL_VAR_TLS_PORT = 64, /* VAR_TLS_PORT */ YYSYMBOL_VAR_TLS_AUTH_PORT = 65, /* VAR_TLS_AUTH_PORT */ YYSYMBOL_VAR_TLS_AUTH_XFR_ONLY = 66, /* VAR_TLS_AUTH_XFR_ONLY */ YYSYMBOL_VAR_TLS_CERT_BUNDLE = 67, /* VAR_TLS_CERT_BUNDLE */ YYSYMBOL_VAR_PROXY_PROTOCOL_PORT = 68, /* VAR_PROXY_PROTOCOL_PORT */ YYSYMBOL_VAR_CPU_AFFINITY = 69, /* VAR_CPU_AFFINITY */ YYSYMBOL_VAR_XFRD_CPU_AFFINITY = 70, /* VAR_XFRD_CPU_AFFINITY */ YYSYMBOL_VAR_SERVER_CPU_AFFINITY = 71, /* VAR_SERVER_CPU_AFFINITY */ YYSYMBOL_VAR_DROP_UPDATES = 72, /* VAR_DROP_UPDATES */ YYSYMBOL_VAR_XFRD_TCP_MAX = 73, /* VAR_XFRD_TCP_MAX */ YYSYMBOL_VAR_XFRD_TCP_PIPELINE = 74, /* VAR_XFRD_TCP_PIPELINE */ YYSYMBOL_VAR_METRICS_ENABLE = 75, /* VAR_METRICS_ENABLE */ YYSYMBOL_VAR_METRICS_INTERFACE = 76, /* VAR_METRICS_INTERFACE */ YYSYMBOL_VAR_METRICS_PORT = 77, /* VAR_METRICS_PORT */ YYSYMBOL_VAR_METRICS_PATH = 78, /* VAR_METRICS_PATH */ YYSYMBOL_VAR_DNSTAP = 79, /* VAR_DNSTAP */ YYSYMBOL_VAR_DNSTAP_ENABLE = 80, /* VAR_DNSTAP_ENABLE */ YYSYMBOL_VAR_DNSTAP_SOCKET_PATH = 81, /* VAR_DNSTAP_SOCKET_PATH */ YYSYMBOL_VAR_DNSTAP_IP = 82, /* VAR_DNSTAP_IP */ YYSYMBOL_VAR_DNSTAP_TLS = 83, /* VAR_DNSTAP_TLS */ YYSYMBOL_VAR_DNSTAP_TLS_SERVER_NAME = 84, /* VAR_DNSTAP_TLS_SERVER_NAME */ YYSYMBOL_VAR_DNSTAP_TLS_CERT_BUNDLE = 85, /* VAR_DNSTAP_TLS_CERT_BUNDLE */ YYSYMBOL_VAR_DNSTAP_TLS_CLIENT_KEY_FILE = 86, /* VAR_DNSTAP_TLS_CLIENT_KEY_FILE */ YYSYMBOL_VAR_DNSTAP_TLS_CLIENT_CERT_FILE = 87, /* VAR_DNSTAP_TLS_CLIENT_CERT_FILE */ YYSYMBOL_VAR_DNSTAP_SEND_IDENTITY = 88, /* VAR_DNSTAP_SEND_IDENTITY */ YYSYMBOL_VAR_DNSTAP_SEND_VERSION = 89, /* VAR_DNSTAP_SEND_VERSION */ YYSYMBOL_VAR_DNSTAP_IDENTITY = 90, /* VAR_DNSTAP_IDENTITY */ YYSYMBOL_VAR_DNSTAP_VERSION = 91, /* VAR_DNSTAP_VERSION */ YYSYMBOL_VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES = 92, /* VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES */ YYSYMBOL_VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES = 93, /* VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES */ YYSYMBOL_VAR_REMOTE_CONTROL = 94, /* VAR_REMOTE_CONTROL */ YYSYMBOL_VAR_CONTROL_ENABLE = 95, /* VAR_CONTROL_ENABLE */ YYSYMBOL_VAR_CONTROL_INTERFACE = 96, /* VAR_CONTROL_INTERFACE */ YYSYMBOL_VAR_CONTROL_PORT = 97, /* VAR_CONTROL_PORT */ YYSYMBOL_VAR_SERVER_KEY_FILE = 98, /* VAR_SERVER_KEY_FILE */ YYSYMBOL_VAR_SERVER_CERT_FILE = 99, /* VAR_SERVER_CERT_FILE */ YYSYMBOL_VAR_CONTROL_KEY_FILE = 100, /* VAR_CONTROL_KEY_FILE */ YYSYMBOL_VAR_CONTROL_CERT_FILE = 101, /* VAR_CONTROL_CERT_FILE */ YYSYMBOL_VAR_KEY = 102, /* VAR_KEY */ YYSYMBOL_VAR_ALGORITHM = 103, /* VAR_ALGORITHM */ YYSYMBOL_VAR_SECRET = 104, /* VAR_SECRET */ YYSYMBOL_VAR_TLS_AUTH = 105, /* VAR_TLS_AUTH */ YYSYMBOL_VAR_TLS_AUTH_DOMAIN_NAME = 106, /* VAR_TLS_AUTH_DOMAIN_NAME */ YYSYMBOL_VAR_TLS_AUTH_CLIENT_CERT = 107, /* VAR_TLS_AUTH_CLIENT_CERT */ YYSYMBOL_VAR_TLS_AUTH_CLIENT_KEY = 108, /* VAR_TLS_AUTH_CLIENT_KEY */ YYSYMBOL_VAR_TLS_AUTH_CLIENT_KEY_PW = 109, /* VAR_TLS_AUTH_CLIENT_KEY_PW */ YYSYMBOL_VAR_PATTERN = 110, /* VAR_PATTERN */ YYSYMBOL_VAR_NAME = 111, /* VAR_NAME */ YYSYMBOL_VAR_ZONEFILE = 112, /* VAR_ZONEFILE */ YYSYMBOL_VAR_NOTIFY = 113, /* VAR_NOTIFY */ YYSYMBOL_VAR_PROVIDE_XFR = 114, /* VAR_PROVIDE_XFR */ YYSYMBOL_VAR_ALLOW_QUERY = 115, /* VAR_ALLOW_QUERY */ YYSYMBOL_VAR_AXFR = 116, /* VAR_AXFR */ YYSYMBOL_VAR_UDP = 117, /* VAR_UDP */ YYSYMBOL_VAR_NOTIFY_RETRY = 118, /* VAR_NOTIFY_RETRY */ YYSYMBOL_VAR_ALLOW_NOTIFY = 119, /* VAR_ALLOW_NOTIFY */ YYSYMBOL_VAR_REQUEST_XFR = 120, /* VAR_REQUEST_XFR */ YYSYMBOL_VAR_ALLOW_AXFR_FALLBACK = 121, /* VAR_ALLOW_AXFR_FALLBACK */ YYSYMBOL_VAR_OUTGOING_INTERFACE = 122, /* VAR_OUTGOING_INTERFACE */ YYSYMBOL_VAR_ANSWER_COOKIE = 123, /* VAR_ANSWER_COOKIE */ YYSYMBOL_VAR_COOKIE_SECRET = 124, /* VAR_COOKIE_SECRET */ YYSYMBOL_VAR_COOKIE_SECRET_FILE = 125, /* VAR_COOKIE_SECRET_FILE */ YYSYMBOL_VAR_COOKIE_STAGING_SECRET = 126, /* VAR_COOKIE_STAGING_SECRET */ YYSYMBOL_VAR_MAX_REFRESH_TIME = 127, /* VAR_MAX_REFRESH_TIME */ YYSYMBOL_VAR_MIN_REFRESH_TIME = 128, /* VAR_MIN_REFRESH_TIME */ YYSYMBOL_VAR_MAX_RETRY_TIME = 129, /* VAR_MAX_RETRY_TIME */ YYSYMBOL_VAR_MIN_RETRY_TIME = 130, /* VAR_MIN_RETRY_TIME */ YYSYMBOL_VAR_MIN_EXPIRE_TIME = 131, /* VAR_MIN_EXPIRE_TIME */ YYSYMBOL_VAR_MULTI_PRIMARY_CHECK = 132, /* VAR_MULTI_PRIMARY_CHECK */ YYSYMBOL_VAR_SIZE_LIMIT_XFR = 133, /* VAR_SIZE_LIMIT_XFR */ YYSYMBOL_VAR_ZONESTATS = 134, /* VAR_ZONESTATS */ YYSYMBOL_VAR_INCLUDE_PATTERN = 135, /* VAR_INCLUDE_PATTERN */ YYSYMBOL_VAR_STORE_IXFR = 136, /* VAR_STORE_IXFR */ YYSYMBOL_VAR_IXFR_SIZE = 137, /* VAR_IXFR_SIZE */ YYSYMBOL_VAR_IXFR_NUMBER = 138, /* VAR_IXFR_NUMBER */ YYSYMBOL_VAR_CREATE_IXFR = 139, /* VAR_CREATE_IXFR */ YYSYMBOL_VAR_CATALOG = 140, /* VAR_CATALOG */ YYSYMBOL_VAR_CATALOG_MEMBER_PATTERN = 141, /* VAR_CATALOG_MEMBER_PATTERN */ YYSYMBOL_VAR_CATALOG_PRODUCER_ZONE = 142, /* VAR_CATALOG_PRODUCER_ZONE */ YYSYMBOL_VAR_ZONE = 143, /* VAR_ZONE */ YYSYMBOL_VAR_RRL_WHITELIST = 144, /* VAR_RRL_WHITELIST */ YYSYMBOL_VAR_SERVERS = 145, /* VAR_SERVERS */ YYSYMBOL_VAR_BINDTODEVICE = 146, /* VAR_BINDTODEVICE */ YYSYMBOL_VAR_SETFIB = 147, /* VAR_SETFIB */ YYSYMBOL_VAR_VERIFY = 148, /* VAR_VERIFY */ YYSYMBOL_VAR_ENABLE = 149, /* VAR_ENABLE */ YYSYMBOL_VAR_VERIFY_ZONE = 150, /* VAR_VERIFY_ZONE */ YYSYMBOL_VAR_VERIFY_ZONES = 151, /* VAR_VERIFY_ZONES */ YYSYMBOL_VAR_VERIFIER = 152, /* VAR_VERIFIER */ YYSYMBOL_VAR_VERIFIER_COUNT = 153, /* VAR_VERIFIER_COUNT */ YYSYMBOL_VAR_VERIFIER_FEED_ZONE = 154, /* VAR_VERIFIER_FEED_ZONE */ YYSYMBOL_VAR_VERIFIER_TIMEOUT = 155, /* VAR_VERIFIER_TIMEOUT */ YYSYMBOL_YYACCEPT = 156, /* $accept */ YYSYMBOL_blocks = 157, /* blocks */ YYSYMBOL_block = 158, /* block */ YYSYMBOL_server = 159, /* server */ YYSYMBOL_server_block = 160, /* server_block */ YYSYMBOL_server_option = 161, /* server_option */ YYSYMBOL_162_1 = 162, /* $@1 */ YYSYMBOL_socket_options = 163, /* socket_options */ YYSYMBOL_socket_option = 164, /* socket_option */ YYSYMBOL_cpus = 165, /* cpus */ YYSYMBOL_service_cpu_affinity = 166, /* service_cpu_affinity */ YYSYMBOL_dnstap = 167, /* dnstap */ YYSYMBOL_dnstap_block = 168, /* dnstap_block */ YYSYMBOL_dnstap_option = 169, /* dnstap_option */ YYSYMBOL_remote_control = 170, /* remote_control */ YYSYMBOL_remote_control_block = 171, /* remote_control_block */ YYSYMBOL_remote_control_option = 172, /* remote_control_option */ YYSYMBOL_tls_auth = 173, /* tls_auth */ YYSYMBOL_174_2 = 174, /* $@2 */ YYSYMBOL_tls_auth_block = 175, /* tls_auth_block */ YYSYMBOL_tls_auth_option = 176, /* tls_auth_option */ YYSYMBOL_key = 177, /* key */ YYSYMBOL_178_3 = 178, /* $@3 */ YYSYMBOL_key_block = 179, /* key_block */ YYSYMBOL_key_option = 180, /* key_option */ YYSYMBOL_zone = 181, /* zone */ YYSYMBOL_182_4 = 182, /* $@4 */ YYSYMBOL_zone_block = 183, /* zone_block */ YYSYMBOL_zone_option = 184, /* zone_option */ YYSYMBOL_pattern = 185, /* pattern */ YYSYMBOL_186_5 = 186, /* $@5 */ YYSYMBOL_pattern_block = 187, /* pattern_block */ YYSYMBOL_pattern_option = 188, /* pattern_option */ YYSYMBOL_pattern_or_zone_option = 189, /* pattern_or_zone_option */ YYSYMBOL_190_6 = 190, /* $@6 */ YYSYMBOL_191_7 = 191, /* $@7 */ YYSYMBOL_192_8 = 192, /* $@8 */ YYSYMBOL_verify = 193, /* verify */ YYSYMBOL_verify_block = 194, /* verify_block */ YYSYMBOL_verify_option = 195, /* verify_option */ YYSYMBOL_command = 196, /* command */ YYSYMBOL_arguments = 197, /* arguments */ YYSYMBOL_ip_address = 198, /* ip_address */ YYSYMBOL_number = 199, /* number */ YYSYMBOL_boolean = 200, /* boolean */ YYSYMBOL_request_xfr_tlsauth_option = 201, /* request_xfr_tlsauth_option */ YYSYMBOL_provide_xfr_tlsauth_option = 202, /* provide_xfr_tlsauth_option */ YYSYMBOL_catalog_role = 203 /* catalog_role */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int16 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 515 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 156 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 48 /* YYNRULES -- Number of rules. */ #define YYNRULES 213 /* YYNSTATES -- Number of states. */ #define YYNSTATES 372 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 410 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 242, 242, 244, 247, 248, 249, 250, 251, 252, 253, 254, 257, 260, 260, 264, 263, 280, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 312, 314, 316, 318, 320, 350, 352, 354, 362, 364, 366, 368, 370, 372, 374, 376, 378, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 417, 423, 429, 439, 449, 455, 457, 459, 461, 466, 471, 476, 481, 483, 485, 487, 489, 491, 498, 505, 513, 515, 523, 525, 536, 547, 559, 561, 563, 567, 595, 601, 613, 623, 631, 632, 635, 662, 664, 669, 670, 704, 706, 717, 720, 720, 723, 725, 727, 729, 731, 733, 735, 737, 739, 741, 743, 745, 747, 749, 754, 757, 757, 760, 762, 772, 780, 782, 784, 786, 792, 791, 813, 813, 816, 827, 831, 835, 839, 847, 846, 871, 871, 874, 886, 894, 913, 912, 937, 937, 940, 953, 957, 956, 973, 973, 976, 983, 986, 992, 994, 996, 1004, 1006, 1009, 1008, 1022, 1021, 1033, 1043, 1048, 1058, 1057, 1064, 1069, 1074, 1079, 1084, 1089, 1094, 1099, 1104, 1116, 1121, 1126, 1131, 1136, 1138, 1140, 1142, 1144, 1151, 1155, 1171, 1174, 1174, 1177, 1179, 1189, 1196, 1198, 1200, 1202, 1204, 1208, 1228, 1229, 1247, 1257, 1266, 1274, 1275, 1279, 1280, 1285 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "STRING", "VAR_SERVER", "VAR_SERVER_COUNT", "VAR_IP_ADDRESS", "VAR_IP_TRANSPARENT", "VAR_IP_FREEBIND", "VAR_REUSEPORT", "VAR_SEND_BUFFER_SIZE", "VAR_RECEIVE_BUFFER_SIZE", "VAR_DEBUG_MODE", "VAR_IP4_ONLY", "VAR_IP6_ONLY", "VAR_DO_IP4", "VAR_DO_IP6", "VAR_PORT", "VAR_USE_SYSTEMD", "VAR_VERBOSITY", "VAR_USERNAME", "VAR_CHROOT", "VAR_ZONESDIR", "VAR_ZONELISTFILE", "VAR_DATABASE", "VAR_LOGFILE", "VAR_LOG_ONLY_SYSLOG", "VAR_PIDFILE", "VAR_DIFFFILE", "VAR_XFRDFILE", "VAR_XFRDIR", "VAR_HIDE_VERSION", "VAR_HIDE_IDENTITY", "VAR_VERSION", "VAR_IDENTITY", "VAR_NSID", "VAR_TCP_COUNT", "VAR_TCP_REJECT_OVERFLOW", "VAR_TCP_QUERY_COUNT", "VAR_TCP_TIMEOUT", "VAR_TCP_MSS", "VAR_OUTGOING_TCP_MSS", "VAR_IPV4_EDNS_SIZE", "VAR_IPV6_EDNS_SIZE", "VAR_STATISTICS", "VAR_XFRD_RELOAD_TIMEOUT", "VAR_LOG_TIME_ASCII", "VAR_LOG_TIME_ISO", "VAR_ROUND_ROBIN", "VAR_MINIMAL_RESPONSES", "VAR_CONFINE_TO_ZONE", "VAR_REFUSE_ANY", "VAR_RELOAD_CONFIG", "VAR_ZONEFILES_CHECK", "VAR_ZONEFILES_WRITE", "VAR_RRL_SIZE", "VAR_RRL_RATELIMIT", "VAR_RRL_SLIP", "VAR_RRL_IPV4_PREFIX_LENGTH", "VAR_RRL_IPV6_PREFIX_LENGTH", "VAR_RRL_WHITELIST_RATELIMIT", "VAR_TLS_SERVICE_KEY", "VAR_TLS_SERVICE_PEM", "VAR_TLS_SERVICE_OCSP", "VAR_TLS_PORT", "VAR_TLS_AUTH_PORT", "VAR_TLS_AUTH_XFR_ONLY", "VAR_TLS_CERT_BUNDLE", "VAR_PROXY_PROTOCOL_PORT", "VAR_CPU_AFFINITY", "VAR_XFRD_CPU_AFFINITY", "VAR_SERVER_CPU_AFFINITY", "VAR_DROP_UPDATES", "VAR_XFRD_TCP_MAX", "VAR_XFRD_TCP_PIPELINE", "VAR_METRICS_ENABLE", "VAR_METRICS_INTERFACE", "VAR_METRICS_PORT", "VAR_METRICS_PATH", "VAR_DNSTAP", "VAR_DNSTAP_ENABLE", "VAR_DNSTAP_SOCKET_PATH", "VAR_DNSTAP_IP", "VAR_DNSTAP_TLS", "VAR_DNSTAP_TLS_SERVER_NAME", "VAR_DNSTAP_TLS_CERT_BUNDLE", "VAR_DNSTAP_TLS_CLIENT_KEY_FILE", "VAR_DNSTAP_TLS_CLIENT_CERT_FILE", "VAR_DNSTAP_SEND_IDENTITY", "VAR_DNSTAP_SEND_VERSION", "VAR_DNSTAP_IDENTITY", "VAR_DNSTAP_VERSION", "VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES", "VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES", "VAR_REMOTE_CONTROL", "VAR_CONTROL_ENABLE", "VAR_CONTROL_INTERFACE", "VAR_CONTROL_PORT", "VAR_SERVER_KEY_FILE", "VAR_SERVER_CERT_FILE", "VAR_CONTROL_KEY_FILE", "VAR_CONTROL_CERT_FILE", "VAR_KEY", "VAR_ALGORITHM", "VAR_SECRET", "VAR_TLS_AUTH", "VAR_TLS_AUTH_DOMAIN_NAME", "VAR_TLS_AUTH_CLIENT_CERT", "VAR_TLS_AUTH_CLIENT_KEY", "VAR_TLS_AUTH_CLIENT_KEY_PW", "VAR_PATTERN", "VAR_NAME", "VAR_ZONEFILE", "VAR_NOTIFY", "VAR_PROVIDE_XFR", "VAR_ALLOW_QUERY", "VAR_AXFR", "VAR_UDP", "VAR_NOTIFY_RETRY", "VAR_ALLOW_NOTIFY", "VAR_REQUEST_XFR", "VAR_ALLOW_AXFR_FALLBACK", "VAR_OUTGOING_INTERFACE", "VAR_ANSWER_COOKIE", "VAR_COOKIE_SECRET", "VAR_COOKIE_SECRET_FILE", "VAR_COOKIE_STAGING_SECRET", "VAR_MAX_REFRESH_TIME", "VAR_MIN_REFRESH_TIME", "VAR_MAX_RETRY_TIME", "VAR_MIN_RETRY_TIME", "VAR_MIN_EXPIRE_TIME", "VAR_MULTI_PRIMARY_CHECK", "VAR_SIZE_LIMIT_XFR", "VAR_ZONESTATS", "VAR_INCLUDE_PATTERN", "VAR_STORE_IXFR", "VAR_IXFR_SIZE", "VAR_IXFR_NUMBER", "VAR_CREATE_IXFR", "VAR_CATALOG", "VAR_CATALOG_MEMBER_PATTERN", "VAR_CATALOG_PRODUCER_ZONE", "VAR_ZONE", "VAR_RRL_WHITELIST", "VAR_SERVERS", "VAR_BINDTODEVICE", "VAR_SETFIB", "VAR_VERIFY", "VAR_ENABLE", "VAR_VERIFY_ZONE", "VAR_VERIFY_ZONES", "VAR_VERIFIER", "VAR_VERIFIER_COUNT", "VAR_VERIFIER_FEED_ZONE", "VAR_VERIFIER_TIMEOUT", "$accept", "blocks", "block", "server", "server_block", "server_option", "$@1", "socket_options", "socket_option", "cpus", "service_cpu_affinity", "dnstap", "dnstap_block", "dnstap_option", "remote_control", "remote_control_block", "remote_control_option", "tls_auth", "$@2", "tls_auth_block", "tls_auth_option", "key", "$@3", "key_block", "key_option", "zone", "$@4", "zone_block", "zone_option", "pattern", "$@5", "pattern_block", "pattern_option", "pattern_or_zone_option", "$@6", "$@7", "$@8", "verify", "verify_block", "verify_option", "command", "arguments", "ip_address", "number", "boolean", "request_xfr_tlsauth_option", "provide_xfr_tlsauth_option", "catalog_role", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-184) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { -184, 32, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 389, 246, -46, -184, -184, -184, -184, -4, 0, 6, 8, 8, 8, 0, 0, 8, 8, 8, 8, 8, 0, 8, 0, 11, 13, 14, 18, 19, 22, 8, 23, 25, 27, 28, 8, 8, 43, 44, 53, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 54, 56, 57, 0, 0, 8, 58, 0, -184, -184, -184, 8, 0, 0, 8, 6, 0, 59, 8, 60, 62, 63, -184, 0, 8, 65, 69, 8, 71, 72, 76, 78, 8, 8, 79, 80, 8, 8, -184, 8, 6, 0, 81, 84, 85, 88, -184, -84, 46, 70, 143, 6, 0, 8, 8, 90, 0, 8, 0, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 91, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 93, 102, 105, -184, 106, 109, 117, 118, 119, -184, 122, 127, 128, 132, 135, 0, 136, 12, 8, 137, 0, 0, 0, 0, 138, 8, 0, 141, 153, 8, 0, 0, 8, 155, 156, 157, 159, 8, 90, 8, 0, -184, -184, 160, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 161, 162, 163, -184, 164, 165, 166, 167, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 168, -112, -184, -184, -184, -184, -184, 170, 171, -184, 174, 8, 0, -184, 176, 183, -184, -184, -184, -184, -184, -184, -184, -184, -184, 183, -184 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 1, 14, 104, 121, 138, 129, 151, 145, 194, 3, 4, 5, 6, 8, 7, 10, 9, 11, 12, 102, 119, 141, 132, 154, 148, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 120, 139, 130, 152, 146, 0, 0, 0, 0, 0, 0, 0, 0, 193, 207, 17, 206, 15, 208, 18, 19, 47, 20, 21, 22, 27, 28, 29, 30, 46, 23, 57, 50, 49, 51, 52, 31, 35, 36, 45, 53, 54, 55, 24, 25, 33, 32, 34, 37, 38, 39, 40, 41, 42, 43, 44, 48, 56, 67, 68, 69, 70, 71, 72, 64, 65, 66, 58, 59, 60, 61, 62, 63, 73, 75, 74, 76, 77, 78, 79, 80, 87, 26, 85, 86, 89, 90, 91, 92, 81, 82, 84, 83, 88, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 128, 0, 0, 0, 140, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 156, 0, 147, 150, 196, 197, 195, 198, 204, 199, 200, 202, 201, 93, 99, 143, 144, 142, 134, 135, 136, 137, 133, 155, 158, 0, 0, 0, 175, 0, 0, 0, 0, 174, 173, 176, 177, 178, 179, 180, 161, 160, 159, 162, 181, 182, 183, 184, 213, 189, 190, 191, 157, 185, 186, 187, 188, 149, 203, 16, 169, 170, 172, 168, 163, 0, 0, 205, 0, 0, 0, 94, 211, 209, 165, 167, 95, 96, 97, 212, 171, 210, 164, 209, 166 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -61, -184, -184, -184, -184, -184, -184, -137, -184, -87, 36, -31, -183, -184, -184 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { 0, 1, 11, 12, 20, 106, 300, 346, 358, 211, 107, 13, 21, 122, 14, 22, 130, 15, 24, 132, 254, 16, 23, 131, 248, 17, 26, 134, 289, 18, 25, 133, 286, 287, 360, 370, 359, 19, 27, 143, 296, 345, 147, 145, 149, 369, 367, 336 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 150, 151, 135, 144, 154, 155, 156, 157, 158, 146, 160, 148, 216, 136, 162, 317, 163, 164, 168, 245, 246, 165, 166, 173, 174, 167, 169, 247, 170, 179, 171, 172, 2, 355, 356, 357, 3, 239, 188, 189, 190, 191, 192, 193, 194, 195, 175, 176, 291, 123, 124, 125, 126, 127, 128, 129, 177, 203, 208, 204, 205, 209, 218, 220, 212, 221, 222, 215, 225, 152, 153, 219, 226, 290, 228, 229, 159, 224, 161, 230, 227, 231, 234, 235, 241, 232, 233, 242, 243, 236, 237, 244, 238, 295, 301, 178, 302, 180, 181, 182, 183, 184, 185, 186, 187, 303, 293, 294, 304, 305, 298, 4, 306, 196, 197, 198, 199, 200, 201, 202, 307, 308, 309, 206, 207, 310, 5, 210, 318, 319, 311, 312, 213, 214, 6, 313, 217, 7, 314, 316, 321, 326, 8, 223, 329, 137, 341, 138, 139, 140, 141, 142, 249, 250, 251, 252, 330, 253, 335, 337, 338, 240, 339, 344, 347, 348, 349, 350, 351, 352, 353, 354, 292, 361, 362, 9, 297, 363, 299, 366, 10, 255, 256, 257, 258, 259, 368, 371, 260, 261, 262, 263, 264, 0, 0, 0, 0, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 0, 281, 0, 0, 0, 0, 0, 282, 0, 283, 0, 284, 285, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 331, 0, 0, 334, 0, 0, 0, 0, 340, 0, 342, 288, 256, 257, 258, 259, 0, 0, 260, 261, 262, 263, 264, 0, 0, 0, 0, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 0, 281, 0, 0, 0, 0, 0, 282, 0, 283, 315, 284, 285, 0, 0, 322, 323, 324, 325, 0, 0, 328, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 364, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 103, 104, 105 }; static const yytype_int16 yycheck[] = { 31, 32, 6, 3, 35, 36, 37, 38, 39, 3, 41, 3, 99, 17, 3, 3, 3, 3, 49, 103, 104, 3, 3, 54, 55, 3, 3, 111, 3, 60, 3, 3, 0, 145, 146, 147, 4, 124, 69, 70, 71, 72, 73, 74, 75, 76, 3, 3, 135, 95, 96, 97, 98, 99, 100, 101, 3, 3, 89, 3, 3, 3, 3, 3, 95, 3, 3, 98, 3, 33, 34, 102, 3, 134, 3, 3, 40, 108, 42, 3, 111, 3, 3, 3, 3, 116, 117, 3, 3, 120, 121, 3, 123, 3, 3, 59, 3, 61, 62, 63, 64, 65, 66, 67, 68, 3, 137, 138, 3, 3, 141, 79, 3, 77, 78, 79, 80, 81, 82, 83, 3, 3, 3, 87, 88, 3, 94, 91, 116, 117, 3, 3, 96, 97, 102, 3, 100, 105, 3, 3, 3, 3, 110, 107, 3, 149, 283, 151, 152, 153, 154, 155, 106, 107, 108, 109, 3, 111, 3, 3, 3, 125, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 136, 3, 3, 143, 140, 3, 142, 3, 148, 111, 112, 113, 114, 115, 3, 370, 118, 119, 120, 121, 122, -1, -1, -1, -1, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, -1, 144, -1, -1, -1, -1, -1, 150, -1, 152, -1, 154, 155, -1, -1, -1, -1, -1, -1, 263, -1, -1, -1, -1, -1, -1, 270, -1, -1, -1, 274, -1, -1, 277, -1, -1, -1, -1, 282, -1, 284, 111, 112, 113, 114, 115, -1, -1, 118, 119, 120, 121, 122, -1, -1, -1, -1, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, -1, 144, -1, -1, -1, -1, -1, 150, -1, 152, 260, 154, 155, -1, -1, 265, 266, 267, 268, -1, -1, 271, -1, -1, -1, 275, 276, -1, -1, -1, -1, -1, -1, -1, -1, 285, -1, -1, -1, 356, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 357, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, 124, 125, 126 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 157, 0, 4, 79, 94, 102, 105, 110, 143, 148, 158, 159, 167, 170, 173, 177, 181, 185, 193, 160, 168, 171, 178, 174, 186, 182, 194, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 123, 124, 125, 126, 161, 166, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 169, 95, 96, 97, 98, 99, 100, 101, 172, 179, 175, 187, 183, 6, 17, 149, 151, 152, 153, 154, 155, 195, 3, 199, 3, 198, 3, 200, 200, 200, 199, 199, 200, 200, 200, 200, 200, 199, 200, 199, 3, 3, 3, 3, 3, 3, 200, 3, 3, 3, 3, 200, 200, 3, 3, 3, 199, 200, 199, 199, 199, 199, 199, 199, 199, 199, 200, 200, 200, 200, 200, 200, 200, 200, 199, 199, 199, 199, 199, 199, 199, 3, 3, 3, 199, 199, 200, 3, 199, 165, 200, 199, 199, 200, 198, 199, 3, 200, 3, 3, 3, 199, 200, 3, 3, 200, 3, 3, 3, 3, 200, 200, 3, 3, 200, 200, 200, 198, 199, 3, 3, 3, 3, 103, 104, 111, 180, 106, 107, 108, 109, 111, 176, 111, 112, 113, 114, 115, 118, 119, 120, 121, 122, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 144, 150, 152, 154, 155, 188, 189, 111, 184, 189, 198, 199, 200, 200, 3, 196, 199, 200, 199, 162, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 199, 3, 3, 116, 117, 200, 3, 199, 199, 199, 199, 3, 200, 199, 3, 3, 200, 199, 199, 200, 3, 203, 3, 3, 3, 200, 196, 200, 199, 3, 197, 163, 3, 3, 3, 3, 3, 3, 3, 3, 145, 146, 147, 164, 192, 190, 3, 3, 3, 200, 199, 3, 202, 3, 201, 191, 201 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_uint8 yyr1[] = { 0, 156, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 159, 160, 160, 162, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 163, 163, 164, 164, 164, 165, 165, 166, 166, 167, 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 171, 172, 172, 172, 172, 172, 172, 172, 174, 173, 175, 175, 176, 176, 176, 176, 176, 178, 177, 179, 179, 180, 180, 180, 182, 181, 183, 183, 184, 184, 186, 185, 187, 187, 188, 188, 189, 189, 189, 189, 189, 189, 190, 189, 191, 189, 189, 189, 189, 192, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 193, 194, 194, 195, 195, 195, 195, 195, 195, 195, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 202, 203 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 1, 1, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 3, 2, 0, 2, 2, 2, 2, 2, 0, 3, 2, 0, 2, 2, 2, 0, 3, 2, 0, 2, 1, 0, 3, 2, 0, 2, 1, 2, 2, 2, 2, 2, 2, 0, 5, 0, 6, 4, 3, 3, 0, 5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 1, 1, 1, 0, 1, 0, 1, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 15: /* $@1: %empty */ #line 264 "configparser.y" { struct ip_address_option *ip = cfg_parser->opt->ip_addresses; if(ip == NULL) { cfg_parser->opt->ip_addresses = (yyvsp[0].ip); } else { while(ip->next) { ip = ip->next; } ip->next = (yyvsp[0].ip); } cfg_parser->ip = (yyvsp[0].ip); } #line 1662 "configparser.c" break; case 16: /* server_option: VAR_IP_ADDRESS ip_address $@1 socket_options */ #line 277 "configparser.y" { cfg_parser->ip = NULL; } #line 1670 "configparser.c" break; case 17: /* server_option: VAR_SERVER_COUNT number */ #line 281 "configparser.y" { if ((yyvsp[0].llng) > 0) { cfg_parser->opt->server_count = (int)(yyvsp[0].llng); } else { yyerror("expected a number greater than zero"); } } #line 1682 "configparser.c" break; case 18: /* server_option: VAR_IP_TRANSPARENT boolean */ #line 289 "configparser.y" { cfg_parser->opt->ip_transparent = (yyvsp[0].bln); } #line 1688 "configparser.c" break; case 19: /* server_option: VAR_IP_FREEBIND boolean */ #line 291 "configparser.y" { cfg_parser->opt->ip_freebind = (yyvsp[0].bln); } #line 1694 "configparser.c" break; case 20: /* server_option: VAR_SEND_BUFFER_SIZE number */ #line 293 "configparser.y" { cfg_parser->opt->send_buffer_size = (int)(yyvsp[0].llng); } #line 1700 "configparser.c" break; case 21: /* server_option: VAR_RECEIVE_BUFFER_SIZE number */ #line 295 "configparser.y" { cfg_parser->opt->receive_buffer_size = (int)(yyvsp[0].llng); } #line 1706 "configparser.c" break; case 22: /* server_option: VAR_DEBUG_MODE boolean */ #line 297 "configparser.y" { cfg_parser->opt->debug_mode = (yyvsp[0].bln); } #line 1712 "configparser.c" break; case 23: /* server_option: VAR_USE_SYSTEMD boolean */ #line 299 "configparser.y" { /* ignored, obsolete */ } #line 1718 "configparser.c" break; case 24: /* server_option: VAR_HIDE_VERSION boolean */ #line 301 "configparser.y" { cfg_parser->opt->hide_version = (yyvsp[0].bln); } #line 1724 "configparser.c" break; case 25: /* server_option: VAR_HIDE_IDENTITY boolean */ #line 303 "configparser.y" { cfg_parser->opt->hide_identity = (yyvsp[0].bln); } #line 1730 "configparser.c" break; case 26: /* server_option: VAR_DROP_UPDATES boolean */ #line 305 "configparser.y" { cfg_parser->opt->drop_updates = (yyvsp[0].bln); } #line 1736 "configparser.c" break; case 27: /* server_option: VAR_IP4_ONLY boolean */ #line 307 "configparser.y" { if((yyvsp[0].bln)) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } } #line 1742 "configparser.c" break; case 28: /* server_option: VAR_IP6_ONLY boolean */ #line 309 "configparser.y" { if((yyvsp[0].bln)) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } } #line 1748 "configparser.c" break; case 29: /* server_option: VAR_DO_IP4 boolean */ #line 311 "configparser.y" { cfg_parser->opt->do_ip4 = (yyvsp[0].bln); } #line 1754 "configparser.c" break; case 30: /* server_option: VAR_DO_IP6 boolean */ #line 313 "configparser.y" { cfg_parser->opt->do_ip6 = (yyvsp[0].bln); } #line 1760 "configparser.c" break; case 31: /* server_option: VAR_DATABASE STRING */ #line 315 "configparser.y" { /* ignored, obsolete */ } #line 1766 "configparser.c" break; case 32: /* server_option: VAR_IDENTITY STRING */ #line 317 "configparser.y" { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1772 "configparser.c" break; case 33: /* server_option: VAR_VERSION STRING */ #line 319 "configparser.y" { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1778 "configparser.c" break; case 34: /* server_option: VAR_NSID STRING */ #line 321 "configparser.y" { unsigned char* nsid = 0; size_t nsid_len = strlen((yyvsp[0].str)); if (strncasecmp((yyvsp[0].str), "ascii_", 6) == 0) { nsid_len -= 6; /* discard "ascii_" */ if(nsid_len < 65535) { cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); hex_ntop((uint8_t*)(yyvsp[0].str)+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); } else { yyerror("NSID too long"); } } else if (nsid_len % 2 != 0) { yyerror("the NSID must be a hex string of an even length."); } else { nsid_len = nsid_len / 2; if(nsid_len < 65535) { nsid = xalloc(nsid_len); if (hex_pton((yyvsp[0].str), nsid, nsid_len) == -1) { yyerror("hex string cannot be parsed in NSID."); } else { cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } free(nsid); } else { yyerror("NSID too long"); } } } #line 1812 "configparser.c" break; case 35: /* server_option: VAR_LOGFILE STRING */ #line 351 "configparser.y" { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1818 "configparser.c" break; case 36: /* server_option: VAR_LOG_ONLY_SYSLOG boolean */ #line 353 "configparser.y" { cfg_parser->opt->log_only_syslog = (yyvsp[0].bln); } #line 1824 "configparser.c" break; case 37: /* server_option: VAR_TCP_COUNT number */ #line 355 "configparser.y" { if ((yyvsp[0].llng) > 0) { cfg_parser->opt->tcp_count = (int)(yyvsp[0].llng); } else { yyerror("expected a number greater than zero"); } } #line 1836 "configparser.c" break; case 38: /* server_option: VAR_TCP_REJECT_OVERFLOW boolean */ #line 363 "configparser.y" { cfg_parser->opt->tcp_reject_overflow = (yyvsp[0].bln); } #line 1842 "configparser.c" break; case 39: /* server_option: VAR_TCP_QUERY_COUNT number */ #line 365 "configparser.y" { cfg_parser->opt->tcp_query_count = (int)(yyvsp[0].llng); } #line 1848 "configparser.c" break; case 40: /* server_option: VAR_TCP_TIMEOUT number */ #line 367 "configparser.y" { cfg_parser->opt->tcp_timeout = (int)(yyvsp[0].llng); } #line 1854 "configparser.c" break; case 41: /* server_option: VAR_TCP_MSS number */ #line 369 "configparser.y" { cfg_parser->opt->tcp_mss = (int)(yyvsp[0].llng); } #line 1860 "configparser.c" break; case 42: /* server_option: VAR_OUTGOING_TCP_MSS number */ #line 371 "configparser.y" { cfg_parser->opt->outgoing_tcp_mss = (int)(yyvsp[0].llng); } #line 1866 "configparser.c" break; case 43: /* server_option: VAR_IPV4_EDNS_SIZE number */ #line 373 "configparser.y" { cfg_parser->opt->ipv4_edns_size = (size_t)(yyvsp[0].llng); } #line 1872 "configparser.c" break; case 44: /* server_option: VAR_IPV6_EDNS_SIZE number */ #line 375 "configparser.y" { cfg_parser->opt->ipv6_edns_size = (size_t)(yyvsp[0].llng); } #line 1878 "configparser.c" break; case 45: /* server_option: VAR_PIDFILE STRING */ #line 377 "configparser.y" { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1884 "configparser.c" break; case 46: /* server_option: VAR_PORT number */ #line 379 "configparser.y" { /* port number, stored as a string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", (yyvsp[0].llng)); cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf); } #line 1895 "configparser.c" break; case 47: /* server_option: VAR_REUSEPORT boolean */ #line 386 "configparser.y" { cfg_parser->opt->reuseport = (yyvsp[0].bln); } #line 1901 "configparser.c" break; case 48: /* server_option: VAR_STATISTICS number */ #line 388 "configparser.y" { cfg_parser->opt->statistics = (int)(yyvsp[0].llng); } #line 1907 "configparser.c" break; case 49: /* server_option: VAR_CHROOT STRING */ #line 390 "configparser.y" { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1913 "configparser.c" break; case 50: /* server_option: VAR_USERNAME STRING */ #line 392 "configparser.y" { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1919 "configparser.c" break; case 51: /* server_option: VAR_ZONESDIR STRING */ #line 394 "configparser.y" { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1925 "configparser.c" break; case 52: /* server_option: VAR_ZONELISTFILE STRING */ #line 396 "configparser.y" { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1931 "configparser.c" break; case 53: /* server_option: VAR_DIFFFILE STRING */ #line 398 "configparser.y" { /* ignored, obsolete */ } #line 1937 "configparser.c" break; case 54: /* server_option: VAR_XFRDFILE STRING */ #line 400 "configparser.y" { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1943 "configparser.c" break; case 55: /* server_option: VAR_XFRDIR STRING */ #line 402 "configparser.y" { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1949 "configparser.c" break; case 56: /* server_option: VAR_XFRD_RELOAD_TIMEOUT number */ #line 404 "configparser.y" { cfg_parser->opt->xfrd_reload_timeout = (int)(yyvsp[0].llng); } #line 1955 "configparser.c" break; case 57: /* server_option: VAR_VERBOSITY number */ #line 406 "configparser.y" { cfg_parser->opt->verbosity = (int)(yyvsp[0].llng); } #line 1961 "configparser.c" break; case 58: /* server_option: VAR_RRL_SIZE number */ #line 408 "configparser.y" { #ifdef RATELIMIT if ((yyvsp[0].llng) > 0) { cfg_parser->opt->rrl_size = (size_t)(yyvsp[0].llng); } else { yyerror("expected a number greater than zero"); } #endif } #line 1975 "configparser.c" break; case 59: /* server_option: VAR_RRL_RATELIMIT number */ #line 418 "configparser.y" { #ifdef RATELIMIT cfg_parser->opt->rrl_ratelimit = (size_t)(yyvsp[0].llng); #endif } #line 1985 "configparser.c" break; case 60: /* server_option: VAR_RRL_SLIP number */ #line 424 "configparser.y" { #ifdef RATELIMIT cfg_parser->opt->rrl_slip = (size_t)(yyvsp[0].llng); #endif } #line 1995 "configparser.c" break; case 61: /* server_option: VAR_RRL_IPV4_PREFIX_LENGTH number */ #line 430 "configparser.y" { #ifdef RATELIMIT if ((yyvsp[0].llng) > 32) { yyerror("invalid IPv4 prefix length"); } else { cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)(yyvsp[0].llng); } #endif } #line 2009 "configparser.c" break; case 62: /* server_option: VAR_RRL_IPV6_PREFIX_LENGTH number */ #line 440 "configparser.y" { #ifdef RATELIMIT if ((yyvsp[0].llng) > 64) { yyerror("invalid IPv6 prefix length"); } else { cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)(yyvsp[0].llng); } #endif } #line 2023 "configparser.c" break; case 63: /* server_option: VAR_RRL_WHITELIST_RATELIMIT number */ #line 450 "configparser.y" { #ifdef RATELIMIT cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)(yyvsp[0].llng); #endif } #line 2033 "configparser.c" break; case 64: /* server_option: VAR_RELOAD_CONFIG boolean */ #line 456 "configparser.y" { cfg_parser->opt->reload_config = (yyvsp[0].bln); } #line 2039 "configparser.c" break; case 65: /* server_option: VAR_ZONEFILES_CHECK boolean */ #line 458 "configparser.y" { cfg_parser->opt->zonefiles_check = (yyvsp[0].bln); } #line 2045 "configparser.c" break; case 66: /* server_option: VAR_ZONEFILES_WRITE number */ #line 460 "configparser.y" { cfg_parser->opt->zonefiles_write = (int)(yyvsp[0].llng); } #line 2051 "configparser.c" break; case 67: /* server_option: VAR_LOG_TIME_ASCII boolean */ #line 462 "configparser.y" { cfg_parser->opt->log_time_ascii = (yyvsp[0].bln); log_time_asc = cfg_parser->opt->log_time_ascii; } #line 2060 "configparser.c" break; case 68: /* server_option: VAR_LOG_TIME_ISO boolean */ #line 467 "configparser.y" { cfg_parser->opt->log_time_iso = (yyvsp[0].bln); log_time_iso = cfg_parser->opt->log_time_iso; } #line 2069 "configparser.c" break; case 69: /* server_option: VAR_ROUND_ROBIN boolean */ #line 472 "configparser.y" { cfg_parser->opt->round_robin = (yyvsp[0].bln); round_robin = cfg_parser->opt->round_robin; } #line 2078 "configparser.c" break; case 70: /* server_option: VAR_MINIMAL_RESPONSES boolean */ #line 477 "configparser.y" { cfg_parser->opt->minimal_responses = (yyvsp[0].bln); minimal_responses = cfg_parser->opt->minimal_responses; } #line 2087 "configparser.c" break; case 71: /* server_option: VAR_CONFINE_TO_ZONE boolean */ #line 482 "configparser.y" { cfg_parser->opt->confine_to_zone = (yyvsp[0].bln); } #line 2093 "configparser.c" break; case 72: /* server_option: VAR_REFUSE_ANY boolean */ #line 484 "configparser.y" { cfg_parser->opt->refuse_any = (yyvsp[0].bln); } #line 2099 "configparser.c" break; case 73: /* server_option: VAR_TLS_SERVICE_KEY STRING */ #line 486 "configparser.y" { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2105 "configparser.c" break; case 74: /* server_option: VAR_TLS_SERVICE_OCSP STRING */ #line 488 "configparser.y" { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2111 "configparser.c" break; case 75: /* server_option: VAR_TLS_SERVICE_PEM STRING */ #line 490 "configparser.y" { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2117 "configparser.c" break; case 76: /* server_option: VAR_TLS_PORT number */ #line 492 "configparser.y" { /* port number, stored as string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", (yyvsp[0].llng)); cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf); } #line 2128 "configparser.c" break; case 77: /* server_option: VAR_TLS_AUTH_PORT number */ #line 499 "configparser.y" { /* port number, stored as string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", (yyvsp[0].llng)); cfg_parser->opt->tls_auth_port = region_strdup(cfg_parser->opt->region, buf); } #line 2139 "configparser.c" break; case 78: /* server_option: VAR_TLS_AUTH_XFR_ONLY boolean */ #line 506 "configparser.y" { if (!cfg_parser->opt->tls_auth_port) { yyerror("tls-auth-xfr-only set without or before tls-auth-port"); YYABORT; } cfg_parser->opt->tls_auth_xfr_only = (yyvsp[0].bln); } #line 2151 "configparser.c" break; case 79: /* server_option: VAR_TLS_CERT_BUNDLE STRING */ #line 514 "configparser.y" { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2157 "configparser.c" break; case 80: /* server_option: VAR_PROXY_PROTOCOL_PORT number */ #line 516 "configparser.y" { struct proxy_protocol_port_list* elem = region_alloc_zero( cfg_parser->opt->region, sizeof(*elem)); elem->port = (yyvsp[0].llng); elem->next = cfg_parser->opt->proxy_protocol_port; cfg_parser->opt->proxy_protocol_port = elem; } #line 2169 "configparser.c" break; case 81: /* server_option: VAR_ANSWER_COOKIE boolean */ #line 524 "configparser.y" { cfg_parser->opt->answer_cookie = (yyvsp[0].bln); } #line 2175 "configparser.c" break; case 82: /* server_option: VAR_COOKIE_SECRET STRING */ #line 526 "configparser.y" { uint8_t secret[32]; ssize_t len = hex_pton((yyvsp[0].str), secret, NSD_COOKIE_SECRET_SIZE); if(len != NSD_COOKIE_SECRET_SIZE) { yyerror("expected a 128 bit hex string"); } else { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } } #line 2190 "configparser.c" break; case 83: /* server_option: VAR_COOKIE_STAGING_SECRET STRING */ #line 537 "configparser.y" { uint8_t secret[32]; ssize_t len = hex_pton((yyvsp[0].str), secret, NSD_COOKIE_SECRET_SIZE); if(len != NSD_COOKIE_SECRET_SIZE) { yyerror("expected a 128 bit hex string"); } else { cfg_parser->opt->cookie_staging_secret = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } } #line 2205 "configparser.c" break; case 84: /* server_option: VAR_COOKIE_SECRET_FILE STRING */ #line 548 "configparser.y" { /* Empty filename means explicitly disabled cookies from file, internally * represented as NULL. * Note that after parsing, if no value was configured, then * cookie_secret_file_is_default is still 1, then the default cookie * secret file value will be assigned to cookie_secret_file. */ if(*(yyvsp[0].str)) cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); cfg_parser->opt->cookie_secret_file_is_default = 0; } #line 2220 "configparser.c" break; case 85: /* server_option: VAR_XFRD_TCP_MAX number */ #line 560 "configparser.y" { cfg_parser->opt->xfrd_tcp_max = (int)(yyvsp[0].llng); } #line 2226 "configparser.c" break; case 86: /* server_option: VAR_XFRD_TCP_PIPELINE number */ #line 562 "configparser.y" { cfg_parser->opt->xfrd_tcp_pipeline = (int)(yyvsp[0].llng); } #line 2232 "configparser.c" break; case 87: /* server_option: VAR_CPU_AFFINITY cpus */ #line 564 "configparser.y" { cfg_parser->opt->cpu_affinity = (yyvsp[0].cpu); } #line 2240 "configparser.c" break; case 88: /* server_option: service_cpu_affinity number */ #line 568 "configparser.y" { if((yyvsp[0].llng) < 0) { yyerror("expected a non-negative number"); YYABORT; } else { struct cpu_map_option *opt, *tail; opt = cfg_parser->opt->service_cpu_affinity; while(opt && opt->service != (yyvsp[-1].llng)) { opt = opt->next; } if(opt) { opt->cpu = (yyvsp[0].llng); } else { opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt)); opt->service = (int)(yyvsp[-1].llng); opt->cpu = (int)(yyvsp[0].llng); tail = cfg_parser->opt->service_cpu_affinity; if(tail) { while(tail->next) { tail = tail->next; } tail->next = opt; } else { cfg_parser->opt->service_cpu_affinity = opt; } } } } #line 2272 "configparser.c" break; case 89: /* server_option: VAR_METRICS_ENABLE boolean */ #line 596 "configparser.y" { #ifdef USE_METRICS cfg_parser->opt->metrics_enable = (yyvsp[0].bln); #endif /* USE_METRICS */ } #line 2282 "configparser.c" break; case 90: /* server_option: VAR_METRICS_INTERFACE ip_address */ #line 602 "configparser.y" { #ifdef USE_METRICS struct ip_address_option *ip = cfg_parser->opt->metrics_interface; if(ip == NULL) { cfg_parser->opt->metrics_interface = (yyvsp[0].ip); } else { while(ip->next != NULL) { ip = ip->next; } ip->next = (yyvsp[0].ip); } #endif /* USE_METRICS */ } #line 2298 "configparser.c" break; case 91: /* server_option: VAR_METRICS_PORT number */ #line 614 "configparser.y" { #ifdef USE_METRICS if((yyvsp[0].llng) == 0) { yyerror("metrics port number expected"); } else { cfg_parser->opt->metrics_port = (int)(yyvsp[0].llng); } #endif /* USE_METRICS */ } #line 2312 "configparser.c" break; case 92: /* server_option: VAR_METRICS_PATH STRING */ #line 624 "configparser.y" { #ifdef USE_METRICS cfg_parser->opt->metrics_path = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); #endif /* USE_METRICS */ } #line 2322 "configparser.c" break; case 95: /* socket_option: VAR_SERVERS STRING */ #line 636 "configparser.y" { char *tok, *ptr, *str; struct range_option *servers = NULL; long long first, last; /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */ for(str = (yyvsp[0].str); (tok = strtok_r(str, " \t", &ptr)); str = NULL) { struct range_option *opt = region_alloc(cfg_parser->opt->region, sizeof(*opt)); first = last = 0; if(!parse_range(tok, &first, &last)) { yyerror("invalid server range '%s'", tok); YYABORT; } assert(first >= 0); assert(last >= 0); opt->next = NULL; opt->first = (int)first; opt->last = (int)last; if(servers) { servers = servers->next = opt; } else { servers = cfg_parser->ip->servers = opt; } } } #line 2353 "configparser.c" break; case 96: /* socket_option: VAR_BINDTODEVICE boolean */ #line 663 "configparser.y" { cfg_parser->ip->dev = (yyvsp[0].bln); } #line 2359 "configparser.c" break; case 97: /* socket_option: VAR_SETFIB number */ #line 665 "configparser.y" { cfg_parser->ip->fib = (yyvsp[0].llng); } #line 2365 "configparser.c" break; case 98: /* cpus: %empty */ #line 669 "configparser.y" { (yyval.cpu) = NULL; } #line 2371 "configparser.c" break; case 99: /* cpus: cpus STRING */ #line 671 "configparser.y" { char *tok, *ptr, *str; struct cpu_option *tail; long long cpu; str = (yyvsp[0].str); (yyval.cpu) = tail = (yyvsp[-1].cpu); if(tail) { while(tail->next) { tail = tail->next; } } /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */ for(str = (yyvsp[0].str); (tok = strtok_r(str, " \t", &ptr)); str = NULL) { struct cpu_option *opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt)); cpu = 0; if(!parse_number(tok, &cpu) || cpu < 0) { yyerror("expected a positive number"); YYABORT; } assert(cpu >=0); opt->cpu = (int)cpu; if(tail) { tail->next = opt; tail = opt; } else { (yyval.cpu) = tail = opt; } } } #line 2406 "configparser.c" break; case 100: /* service_cpu_affinity: VAR_XFRD_CPU_AFFINITY */ #line 705 "configparser.y" { (yyval.llng) = -1; } #line 2412 "configparser.c" break; case 101: /* service_cpu_affinity: VAR_SERVER_CPU_AFFINITY */ #line 707 "configparser.y" { if((yyvsp[0].llng) <= 0) { yyerror("invalid server identifier"); YYABORT; } (yyval.llng) = (yyvsp[0].llng); } #line 2424 "configparser.c" break; case 105: /* dnstap_option: VAR_DNSTAP_ENABLE boolean */ #line 724 "configparser.y" { cfg_parser->opt->dnstap_enable = (yyvsp[0].bln); } #line 2430 "configparser.c" break; case 106: /* dnstap_option: VAR_DNSTAP_SOCKET_PATH STRING */ #line 726 "configparser.y" { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2436 "configparser.c" break; case 107: /* dnstap_option: VAR_DNSTAP_IP STRING */ #line 728 "configparser.y" { cfg_parser->opt->dnstap_ip = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2442 "configparser.c" break; case 108: /* dnstap_option: VAR_DNSTAP_TLS boolean */ #line 730 "configparser.y" { cfg_parser->opt->dnstap_tls = (yyvsp[0].bln); } #line 2448 "configparser.c" break; case 109: /* dnstap_option: VAR_DNSTAP_TLS_SERVER_NAME STRING */ #line 732 "configparser.y" { cfg_parser->opt->dnstap_tls_server_name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2454 "configparser.c" break; case 110: /* dnstap_option: VAR_DNSTAP_TLS_CERT_BUNDLE STRING */ #line 734 "configparser.y" { cfg_parser->opt->dnstap_tls_cert_bundle = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2460 "configparser.c" break; case 111: /* dnstap_option: VAR_DNSTAP_TLS_CLIENT_KEY_FILE STRING */ #line 736 "configparser.y" { cfg_parser->opt->dnstap_tls_client_key_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2466 "configparser.c" break; case 112: /* dnstap_option: VAR_DNSTAP_TLS_CLIENT_CERT_FILE STRING */ #line 738 "configparser.y" { cfg_parser->opt->dnstap_tls_client_cert_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2472 "configparser.c" break; case 113: /* dnstap_option: VAR_DNSTAP_SEND_IDENTITY boolean */ #line 740 "configparser.y" { cfg_parser->opt->dnstap_send_identity = (yyvsp[0].bln); } #line 2478 "configparser.c" break; case 114: /* dnstap_option: VAR_DNSTAP_SEND_VERSION boolean */ #line 742 "configparser.y" { cfg_parser->opt->dnstap_send_version = (yyvsp[0].bln); } #line 2484 "configparser.c" break; case 115: /* dnstap_option: VAR_DNSTAP_IDENTITY STRING */ #line 744 "configparser.y" { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2490 "configparser.c" break; case 116: /* dnstap_option: VAR_DNSTAP_VERSION STRING */ #line 746 "configparser.y" { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2496 "configparser.c" break; case 117: /* dnstap_option: VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean */ #line 748 "configparser.y" { cfg_parser->opt->dnstap_log_auth_query_messages = (yyvsp[0].bln); } #line 2502 "configparser.c" break; case 118: /* dnstap_option: VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean */ #line 750 "configparser.y" { cfg_parser->opt->dnstap_log_auth_response_messages = (yyvsp[0].bln); } #line 2508 "configparser.c" break; case 122: /* remote_control_option: VAR_CONTROL_ENABLE boolean */ #line 761 "configparser.y" { cfg_parser->opt->control_enable = (yyvsp[0].bln); } #line 2514 "configparser.c" break; case 123: /* remote_control_option: VAR_CONTROL_INTERFACE ip_address */ #line 763 "configparser.y" { struct ip_address_option *ip = cfg_parser->opt->control_interface; if(ip == NULL) { cfg_parser->opt->control_interface = (yyvsp[0].ip); } else { while(ip->next != NULL) { ip = ip->next; } ip->next = (yyvsp[0].ip); } } #line 2528 "configparser.c" break; case 124: /* remote_control_option: VAR_CONTROL_PORT number */ #line 773 "configparser.y" { if((yyvsp[0].llng) == 0) { yyerror("control port number expected"); } else { cfg_parser->opt->control_port = (int)(yyvsp[0].llng); } } #line 2540 "configparser.c" break; case 125: /* remote_control_option: VAR_SERVER_KEY_FILE STRING */ #line 781 "configparser.y" { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2546 "configparser.c" break; case 126: /* remote_control_option: VAR_SERVER_CERT_FILE STRING */ #line 783 "configparser.y" { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2552 "configparser.c" break; case 127: /* remote_control_option: VAR_CONTROL_KEY_FILE STRING */ #line 785 "configparser.y" { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2558 "configparser.c" break; case 128: /* remote_control_option: VAR_CONTROL_CERT_FILE STRING */ #line 787 "configparser.y" { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2564 "configparser.c" break; case 129: /* $@2: %empty */ #line 792 "configparser.y" { tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region); assert(cfg_parser->tls_auth == NULL); cfg_parser->tls_auth = tls_auth; } #line 2574 "configparser.c" break; case 130: /* tls_auth: VAR_TLS_AUTH $@2 tls_auth_block */ #line 798 "configparser.y" { struct tls_auth_options *tls_auth = cfg_parser->tls_auth; if(tls_auth->name == NULL) { yyerror("tls-auth has no name"); } else if(tls_auth->auth_domain_name == NULL) { yyerror("tls-auth %s has no auth-domain-name", tls_auth->name); } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) { yyerror("duplicate tls-auth %s", tls_auth->name); } else { tls_auth_options_insert(cfg_parser->opt, tls_auth); cfg_parser->tls_auth = NULL; } } #line 2592 "configparser.c" break; case 133: /* tls_auth_option: VAR_NAME STRING */ #line 817 "configparser.y" { dname_type *dname; dname = (dname_type *)dname_parse(cfg_parser->opt->region, (yyvsp[0].str)); cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if(dname == NULL) { yyerror("bad tls-auth name %s", (yyvsp[0].str)); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); } } #line 2607 "configparser.c" break; case 134: /* tls_auth_option: VAR_TLS_AUTH_DOMAIN_NAME STRING */ #line 828 "configparser.y" { cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2615 "configparser.c" break; case 135: /* tls_auth_option: VAR_TLS_AUTH_CLIENT_CERT STRING */ #line 832 "configparser.y" { cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2623 "configparser.c" break; case 136: /* tls_auth_option: VAR_TLS_AUTH_CLIENT_KEY STRING */ #line 836 "configparser.y" { cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2631 "configparser.c" break; case 137: /* tls_auth_option: VAR_TLS_AUTH_CLIENT_KEY_PW STRING */ #line 840 "configparser.y" { cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2639 "configparser.c" break; case 138: /* $@3: %empty */ #line 847 "configparser.y" { key_options_type *key = key_options_create(cfg_parser->opt->region); key->algorithm = region_strdup(cfg_parser->opt->region, "sha256"); assert(cfg_parser->key == NULL); cfg_parser->key = key; } #line 2650 "configparser.c" break; case 139: /* key: VAR_KEY $@3 key_block */ #line 854 "configparser.y" { struct key_options *key = cfg_parser->key; if(key->name == NULL) { yyerror("tsig key has no name"); } else if(key->algorithm == NULL) { yyerror("tsig key %s has no algorithm", key->name); } else if(key->secret == NULL) { yyerror("tsig key %s has no secret blob", key->name); } else if(key_options_find(cfg_parser->opt, key->name)) { yyerror("duplicate tsig key %s", key->name); } else { key_options_insert(cfg_parser->opt, key); cfg_parser->key = NULL; } } #line 2670 "configparser.c" break; case 142: /* key_option: VAR_NAME STRING */ #line 875 "configparser.y" { dname_type *dname; dname = (dname_type *)dname_parse(cfg_parser->opt->region, (yyvsp[0].str)); cfg_parser->key->name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if(dname == NULL) { yyerror("bad tsig key name %s", (yyvsp[0].str)); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); } } #line 2686 "configparser.c" break; case 143: /* key_option: VAR_ALGORITHM STRING */ #line 887 "configparser.y" { if(tsig_get_algorithm_by_name((yyvsp[0].str)) == NULL) { yyerror("bad tsig key algorithm %s", (yyvsp[0].str)); } else { cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } } #line 2698 "configparser.c" break; case 144: /* key_option: VAR_SECRET STRING */ #line 895 "configparser.y" { uint8_t data[16384]; int size; cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); size = b64_pton((yyvsp[0].str), data, sizeof(data)); if(size == -1) { yyerror("cannot base64 decode tsig secret %s", cfg_parser->key->name? cfg_parser->key->name:""); } else if(size != 0) { memset(data, 0xdd, size); /* wipe secret */ } } #line 2717 "configparser.c" break; case 145: /* $@4: %empty */ #line 913 "configparser.y" { assert(cfg_parser->pattern == NULL); assert(cfg_parser->zone == NULL); cfg_parser->zone = zone_options_create(cfg_parser->opt->region); cfg_parser->zone->part_of_config = 1; cfg_parser->zone->pattern = cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region); cfg_parser->zone->pattern->implicit = 1; } #line 2731 "configparser.c" break; case 146: /* zone: VAR_ZONE $@4 zone_block */ #line 923 "configparser.y" { assert(cfg_parser->zone != NULL); if(cfg_parser->zone->name == NULL) { yyerror("zone has no name"); } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) { yyerror("duplicate zone %s", cfg_parser->zone->name); } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) { yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname); } cfg_parser->pattern = NULL; cfg_parser->zone = NULL; } #line 2748 "configparser.c" break; case 149: /* zone_option: VAR_NAME STRING */ #line 941 "configparser.y" { const char *marker = PATTERN_IMPLICIT_MARKER; char *pname = region_alloc(cfg_parser->opt->region, strlen((yyvsp[0].str)) + strlen(marker) + 1); memmove(pname, marker, strlen(marker)); memmove(pname + strlen(marker), (yyvsp[0].str), strlen((yyvsp[0].str)) + 1); cfg_parser->zone->pattern->pname = pname; cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if(pattern_options_find(cfg_parser->opt, pname)) { yyerror("zone %s cannot be created because implicit pattern %s " "already exists", (yyvsp[0].str), pname); } } #line 2765 "configparser.c" break; case 151: /* $@5: %empty */ #line 957 "configparser.y" { assert(cfg_parser->pattern == NULL); cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region); } #line 2774 "configparser.c" break; case 152: /* pattern: VAR_PATTERN $@5 pattern_block */ #line 962 "configparser.y" { pattern_options_type *pattern = cfg_parser->pattern; if(pattern->pname == NULL) { yyerror("pattern has no name"); } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) { yyerror("duplicate pattern %s", pattern->pname); } cfg_parser->pattern = NULL; } #line 2788 "configparser.c" break; case 155: /* pattern_option: VAR_NAME STRING */ #line 977 "configparser.y" { if(strchr((yyvsp[0].str), ' ')) { yyerror("space is not allowed in pattern name: '%s'", (yyvsp[0].str)); } cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2799 "configparser.c" break; case 157: /* pattern_or_zone_option: VAR_RRL_WHITELIST STRING */ #line 987 "configparser.y" { #ifdef RATELIMIT cfg_parser->pattern->rrl_whitelist |= rrlstr2type((yyvsp[0].str)); #endif } #line 2809 "configparser.c" break; case 158: /* pattern_or_zone_option: VAR_ZONEFILE STRING */ #line 993 "configparser.y" { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2815 "configparser.c" break; case 159: /* pattern_or_zone_option: VAR_ZONESTATS STRING */ #line 995 "configparser.y" { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2821 "configparser.c" break; case 160: /* pattern_or_zone_option: VAR_SIZE_LIMIT_XFR number */ #line 997 "configparser.y" { if((yyvsp[0].llng) > 0) { cfg_parser->pattern->size_limit_xfr = (int)(yyvsp[0].llng); } else { yyerror("expected a number greater than zero"); } } #line 2833 "configparser.c" break; case 161: /* pattern_or_zone_option: VAR_MULTI_PRIMARY_CHECK boolean */ #line 1005 "configparser.y" { cfg_parser->pattern->multi_primary_check = (int)(yyvsp[0].bln); } #line 2839 "configparser.c" break; case 162: /* pattern_or_zone_option: VAR_INCLUDE_PATTERN STRING */ #line 1007 "configparser.y" { config_apply_pattern(cfg_parser->pattern, (yyvsp[0].str)); } #line 2845 "configparser.c" break; case 163: /* $@6: %empty */ #line 1009 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); if(cfg_parser->pattern->catalog_role == CATALOG_ROLE_PRODUCER) yyerror("catalog producer zones cannot be secondary zones"); if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } #line 2860 "configparser.c" break; case 164: /* pattern_or_zone_option: VAR_REQUEST_XFR STRING STRING $@6 request_xfr_tlsauth_option */ #line 1020 "configparser.y" { } #line 2866 "configparser.c" break; case 165: /* $@7: %empty */ #line 1022 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); acl->use_axfr_only = 1; if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } #line 2880 "configparser.c" break; case 166: /* pattern_or_zone_option: VAR_REQUEST_XFR VAR_AXFR STRING STRING $@7 request_xfr_tlsauth_option */ #line 1032 "configparser.y" { } #line 2886 "configparser.c" break; case 167: /* pattern_or_zone_option: VAR_REQUEST_XFR VAR_UDP STRING STRING */ #line 1034 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); acl->allow_udp = 1; if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } #line 2900 "configparser.c" break; case 168: /* pattern_or_zone_option: VAR_ALLOW_NOTIFY STRING STRING */ #line 1044 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); append_acl(&cfg_parser->pattern->allow_notify, acl); } #line 2909 "configparser.c" break; case 169: /* pattern_or_zone_option: VAR_NOTIFY STRING STRING */ #line 1049 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); if(acl->blocked) yyerror("blocked address used for notify"); if(acl->rangetype != acl_range_single) yyerror("address range used for notify"); append_acl(&cfg_parser->pattern->notify, acl); } #line 2922 "configparser.c" break; case 170: /* $@8: %empty */ #line 1058 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); append_acl(&cfg_parser->pattern->provide_xfr, acl); } #line 2931 "configparser.c" break; case 171: /* pattern_or_zone_option: VAR_PROVIDE_XFR STRING STRING $@8 provide_xfr_tlsauth_option */ #line 1063 "configparser.y" { } #line 2937 "configparser.c" break; case 172: /* pattern_or_zone_option: VAR_ALLOW_QUERY STRING STRING */ #line 1065 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); append_acl(&cfg_parser->pattern->allow_query, acl); } #line 2946 "configparser.c" break; case 173: /* pattern_or_zone_option: VAR_OUTGOING_INTERFACE STRING */ #line 1070 "configparser.y" { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[0].str), "NOKEY"); append_acl(&cfg_parser->pattern->outgoing_interface, acl); } #line 2955 "configparser.c" break; case 174: /* pattern_or_zone_option: VAR_ALLOW_AXFR_FALLBACK boolean */ #line 1075 "configparser.y" { cfg_parser->pattern->allow_axfr_fallback = (yyvsp[0].bln); cfg_parser->pattern->allow_axfr_fallback_is_default = 0; } #line 2964 "configparser.c" break; case 175: /* pattern_or_zone_option: VAR_NOTIFY_RETRY number */ #line 1080 "configparser.y" { cfg_parser->pattern->notify_retry = (yyvsp[0].llng); cfg_parser->pattern->notify_retry_is_default = 0; } #line 2973 "configparser.c" break; case 176: /* pattern_or_zone_option: VAR_MAX_REFRESH_TIME number */ #line 1085 "configparser.y" { cfg_parser->pattern->max_refresh_time = (yyvsp[0].llng); cfg_parser->pattern->max_refresh_time_is_default = 0; } #line 2982 "configparser.c" break; case 177: /* pattern_or_zone_option: VAR_MIN_REFRESH_TIME number */ #line 1090 "configparser.y" { cfg_parser->pattern->min_refresh_time = (yyvsp[0].llng); cfg_parser->pattern->min_refresh_time_is_default = 0; } #line 2991 "configparser.c" break; case 178: /* pattern_or_zone_option: VAR_MAX_RETRY_TIME number */ #line 1095 "configparser.y" { cfg_parser->pattern->max_retry_time = (yyvsp[0].llng); cfg_parser->pattern->max_retry_time_is_default = 0; } #line 3000 "configparser.c" break; case 179: /* pattern_or_zone_option: VAR_MIN_RETRY_TIME number */ #line 1100 "configparser.y" { cfg_parser->pattern->min_retry_time = (yyvsp[0].llng); cfg_parser->pattern->min_retry_time_is_default = 0; } #line 3009 "configparser.c" break; case 180: /* pattern_or_zone_option: VAR_MIN_EXPIRE_TIME STRING */ #line 1105 "configparser.y" { long long num; uint8_t expr; if (!parse_expire_expr((yyvsp[0].str), &num, &expr)) { yyerror("expected an expire time in seconds or \"refresh+retry+1\""); YYABORT; /* trigger a parser error */ } cfg_parser->pattern->min_expire_time = num; cfg_parser->pattern->min_expire_time_expr = expr; } #line 3025 "configparser.c" break; case 181: /* pattern_or_zone_option: VAR_STORE_IXFR boolean */ #line 1117 "configparser.y" { cfg_parser->pattern->store_ixfr = (yyvsp[0].bln); cfg_parser->pattern->store_ixfr_is_default = 0; } #line 3034 "configparser.c" break; case 182: /* pattern_or_zone_option: VAR_IXFR_SIZE number */ #line 1122 "configparser.y" { cfg_parser->pattern->ixfr_size = (yyvsp[0].llng); cfg_parser->pattern->ixfr_size_is_default = 0; } #line 3043 "configparser.c" break; case 183: /* pattern_or_zone_option: VAR_IXFR_NUMBER number */ #line 1127 "configparser.y" { cfg_parser->pattern->ixfr_number = (yyvsp[0].llng); cfg_parser->pattern->ixfr_number_is_default = 0; } #line 3052 "configparser.c" break; case 184: /* pattern_or_zone_option: VAR_CREATE_IXFR boolean */ #line 1132 "configparser.y" { cfg_parser->pattern->create_ixfr = (yyvsp[0].bln); cfg_parser->pattern->create_ixfr_is_default = 0; } #line 3061 "configparser.c" break; case 185: /* pattern_or_zone_option: VAR_VERIFY_ZONE boolean */ #line 1137 "configparser.y" { cfg_parser->pattern->verify_zone = (yyvsp[0].bln); } #line 3067 "configparser.c" break; case 186: /* pattern_or_zone_option: VAR_VERIFIER command */ #line 1139 "configparser.y" { cfg_parser->pattern->verifier = (yyvsp[0].strv); } #line 3073 "configparser.c" break; case 187: /* pattern_or_zone_option: VAR_VERIFIER_FEED_ZONE boolean */ #line 1141 "configparser.y" { cfg_parser->pattern->verifier_feed_zone = (yyvsp[0].bln); } #line 3079 "configparser.c" break; case 188: /* pattern_or_zone_option: VAR_VERIFIER_TIMEOUT number */ #line 1143 "configparser.y" { cfg_parser->pattern->verifier_timeout = (yyvsp[0].llng); } #line 3085 "configparser.c" break; case 189: /* pattern_or_zone_option: VAR_CATALOG catalog_role */ #line 1145 "configparser.y" { if((yyvsp[0].role) == CATALOG_ROLE_PRODUCER && cfg_parser->pattern->request_xfr) yyerror("catalog producer zones cannot be secondary zones"); cfg_parser->pattern->catalog_role = (yyvsp[0].role); cfg_parser->pattern->catalog_role_is_default = 0; } #line 3096 "configparser.c" break; case 190: /* pattern_or_zone_option: VAR_CATALOG_MEMBER_PATTERN STRING */ #line 1152 "configparser.y" { cfg_parser->pattern->catalog_member_pattern = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 3104 "configparser.c" break; case 191: /* pattern_or_zone_option: VAR_CATALOG_PRODUCER_ZONE STRING */ #line 1156 "configparser.y" { dname_type *dname; if(cfg_parser->zone) { yyerror("catalog-producer-zone option is for patterns only and cannot " "be used in a zone clause"); } else if(!(dname = (dname_type *)dname_parse(cfg_parser->opt->region, (yyvsp[0].str)))) { yyerror("bad catalog producer name %s", (yyvsp[0].str)); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); cfg_parser->pattern->catalog_producer_zone = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } } #line 3122 "configparser.c" break; case 195: /* verify_option: VAR_ENABLE boolean */ #line 1178 "configparser.y" { cfg_parser->opt->verify_enable = (yyvsp[0].bln); } #line 3128 "configparser.c" break; case 196: /* verify_option: VAR_IP_ADDRESS ip_address */ #line 1180 "configparser.y" { struct ip_address_option *ip = cfg_parser->opt->verify_ip_addresses; if(!ip) { cfg_parser->opt->verify_ip_addresses = (yyvsp[0].ip); } else { while(ip->next) { ip = ip->next; } ip->next = (yyvsp[0].ip); } } #line 3142 "configparser.c" break; case 197: /* verify_option: VAR_PORT number */ #line 1190 "configparser.y" { /* port number, stored as a string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", (yyvsp[0].llng)); cfg_parser->opt->verify_port = region_strdup(cfg_parser->opt->region, buf); } #line 3153 "configparser.c" break; case 198: /* verify_option: VAR_VERIFY_ZONES boolean */ #line 1197 "configparser.y" { cfg_parser->opt->verify_zones = (yyvsp[0].bln); } #line 3159 "configparser.c" break; case 199: /* verify_option: VAR_VERIFIER command */ #line 1199 "configparser.y" { cfg_parser->opt->verifier = (yyvsp[0].strv); } #line 3165 "configparser.c" break; case 200: /* verify_option: VAR_VERIFIER_COUNT number */ #line 1201 "configparser.y" { cfg_parser->opt->verifier_count = (int)(yyvsp[0].llng); } #line 3171 "configparser.c" break; case 201: /* verify_option: VAR_VERIFIER_TIMEOUT number */ #line 1203 "configparser.y" { cfg_parser->opt->verifier_timeout = (int)(yyvsp[0].llng); } #line 3177 "configparser.c" break; case 202: /* verify_option: VAR_VERIFIER_FEED_ZONE boolean */ #line 1205 "configparser.y" { cfg_parser->opt->verifier_feed_zone = (yyvsp[0].bln); } #line 3183 "configparser.c" break; case 203: /* command: STRING arguments */ #line 1209 "configparser.y" { char **argv; size_t argc = 1; for(struct component *i = (yyvsp[0].comp); i; i = i->next) { argc++; } argv = region_alloc_zero( cfg_parser->opt->region, (argc + 1) * sizeof(char *)); argc = 0; argv[argc++] = (yyvsp[-1].str); for(struct component *j, *i = (yyvsp[0].comp); i; i = j) { j = i->next; argv[argc++] = i->str; region_recycle(cfg_parser->opt->region, i, sizeof(*i)); } (yyval.strv) = argv; } #line 3205 "configparser.c" break; case 204: /* arguments: %empty */ #line 1228 "configparser.y" { (yyval.comp) = NULL; } #line 3211 "configparser.c" break; case 205: /* arguments: arguments STRING */ #line 1230 "configparser.y" { struct component *comp = region_alloc_zero( cfg_parser->opt->region, sizeof(*comp)); comp->str = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if((yyvsp[-1].comp)) { struct component *tail = (yyvsp[-1].comp); while(tail->next) { tail = tail->next; } tail->next = comp; (yyval.comp) = (yyvsp[-1].comp); } else { (yyval.comp) = comp; } } #line 3231 "configparser.c" break; case 206: /* ip_address: STRING */ #line 1248 "configparser.y" { struct ip_address_option *ip = region_alloc_zero( cfg_parser->opt->region, sizeof(*ip)); ip->address = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); ip->fib = -1; (yyval.ip) = ip; } #line 3243 "configparser.c" break; case 207: /* number: STRING */ #line 1258 "configparser.y" { if(!parse_number((yyvsp[0].str), &(yyval.llng))) { yyerror("expected a number"); YYABORT; /* trigger a parser error */ } } #line 3254 "configparser.c" break; case 208: /* boolean: STRING */ #line 1267 "configparser.y" { if(!parse_boolean((yyvsp[0].str), &(yyval.bln))) { yyerror("expected yes or no"); YYABORT; /* trigger a parser error */ } } #line 3265 "configparser.c" break; case 210: /* request_xfr_tlsauth_option: STRING */ #line 1276 "configparser.y" { char *tls_auth_name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} #line 3272 "configparser.c" break; case 212: /* provide_xfr_tlsauth_option: STRING */ #line 1281 "configparser.y" { char *tls_auth_name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); add_to_last_acl(&cfg_parser->pattern->provide_xfr, tls_auth_name);} #line 3279 "configparser.c" break; case 213: /* catalog_role: STRING */ #line 1286 "configparser.y" { if(!parse_catalog_role((yyvsp[0].str), &(yyval.role))) { yyerror("expected consumer or producer"); YYABORT; /* trigger a parser error */ } } #line 3290 "configparser.c" break; #line 3294 "configparser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 1293 "configparser.y" static void append_acl(struct acl_options **list, struct acl_options *acl) { assert(list != NULL); if(*list == NULL) { *list = acl; } else { struct acl_options *tail = *list; while(tail->next != NULL) tail = tail->next; tail->next = acl; } } static void add_to_last_acl(struct acl_options **list, char *tls_auth_name) { struct acl_options *tail = *list; assert(list != NULL); assert(*list != NULL); while(tail->next != NULL) tail = tail->next; tail->tls_auth_name = tls_auth_name; } static int parse_boolean(const char *str, int *bln) { if(strcmp(str, "yes") == 0) { *bln = 1; } else if(strcmp(str, "no") == 0) { *bln = 0; } else { return 0; } return 1; } static int parse_expire_expr(const char *str, long long *num, uint8_t *expr) { if(parse_number(str, num)) { *expr = EXPIRE_TIME_HAS_VALUE; return 1; } if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) { *num = 0; *expr = REFRESHPLUSRETRYPLUS1; return 1; } return 0; } static int parse_number(const char *str, long long *num) { /* ensure string consists entirely of digits */ size_t pos = 0; while(str[pos] >= '0' && str[pos] <= '9') { pos++; } if(pos != 0 && str[pos] == '\0') { *num = strtoll(str, NULL, 10); return 1; } return 0; } static int parse_range(const char *str, long long *low, long long *high) { const char *ptr = str; long long num[2]; /* require range to begin with a number */ if(*ptr < '0' || *ptr > '9') { return 0; } num[0] = strtoll(ptr, (char **)&ptr, 10); /* require number to be followed by nothing at all or a dash */ if(*ptr == '\0') { *low = num[0]; *high = num[0]; return 1; } else if(*ptr != '-') { return 0; } ++ptr; /* require dash to be followed by a number */ if(*ptr < '0' || *ptr > '9') { return 0; } num[1] = strtoll(ptr, (char **)&ptr, 10); /* require number to be followed by nothing at all */ if(*ptr == '\0') { if(num[0] < num[1]) { *low = num[0]; *high = num[1]; } else { *low = num[1]; *high = num[0]; } return 1; } return 0; } static int parse_catalog_role(const char *str, int *role) { if(strcasecmp(str, "consumer") == 0) { *role = CATALOG_ROLE_CONSUMER; } else if(strcmp(str, "producer") == 0) { *role = CATALOG_ROLE_PRODUCER; } else { return 0; } return 1; } nsd-4.12.0/configparser.h0000644000175000017500000004041215002373060014626 0ustar mozziemozzie/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_C_CONFIGPARSER_H_INCLUDED # define YY_C_CONFIGPARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int c_debug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ STRING = 258, /* STRING */ VAR_SERVER = 259, /* VAR_SERVER */ VAR_SERVER_COUNT = 260, /* VAR_SERVER_COUNT */ VAR_IP_ADDRESS = 261, /* VAR_IP_ADDRESS */ VAR_IP_TRANSPARENT = 262, /* VAR_IP_TRANSPARENT */ VAR_IP_FREEBIND = 263, /* VAR_IP_FREEBIND */ VAR_REUSEPORT = 264, /* VAR_REUSEPORT */ VAR_SEND_BUFFER_SIZE = 265, /* VAR_SEND_BUFFER_SIZE */ VAR_RECEIVE_BUFFER_SIZE = 266, /* VAR_RECEIVE_BUFFER_SIZE */ VAR_DEBUG_MODE = 267, /* VAR_DEBUG_MODE */ VAR_IP4_ONLY = 268, /* VAR_IP4_ONLY */ VAR_IP6_ONLY = 269, /* VAR_IP6_ONLY */ VAR_DO_IP4 = 270, /* VAR_DO_IP4 */ VAR_DO_IP6 = 271, /* VAR_DO_IP6 */ VAR_PORT = 272, /* VAR_PORT */ VAR_USE_SYSTEMD = 273, /* VAR_USE_SYSTEMD */ VAR_VERBOSITY = 274, /* VAR_VERBOSITY */ VAR_USERNAME = 275, /* VAR_USERNAME */ VAR_CHROOT = 276, /* VAR_CHROOT */ VAR_ZONESDIR = 277, /* VAR_ZONESDIR */ VAR_ZONELISTFILE = 278, /* VAR_ZONELISTFILE */ VAR_DATABASE = 279, /* VAR_DATABASE */ VAR_LOGFILE = 280, /* VAR_LOGFILE */ VAR_LOG_ONLY_SYSLOG = 281, /* VAR_LOG_ONLY_SYSLOG */ VAR_PIDFILE = 282, /* VAR_PIDFILE */ VAR_DIFFFILE = 283, /* VAR_DIFFFILE */ VAR_XFRDFILE = 284, /* VAR_XFRDFILE */ VAR_XFRDIR = 285, /* VAR_XFRDIR */ VAR_HIDE_VERSION = 286, /* VAR_HIDE_VERSION */ VAR_HIDE_IDENTITY = 287, /* VAR_HIDE_IDENTITY */ VAR_VERSION = 288, /* VAR_VERSION */ VAR_IDENTITY = 289, /* VAR_IDENTITY */ VAR_NSID = 290, /* VAR_NSID */ VAR_TCP_COUNT = 291, /* VAR_TCP_COUNT */ VAR_TCP_REJECT_OVERFLOW = 292, /* VAR_TCP_REJECT_OVERFLOW */ VAR_TCP_QUERY_COUNT = 293, /* VAR_TCP_QUERY_COUNT */ VAR_TCP_TIMEOUT = 294, /* VAR_TCP_TIMEOUT */ VAR_TCP_MSS = 295, /* VAR_TCP_MSS */ VAR_OUTGOING_TCP_MSS = 296, /* VAR_OUTGOING_TCP_MSS */ VAR_IPV4_EDNS_SIZE = 297, /* VAR_IPV4_EDNS_SIZE */ VAR_IPV6_EDNS_SIZE = 298, /* VAR_IPV6_EDNS_SIZE */ VAR_STATISTICS = 299, /* VAR_STATISTICS */ VAR_XFRD_RELOAD_TIMEOUT = 300, /* VAR_XFRD_RELOAD_TIMEOUT */ VAR_LOG_TIME_ASCII = 301, /* VAR_LOG_TIME_ASCII */ VAR_LOG_TIME_ISO = 302, /* VAR_LOG_TIME_ISO */ VAR_ROUND_ROBIN = 303, /* VAR_ROUND_ROBIN */ VAR_MINIMAL_RESPONSES = 304, /* VAR_MINIMAL_RESPONSES */ VAR_CONFINE_TO_ZONE = 305, /* VAR_CONFINE_TO_ZONE */ VAR_REFUSE_ANY = 306, /* VAR_REFUSE_ANY */ VAR_RELOAD_CONFIG = 307, /* VAR_RELOAD_CONFIG */ VAR_ZONEFILES_CHECK = 308, /* VAR_ZONEFILES_CHECK */ VAR_ZONEFILES_WRITE = 309, /* VAR_ZONEFILES_WRITE */ VAR_RRL_SIZE = 310, /* VAR_RRL_SIZE */ VAR_RRL_RATELIMIT = 311, /* VAR_RRL_RATELIMIT */ VAR_RRL_SLIP = 312, /* VAR_RRL_SLIP */ VAR_RRL_IPV4_PREFIX_LENGTH = 313, /* VAR_RRL_IPV4_PREFIX_LENGTH */ VAR_RRL_IPV6_PREFIX_LENGTH = 314, /* VAR_RRL_IPV6_PREFIX_LENGTH */ VAR_RRL_WHITELIST_RATELIMIT = 315, /* VAR_RRL_WHITELIST_RATELIMIT */ VAR_TLS_SERVICE_KEY = 316, /* VAR_TLS_SERVICE_KEY */ VAR_TLS_SERVICE_PEM = 317, /* VAR_TLS_SERVICE_PEM */ VAR_TLS_SERVICE_OCSP = 318, /* VAR_TLS_SERVICE_OCSP */ VAR_TLS_PORT = 319, /* VAR_TLS_PORT */ VAR_TLS_AUTH_PORT = 320, /* VAR_TLS_AUTH_PORT */ VAR_TLS_AUTH_XFR_ONLY = 321, /* VAR_TLS_AUTH_XFR_ONLY */ VAR_TLS_CERT_BUNDLE = 322, /* VAR_TLS_CERT_BUNDLE */ VAR_PROXY_PROTOCOL_PORT = 323, /* VAR_PROXY_PROTOCOL_PORT */ VAR_CPU_AFFINITY = 324, /* VAR_CPU_AFFINITY */ VAR_XFRD_CPU_AFFINITY = 325, /* VAR_XFRD_CPU_AFFINITY */ VAR_SERVER_CPU_AFFINITY = 326, /* VAR_SERVER_CPU_AFFINITY */ VAR_DROP_UPDATES = 327, /* VAR_DROP_UPDATES */ VAR_XFRD_TCP_MAX = 328, /* VAR_XFRD_TCP_MAX */ VAR_XFRD_TCP_PIPELINE = 329, /* VAR_XFRD_TCP_PIPELINE */ VAR_METRICS_ENABLE = 330, /* VAR_METRICS_ENABLE */ VAR_METRICS_INTERFACE = 331, /* VAR_METRICS_INTERFACE */ VAR_METRICS_PORT = 332, /* VAR_METRICS_PORT */ VAR_METRICS_PATH = 333, /* VAR_METRICS_PATH */ VAR_DNSTAP = 334, /* VAR_DNSTAP */ VAR_DNSTAP_ENABLE = 335, /* VAR_DNSTAP_ENABLE */ VAR_DNSTAP_SOCKET_PATH = 336, /* VAR_DNSTAP_SOCKET_PATH */ VAR_DNSTAP_IP = 337, /* VAR_DNSTAP_IP */ VAR_DNSTAP_TLS = 338, /* VAR_DNSTAP_TLS */ VAR_DNSTAP_TLS_SERVER_NAME = 339, /* VAR_DNSTAP_TLS_SERVER_NAME */ VAR_DNSTAP_TLS_CERT_BUNDLE = 340, /* VAR_DNSTAP_TLS_CERT_BUNDLE */ VAR_DNSTAP_TLS_CLIENT_KEY_FILE = 341, /* VAR_DNSTAP_TLS_CLIENT_KEY_FILE */ VAR_DNSTAP_TLS_CLIENT_CERT_FILE = 342, /* VAR_DNSTAP_TLS_CLIENT_CERT_FILE */ VAR_DNSTAP_SEND_IDENTITY = 343, /* VAR_DNSTAP_SEND_IDENTITY */ VAR_DNSTAP_SEND_VERSION = 344, /* VAR_DNSTAP_SEND_VERSION */ VAR_DNSTAP_IDENTITY = 345, /* VAR_DNSTAP_IDENTITY */ VAR_DNSTAP_VERSION = 346, /* VAR_DNSTAP_VERSION */ VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES = 347, /* VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES */ VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES = 348, /* VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES */ VAR_REMOTE_CONTROL = 349, /* VAR_REMOTE_CONTROL */ VAR_CONTROL_ENABLE = 350, /* VAR_CONTROL_ENABLE */ VAR_CONTROL_INTERFACE = 351, /* VAR_CONTROL_INTERFACE */ VAR_CONTROL_PORT = 352, /* VAR_CONTROL_PORT */ VAR_SERVER_KEY_FILE = 353, /* VAR_SERVER_KEY_FILE */ VAR_SERVER_CERT_FILE = 354, /* VAR_SERVER_CERT_FILE */ VAR_CONTROL_KEY_FILE = 355, /* VAR_CONTROL_KEY_FILE */ VAR_CONTROL_CERT_FILE = 356, /* VAR_CONTROL_CERT_FILE */ VAR_KEY = 357, /* VAR_KEY */ VAR_ALGORITHM = 358, /* VAR_ALGORITHM */ VAR_SECRET = 359, /* VAR_SECRET */ VAR_TLS_AUTH = 360, /* VAR_TLS_AUTH */ VAR_TLS_AUTH_DOMAIN_NAME = 361, /* VAR_TLS_AUTH_DOMAIN_NAME */ VAR_TLS_AUTH_CLIENT_CERT = 362, /* VAR_TLS_AUTH_CLIENT_CERT */ VAR_TLS_AUTH_CLIENT_KEY = 363, /* VAR_TLS_AUTH_CLIENT_KEY */ VAR_TLS_AUTH_CLIENT_KEY_PW = 364, /* VAR_TLS_AUTH_CLIENT_KEY_PW */ VAR_PATTERN = 365, /* VAR_PATTERN */ VAR_NAME = 366, /* VAR_NAME */ VAR_ZONEFILE = 367, /* VAR_ZONEFILE */ VAR_NOTIFY = 368, /* VAR_NOTIFY */ VAR_PROVIDE_XFR = 369, /* VAR_PROVIDE_XFR */ VAR_ALLOW_QUERY = 370, /* VAR_ALLOW_QUERY */ VAR_AXFR = 371, /* VAR_AXFR */ VAR_UDP = 372, /* VAR_UDP */ VAR_NOTIFY_RETRY = 373, /* VAR_NOTIFY_RETRY */ VAR_ALLOW_NOTIFY = 374, /* VAR_ALLOW_NOTIFY */ VAR_REQUEST_XFR = 375, /* VAR_REQUEST_XFR */ VAR_ALLOW_AXFR_FALLBACK = 376, /* VAR_ALLOW_AXFR_FALLBACK */ VAR_OUTGOING_INTERFACE = 377, /* VAR_OUTGOING_INTERFACE */ VAR_ANSWER_COOKIE = 378, /* VAR_ANSWER_COOKIE */ VAR_COOKIE_SECRET = 379, /* VAR_COOKIE_SECRET */ VAR_COOKIE_SECRET_FILE = 380, /* VAR_COOKIE_SECRET_FILE */ VAR_COOKIE_STAGING_SECRET = 381, /* VAR_COOKIE_STAGING_SECRET */ VAR_MAX_REFRESH_TIME = 382, /* VAR_MAX_REFRESH_TIME */ VAR_MIN_REFRESH_TIME = 383, /* VAR_MIN_REFRESH_TIME */ VAR_MAX_RETRY_TIME = 384, /* VAR_MAX_RETRY_TIME */ VAR_MIN_RETRY_TIME = 385, /* VAR_MIN_RETRY_TIME */ VAR_MIN_EXPIRE_TIME = 386, /* VAR_MIN_EXPIRE_TIME */ VAR_MULTI_PRIMARY_CHECK = 387, /* VAR_MULTI_PRIMARY_CHECK */ VAR_SIZE_LIMIT_XFR = 388, /* VAR_SIZE_LIMIT_XFR */ VAR_ZONESTATS = 389, /* VAR_ZONESTATS */ VAR_INCLUDE_PATTERN = 390, /* VAR_INCLUDE_PATTERN */ VAR_STORE_IXFR = 391, /* VAR_STORE_IXFR */ VAR_IXFR_SIZE = 392, /* VAR_IXFR_SIZE */ VAR_IXFR_NUMBER = 393, /* VAR_IXFR_NUMBER */ VAR_CREATE_IXFR = 394, /* VAR_CREATE_IXFR */ VAR_CATALOG = 395, /* VAR_CATALOG */ VAR_CATALOG_MEMBER_PATTERN = 396, /* VAR_CATALOG_MEMBER_PATTERN */ VAR_CATALOG_PRODUCER_ZONE = 397, /* VAR_CATALOG_PRODUCER_ZONE */ VAR_ZONE = 398, /* VAR_ZONE */ VAR_RRL_WHITELIST = 399, /* VAR_RRL_WHITELIST */ VAR_SERVERS = 400, /* VAR_SERVERS */ VAR_BINDTODEVICE = 401, /* VAR_BINDTODEVICE */ VAR_SETFIB = 402, /* VAR_SETFIB */ VAR_VERIFY = 403, /* VAR_VERIFY */ VAR_ENABLE = 404, /* VAR_ENABLE */ VAR_VERIFY_ZONE = 405, /* VAR_VERIFY_ZONE */ VAR_VERIFY_ZONES = 406, /* VAR_VERIFY_ZONES */ VAR_VERIFIER = 407, /* VAR_VERIFIER */ VAR_VERIFIER_COUNT = 408, /* VAR_VERIFIER_COUNT */ VAR_VERIFIER_FEED_ZONE = 409, /* VAR_VERIFIER_FEED_ZONE */ VAR_VERIFIER_TIMEOUT = 410 /* VAR_VERIFIER_TIMEOUT */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define STRING 258 #define VAR_SERVER 259 #define VAR_SERVER_COUNT 260 #define VAR_IP_ADDRESS 261 #define VAR_IP_TRANSPARENT 262 #define VAR_IP_FREEBIND 263 #define VAR_REUSEPORT 264 #define VAR_SEND_BUFFER_SIZE 265 #define VAR_RECEIVE_BUFFER_SIZE 266 #define VAR_DEBUG_MODE 267 #define VAR_IP4_ONLY 268 #define VAR_IP6_ONLY 269 #define VAR_DO_IP4 270 #define VAR_DO_IP6 271 #define VAR_PORT 272 #define VAR_USE_SYSTEMD 273 #define VAR_VERBOSITY 274 #define VAR_USERNAME 275 #define VAR_CHROOT 276 #define VAR_ZONESDIR 277 #define VAR_ZONELISTFILE 278 #define VAR_DATABASE 279 #define VAR_LOGFILE 280 #define VAR_LOG_ONLY_SYSLOG 281 #define VAR_PIDFILE 282 #define VAR_DIFFFILE 283 #define VAR_XFRDFILE 284 #define VAR_XFRDIR 285 #define VAR_HIDE_VERSION 286 #define VAR_HIDE_IDENTITY 287 #define VAR_VERSION 288 #define VAR_IDENTITY 289 #define VAR_NSID 290 #define VAR_TCP_COUNT 291 #define VAR_TCP_REJECT_OVERFLOW 292 #define VAR_TCP_QUERY_COUNT 293 #define VAR_TCP_TIMEOUT 294 #define VAR_TCP_MSS 295 #define VAR_OUTGOING_TCP_MSS 296 #define VAR_IPV4_EDNS_SIZE 297 #define VAR_IPV6_EDNS_SIZE 298 #define VAR_STATISTICS 299 #define VAR_XFRD_RELOAD_TIMEOUT 300 #define VAR_LOG_TIME_ASCII 301 #define VAR_LOG_TIME_ISO 302 #define VAR_ROUND_ROBIN 303 #define VAR_MINIMAL_RESPONSES 304 #define VAR_CONFINE_TO_ZONE 305 #define VAR_REFUSE_ANY 306 #define VAR_RELOAD_CONFIG 307 #define VAR_ZONEFILES_CHECK 308 #define VAR_ZONEFILES_WRITE 309 #define VAR_RRL_SIZE 310 #define VAR_RRL_RATELIMIT 311 #define VAR_RRL_SLIP 312 #define VAR_RRL_IPV4_PREFIX_LENGTH 313 #define VAR_RRL_IPV6_PREFIX_LENGTH 314 #define VAR_RRL_WHITELIST_RATELIMIT 315 #define VAR_TLS_SERVICE_KEY 316 #define VAR_TLS_SERVICE_PEM 317 #define VAR_TLS_SERVICE_OCSP 318 #define VAR_TLS_PORT 319 #define VAR_TLS_AUTH_PORT 320 #define VAR_TLS_AUTH_XFR_ONLY 321 #define VAR_TLS_CERT_BUNDLE 322 #define VAR_PROXY_PROTOCOL_PORT 323 #define VAR_CPU_AFFINITY 324 #define VAR_XFRD_CPU_AFFINITY 325 #define VAR_SERVER_CPU_AFFINITY 326 #define VAR_DROP_UPDATES 327 #define VAR_XFRD_TCP_MAX 328 #define VAR_XFRD_TCP_PIPELINE 329 #define VAR_METRICS_ENABLE 330 #define VAR_METRICS_INTERFACE 331 #define VAR_METRICS_PORT 332 #define VAR_METRICS_PATH 333 #define VAR_DNSTAP 334 #define VAR_DNSTAP_ENABLE 335 #define VAR_DNSTAP_SOCKET_PATH 336 #define VAR_DNSTAP_IP 337 #define VAR_DNSTAP_TLS 338 #define VAR_DNSTAP_TLS_SERVER_NAME 339 #define VAR_DNSTAP_TLS_CERT_BUNDLE 340 #define VAR_DNSTAP_TLS_CLIENT_KEY_FILE 341 #define VAR_DNSTAP_TLS_CLIENT_CERT_FILE 342 #define VAR_DNSTAP_SEND_IDENTITY 343 #define VAR_DNSTAP_SEND_VERSION 344 #define VAR_DNSTAP_IDENTITY 345 #define VAR_DNSTAP_VERSION 346 #define VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES 347 #define VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES 348 #define VAR_REMOTE_CONTROL 349 #define VAR_CONTROL_ENABLE 350 #define VAR_CONTROL_INTERFACE 351 #define VAR_CONTROL_PORT 352 #define VAR_SERVER_KEY_FILE 353 #define VAR_SERVER_CERT_FILE 354 #define VAR_CONTROL_KEY_FILE 355 #define VAR_CONTROL_CERT_FILE 356 #define VAR_KEY 357 #define VAR_ALGORITHM 358 #define VAR_SECRET 359 #define VAR_TLS_AUTH 360 #define VAR_TLS_AUTH_DOMAIN_NAME 361 #define VAR_TLS_AUTH_CLIENT_CERT 362 #define VAR_TLS_AUTH_CLIENT_KEY 363 #define VAR_TLS_AUTH_CLIENT_KEY_PW 364 #define VAR_PATTERN 365 #define VAR_NAME 366 #define VAR_ZONEFILE 367 #define VAR_NOTIFY 368 #define VAR_PROVIDE_XFR 369 #define VAR_ALLOW_QUERY 370 #define VAR_AXFR 371 #define VAR_UDP 372 #define VAR_NOTIFY_RETRY 373 #define VAR_ALLOW_NOTIFY 374 #define VAR_REQUEST_XFR 375 #define VAR_ALLOW_AXFR_FALLBACK 376 #define VAR_OUTGOING_INTERFACE 377 #define VAR_ANSWER_COOKIE 378 #define VAR_COOKIE_SECRET 379 #define VAR_COOKIE_SECRET_FILE 380 #define VAR_COOKIE_STAGING_SECRET 381 #define VAR_MAX_REFRESH_TIME 382 #define VAR_MIN_REFRESH_TIME 383 #define VAR_MAX_RETRY_TIME 384 #define VAR_MIN_RETRY_TIME 385 #define VAR_MIN_EXPIRE_TIME 386 #define VAR_MULTI_PRIMARY_CHECK 387 #define VAR_SIZE_LIMIT_XFR 388 #define VAR_ZONESTATS 389 #define VAR_INCLUDE_PATTERN 390 #define VAR_STORE_IXFR 391 #define VAR_IXFR_SIZE 392 #define VAR_IXFR_NUMBER 393 #define VAR_CREATE_IXFR 394 #define VAR_CATALOG 395 #define VAR_CATALOG_MEMBER_PATTERN 396 #define VAR_CATALOG_PRODUCER_ZONE 397 #define VAR_ZONE 398 #define VAR_RRL_WHITELIST 399 #define VAR_SERVERS 400 #define VAR_BINDTODEVICE 401 #define VAR_SETFIB 402 #define VAR_VERIFY 403 #define VAR_ENABLE 404 #define VAR_VERIFY_ZONE 405 #define VAR_VERIFY_ZONES 406 #define VAR_VERIFIER 407 #define VAR_VERIFIER_COUNT 408 #define VAR_VERIFIER_FEED_ZONE 409 #define VAR_VERIFIER_TIMEOUT 410 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 48 "configparser.y" char *str; long long llng; int bln; struct ip_address_option *ip; struct range_option *range; struct cpu_option *cpu; char **strv; struct component *comp; int role; #line 389 "configparser.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE c_lval; int c_parse (void); #endif /* !YY_C_CONFIGPARSER_H_INCLUDED */ nsd-4.12.0/configlexer.c0000644000175000017500000046755115002373060014465 0ustar mozziemozzie#include "config.h" #line 2 "" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer c__create_buffer #define yy_delete_buffer c__delete_buffer #define yy_scan_buffer c__scan_buffer #define yy_scan_string c__scan_string #define yy_scan_bytes c__scan_bytes #define yy_init_buffer c__init_buffer #define yy_flush_buffer c__flush_buffer #define yy_load_buffer_state c__load_buffer_state #define yy_switch_to_buffer c__switch_to_buffer #define yypush_buffer_state c_push_buffer_state #define yypop_buffer_state c_pop_buffer_state #define yyensure_buffer_stack c_ensure_buffer_stack #define yy_flex_debug c__flex_debug #define yyin c_in #define yyleng c_leng #define yylex c_lex #define yylineno c_lineno #define yyout c_out #define yyrestart c_restart #define yytext c_text #define yywrap c_wrap #define yyalloc c_alloc #define yyrealloc c_realloc #define yyfree c_free #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define c__create_buffer_ALREADY_DEFINED #else #define yy_create_buffer c__create_buffer #endif #ifdef yy_delete_buffer #define c__delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer c__delete_buffer #endif #ifdef yy_scan_buffer #define c__scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer c__scan_buffer #endif #ifdef yy_scan_string #define c__scan_string_ALREADY_DEFINED #else #define yy_scan_string c__scan_string #endif #ifdef yy_scan_bytes #define c__scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes c__scan_bytes #endif #ifdef yy_init_buffer #define c__init_buffer_ALREADY_DEFINED #else #define yy_init_buffer c__init_buffer #endif #ifdef yy_flush_buffer #define c__flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer c__flush_buffer #endif #ifdef yy_load_buffer_state #define c__load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state c__load_buffer_state #endif #ifdef yy_switch_to_buffer #define c__switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer c__switch_to_buffer #endif #ifdef yypush_buffer_state #define c_push_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state c_push_buffer_state #endif #ifdef yypop_buffer_state #define c_pop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state c_pop_buffer_state #endif #ifdef yyensure_buffer_stack #define c_ensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack c_ensure_buffer_stack #endif #ifdef yylex #define c_lex_ALREADY_DEFINED #else #define yylex c_lex #endif #ifdef yyrestart #define c_restart_ALREADY_DEFINED #else #define yyrestart c_restart #endif #ifdef yylex_init #define c_lex_init_ALREADY_DEFINED #else #define yylex_init c_lex_init #endif #ifdef yylex_init_extra #define c_lex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra c_lex_init_extra #endif #ifdef yylex_destroy #define c_lex_destroy_ALREADY_DEFINED #else #define yylex_destroy c_lex_destroy #endif #ifdef yyget_debug #define c_get_debug_ALREADY_DEFINED #else #define yyget_debug c_get_debug #endif #ifdef yyset_debug #define c_set_debug_ALREADY_DEFINED #else #define yyset_debug c_set_debug #endif #ifdef yyget_extra #define c_get_extra_ALREADY_DEFINED #else #define yyget_extra c_get_extra #endif #ifdef yyset_extra #define c_set_extra_ALREADY_DEFINED #else #define yyset_extra c_set_extra #endif #ifdef yyget_in #define c_get_in_ALREADY_DEFINED #else #define yyget_in c_get_in #endif #ifdef yyset_in #define c_set_in_ALREADY_DEFINED #else #define yyset_in c_set_in #endif #ifdef yyget_out #define c_get_out_ALREADY_DEFINED #else #define yyget_out c_get_out #endif #ifdef yyset_out #define c_set_out_ALREADY_DEFINED #else #define yyset_out c_set_out #endif #ifdef yyget_leng #define c_get_leng_ALREADY_DEFINED #else #define yyget_leng c_get_leng #endif #ifdef yyget_text #define c_get_text_ALREADY_DEFINED #else #define yyget_text c_get_text #endif #ifdef yyget_lineno #define c_get_lineno_ALREADY_DEFINED #else #define yyget_lineno c_get_lineno #endif #ifdef yyset_lineno #define c_set_lineno_ALREADY_DEFINED #else #define yyset_lineno c_set_lineno #endif #ifdef yywrap #define c_wrap_ALREADY_DEFINED #else #define yywrap c_wrap #endif #ifdef yyalloc #define c_alloc_ALREADY_DEFINED #else #define yyalloc c_alloc #endif #ifdef yyrealloc #define c_realloc_ALREADY_DEFINED #else #define yyrealloc c_realloc #endif #ifdef yyfree #define c_free_ALREADY_DEFINED #else #define yyfree c_free #endif #ifdef yytext #define c_text_ALREADY_DEFINED #else #define yytext c_text #endif #ifdef yyleng #define c_leng_ALREADY_DEFINED #else #define yyleng c_leng #endif #ifdef yyin #define c_in_ALREADY_DEFINED #else #define yyin c_in #endif #ifdef yyout #define c_out_ALREADY_DEFINED #else #define yyout c_out #endif #ifdef yy_flex_debug #define c__flex_debug_ALREADY_DEFINED #else #define yy_flex_debug c__flex_debug #endif #ifdef yylineno #define c_lineno_ALREADY_DEFINED #else #define yylineno c_lineno #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart ( FILE *input_file ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); void yy_delete_buffer ( YY_BUFFER_STATE b ); void yy_flush_buffer ( YY_BUFFER_STATE b ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); void yypop_buffer_state ( void ); static void yyensure_buffer_stack ( void ); static void yy_load_buffer_state ( void ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); void *yyalloc ( yy_size_t ); void *yyrealloc ( void *, yy_size_t ); void yyfree ( void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef flex_uint8_t YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state ( void ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); static int yy_get_next_buffer ( void ); static void yynoreturn yy_fatal_error ( const char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ (yytext_ptr) -= (yy_more_len); \ yyleng = (int) (yy_cp - (yytext_ptr)); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 171 #define YY_END_OF_BUFFER 172 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[1509] = { 0, 1, 1, 159, 159, 163, 163, 167, 167, 172, 170, 1, 151, 158, 2, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 159, 160, 171, 161, 171, 166, 163, 164, 165, 171, 167, 168, 169, 171, 170, 0, 1, 2, 2, 2, 2, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 159, 0, 166, 0, 163, 167, 0, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 83, 170, 170, 170, 170, 170, 170, 170, 170, 82, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 65, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 4, 170, 23, 170, 170, 170, 36, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 48, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 39, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 94, 18, 19, 170, 141, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 54, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 67, 170, 170, 3, 170, 154, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 140, 170, 170, 170, 170, 170, 45, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 148, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 162, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 24, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 68, 35, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 152, 154, 0, 170, 170, 170, 170, 31, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 22, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 20, 170, 43, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 21, 170, 170, 170, 170, 170, 16, 17, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 84, 86, 170, 170, 170, 170, 170, 170, 170, 152, 0, 170, 170, 170, 170, 170, 170, 170, 170, 60, 170, 129, 170, 170, 40, 170, 170, 144, 170, 170, 170, 170, 44, 49, 170, 170, 41, 170, 66, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 97, 170, 170, 170, 170, 170, 170, 170, 170, 170, 6, 170, 170, 170, 170, 170, 170, 121, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 37, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 27, 170, 170, 170, 170, 170, 170, 170, 170, 47, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 50, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 63, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 11, 170, 170, 170, 170, 170, 170, 98, 170, 170, 170, 170, 170, 5, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 114, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 38, 120, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 57, 170, 170, 170, 170, 170, 62, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 123, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 8, 170, 170, 170, 122, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 56, 170, 170, 170, 170, 53, 111, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 30, 170, 170, 170, 170, 12, 170, 170, 170, 142, 170, 170, 170, 170, 170, 170, 170, 170, 170, 51, 170, 170, 153, 170, 170, 170, 170, 170, 170, 170, 170, 73, 170, 170, 155, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 15, 170, 13, 170, 170, 170, 170, 170, 170, 110, 170, 170, 170, 170, 81, 80, 170, 170, 170, 170, 170, 170, 55, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 26, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 143, 170, 170, 138, 170, 170, 170, 42, 170, 134, 170, 153, 0, 170, 170, 64, 170, 170, 170, 170, 170, 170, 135, 170, 95, 170, 170, 170, 170, 170, 170, 170, 170, 170, 14, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 91, 170, 170, 170, 85, 170, 90, 170, 170, 170, 170, 170, 170, 170, 130, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 71, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 106, 170, 7, 33, 34, 170, 109, 170, 117, 78, 170, 170, 170, 118, 170, 170, 170, 170, 170, 170, 170, 70, 170, 170, 170, 170, 170, 170, 170, 52, 170, 170, 170, 170, 170, 170, 170, 145, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 113, 170, 170, 170, 170, 170, 105, 170, 170, 170, 170, 170, 170, 170, 69, 25, 170, 170, 119, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 74, 29, 170, 170, 132, 126, 170, 128, 170, 170, 170, 170, 170, 92, 93, 170, 61, 170, 170, 170, 170, 76, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 115, 170, 116, 170, 170, 170, 170, 32, 170, 170, 170, 170, 170, 9, 170, 75, 170, 170, 127, 170, 147, 170, 170, 170, 170, 170, 170, 77, 72, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 79, 112, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 131, 170, 156, 170, 139, 170, 170, 170, 136, 170, 170, 170, 170, 170, 96, 170, 170, 170, 170, 124, 170, 58, 170, 170, 170, 170, 170, 170, 170, 146, 170, 59, 170, 170, 170, 170, 170, 170, 104, 170, 170, 170, 170, 125, 133, 10, 170, 170, 170, 170, 28, 46, 170, 170, 170, 170, 170, 103, 170, 170, 170, 170, 170, 170, 170, 170, 170, 150, 137, 170, 170, 170, 170, 170, 170, 170, 170, 170, 157, 149, 170, 170, 100, 170, 170, 99, 87, 88, 170, 170, 170, 170, 170, 89, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 101, 170, 170, 102, 170, 170, 170, 170, 107, 170, 170, 170, 108, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 8, 9, 9, 9, 10, 9, 11, 9, 9, 9, 12, 1, 1, 13, 1, 1, 1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 1, 40, 1, 1, 1, 1, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[67] = { 0, 1, 2, 3, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const flex_int16_t yy_base[1521] = { 0, 0, 0, 64, 67, 71, 75, 78, 81, 4188, 4107, 85, 4267, 4267, 88, 72, 73, 123, 168, 62, 74, 102, 80, 77, 127, 166, 113, 188, 187, 216, 208, 133, 90, 143, 115, 155, 4106, 4267, 4267, 4267, 96, 4104, 4141, 4267, 4267, 199, 4068, 4267, 4267, 180, 4065, 248, 132, 0, 253, 0, 0, 219, 222, 160, 195, 237, 207, 232, 246, 242, 239, 262, 245, 259, 264, 252, 87, 266, 273, 272, 280, 293, 308, 284, 289, 288, 294, 299, 310, 315, 312, 309, 322, 323, 328, 334, 326, 332, 373, 339, 350, 377, 346, 381, 389, 365, 398, 383, 375, 401, 412, 4063, 207, 4048, 438, 4059, 3980, 226, 416, 418, 411, 427, 422, 432, 441, 429, 443, 445, 439, 340, 446, 454, 458, 470, 437, 471, 467, 484, 482, 474, 477, 485, 499, 374, 497, 498, 475, 157, 524, 514, 504, 527, 508, 518, 520, 533, 531, 532, 534, 542, 544, 543, 551, 558, 559, 555, 561, 563, 587, 565, 590, 569, 578, 592, 582, 588, 593, 604, 3969, 614, 621, 608, 611, 607, 599, 631, 619, 3964, 617, 615, 638, 633, 642, 643, 646, 644, 648, 654, 659, 670, 678, 669, 683, 672, 693, 671, 673, 674, 686, 689, 696, 700, 709, 695, 708, 710, 3956, 711, 716, 712, 719, 727, 720, 735, 305, 723, 741, 734, 743, 754, 765, 757, 742, 764, 755, 776, 758, 775, 781, 779, 800, 784, 771, 790, 788, 785, 805, 794, 848, 828, 806, 816, 822, 836, 826, 873, 871, 845, 793, 858, 880, 872, 874, 885, 888, 899, 903, 892, 853, 915, 895, 846, 912, 909, 930, 910, 924, 932, 934, 940, 947, 942, 928, 937, 935, 936, 961, 967, 964, 965, 973, 963, 980, 981, 962, 990, 996, 993, 3948, 976, 3872, 989, 1000, 992, 3863, 1010, 1002, 999, 1025, 1011, 1027, 1016, 1017, 1040, 1020, 1038, 1037, 1042, 1031, 1053, 1043, 1054, 1059, 1060, 1074, 1057, 1066, 1068, 1070, 1081, 1073, 1086, 1077, 1098, 1080, 1095, 1101, 1102, 1099, 1128, 1106, 1116, 3821, 1126, 1130, 1132, 1117, 1155, 1151, 1150, 1163, 1153, 1141, 1157, 1144, 1158, 1180, 1175, 1192, 1174, 1176, 1179, 1201, 1199, 1205, 1194, 1206, 1184, 1204, 1197, 1207, 1213, 1211, 1218, 1208, 1215, 1231, 1221, 1226, 1234, 1237, 1235, 1238, 1254, 1257, 1241, 1253, 1265, 1264, 1281, 1273, 1252, 1261, 1278, 1284, 1279, 1296, 1305, 1313, 1315, 1298, 1299, 1302, 1308, 1307, 1310, 1322, 1324, 1316, 1317, 1354, 1319, 1341, 1332, 1347, 1334, 1343, 1359, 1357, 1353, 1349, 1360, 1370, 1372, 1376, 1358, 1383, 1396, 1408, 1397, 1393, 1399, 1403, 1400, 1414, 1413, 1402, 1407, 1417, 1424, 1422, 1427, 1426, 1434, 1443, 1445, 1461, 3814, 1454, 1345, 1381, 1439, 1453, 1459, 1466, 1448, 1473, 1501, 3753, 3711, 3703, 1472, 3700, 1477, 1469, 1490, 1503, 1464, 1502, 1509, 1489, 1497, 1500, 1504, 1505, 1499, 1517, 1526, 1536, 1555, 1538, 1539, 1561, 1549, 1542, 1544, 1565, 1563, 1554, 1559, 3668, 1566, 1568, 1575, 1567, 1578, 1581, 1579, 1594, 1595, 1585, 1583, 1588, 1616, 1604, 1606, 1602, 1599, 3664, 1614, 1652, 3663, 1617, 3660, 1624, 1625, 1608, 1613, 1640, 1635, 1651, 1660, 1649, 1646, 1648, 1647, 1650, 1667, 1661, 1671, 1659, 3656, 1692, 1679, 1690, 1687, 1696, 3654, 1699, 1691, 1695, 1705, 1694, 1709, 1717, 1719, 1718, 1734, 1721, 1740, 3648, 1736, 1742, 1730, 1781, 1767, 1744, 1749, 1755, 1762, 1776, 1764, 1791, 1783, 1801, 1800, 1799, 1808, 1774, 1802, 1803, 1822, 3609, 1815, 1813, 1814, 1828, 1846, 1847, 1833, 1834, 1835, 1849, 1857, 1862, 3602, 1858, 1841, 1878, 1851, 1865, 1850, 1864, 1876, 1877, 1893, 1873, 3593, 3543, 1884, 1891, 1897, 1874, 1892, 1901, 1903, 1909, 1910, 1923, 1937, 1920, 1924, 1939, 1935, 1936, 1976, 1950, 1948, 3537, 3490, 1957, 1949, 1954, 1962, 1959, 3398, 1963, 1975, 1972, 1997, 1966, 1984, 1985, 1993, 2001, 1982, 2014, 1989, 3301, 2003, 1995, 2023, 2002, 2019, 2020, 2024, 2008, 2033, 2018, 2030, 2022, 2028, 2035, 2047, 2037, 2034, 2041, 2048, 2057, 2053, 2062, 2063, 2082, 2066, 2075, 2090, 2079, 2086, 3299, 2089, 3297, 2095, 2093, 2083, 2100, 2097, 2109, 2110, 2108, 2113, 2121, 2119, 3253, 2130, 2143, 2125, 2118, 2146, 3218, 3216, 2103, 2149, 2145, 2152, 2135, 2160, 2148, 2155, 2151, 2166, 2182, 2158, 2172, 2190, 2181, 2175, 2176, 2178, 2192, 2194, 2184, 2193, 2205, 2209, 2215, 2220, 2207, 2224, 2219, 2221, 2231, 3178, 3173, 2232, 2238, 2242, 2279, 2234, 2257, 2241, 3167, 2291, 2261, 2267, 2269, 2264, 2291, 2270, 2268, 2276, 3165, 2296, 3158, 2299, 2288, 3127, 2305, 2304, 3117, 2295, 2311, 2319, 2317, 3108, 3102, 2327, 2326, 3068, 2341, 3062, 2347, 2336, 2318, 2337, 2338, 2346, 2345, 2340, 2339, 2362, 2356, 2353, 2376, 2361, 2365, 2360, 2366, 2387, 2375, 2373, 2397, 2399, 2392, 3061, 2403, 2405, 2396, 2416, 2393, 2408, 2418, 2410, 2411, 2908, 2417, 2437, 2424, 2428, 2429, 2432, 2904, 2435, 2430, 2434, 2438, 2443, 2465, 2451, 2452, 2464, 2473, 2475, 2461, 2467, 2479, 2488, 2477, 2487, 2493, 2485, 2490, 2491, 2508, 2513, 2506, 2507, 2902, 2515, 2509, 2520, 2518, 2512, 2523, 2528, 2537, 2535, 2543, 2565, 2552, 2561, 2853, 2560, 2567, 2546, 2554, 2568, 2551, 2570, 2573, 2822, 2571, 2578, 2576, 2584, 2600, 2587, 2581, 2598, 2612, 2605, 2818, 2613, 2595, 2622, 2614, 2630, 2621, 2627, 2624, 2631, 2636, 2797, 2611, 2639, 2641, 2640, 2642, 2651, 2655, 2656, 2648, 2662, 2768, 2664, 2654, 2679, 2683, 2685, 2692, 2762, 2687, 2675, 2677, 2691, 2688, 2719, 2686, 2704, 2707, 2717, 2700, 2701, 2722, 2714, 2736, 2724, 2735, 2734, 2732, 2728, 2730, 2751, 2745, 2742, 2747, 2752, 2746, 2756, 2764, 2769, 2779, 2778, 2715, 2777, 2772, 2788, 2789, 2795, 2796, 2785, 2783, 2799, 2787, 2824, 2805, 2813, 2806, 2666, 2661, 2816, 2821, 2835, 2820, 2823, 2828, 2826, 2840, 2833, 2832, 2843, 2867, 2855, 2850, 2847, 2857, 2864, 2858, 2870, 2877, 2880, 2657, 2882, 2879, 2889, 2885, 2874, 2604, 2869, 2896, 2914, 2898, 2897, 2912, 2922, 2906, 2913, 2929, 2553, 2925, 2923, 2934, 2938, 2916, 2939, 2941, 2943, 2935, 2942, 2949, 2959, 2540, 2961, 2953, 2957, 2516, 2965, 2963, 2982, 2969, 2980, 2985, 2987, 2996, 2999, 2991, 2981, 2990, 2998, 3017, 2994, 3016, 3024, 3028, 2458, 3018, 3026, 3027, 3020, 2402, 2372, 3030, 3032, 3021, 3022, 3045, 3043, 3044, 3040, 3057, 3046, 3053, 3054, 2284, 3055, 3084, 3079, 3081, 2272, 3071, 3082, 3089, 2228, 3088, 3090, 3080, 3091, 3109, 3115, 3095, 3106, 3113, 2227, 3129, 3131, 2222, 3112, 3134, 3135, 3124, 3139, 3141, 3142, 3140, 2211, 3156, 3136, 2188, 3154, 3151, 3157, 3170, 3155, 3185, 3162, 3179, 3168, 3176, 2139, 3192, 2137, 3175, 3189, 3191, 3194, 3195, 3202, 2074, 3205, 3203, 3219, 3221, 2068, 2021, 3212, 3222, 3223, 3220, 3230, 3246, 2006, 3226, 3229, 3247, 3245, 3265, 3250, 3257, 3258, 3269, 3271, 3270, 3274, 3272, 1992, 3264, 3260, 3268, 3283, 3284, 3285, 3292, 3302, 3310, 3309, 3296, 3323, 3303, 1934, 3306, 3312, 1925, 3326, 3319, 3305, 1918, 3330, 1917, 3331, 1914, 3370, 3341, 3346, 1845, 3349, 3347, 3361, 3362, 3343, 3358, 1831, 3372, 1830, 3350, 3359, 3374, 3366, 3371, 3376, 3390, 3370, 3373, 1769, 3391, 3381, 3408, 3410, 3397, 3411, 3399, 3414, 3416, 3419, 3422, 3415, 3417, 3402, 3425, 3431, 3424, 3426, 3442, 3446, 1754, 3451, 3432, 3438, 1752, 3448, 1738, 3437, 3461, 3458, 3469, 3472, 3457, 3464, 1732, 3454, 3471, 3475, 3460, 3492, 3481, 3484, 3465, 3498, 3499, 3506, 3503, 3511, 3518, 3517, 3508, 3513, 3519, 3509, 1728, 3525, 3545, 3544, 3535, 3530, 3529, 3546, 3540, 3562, 3567, 3551, 3561, 1722, 3569, 1712, 1693, 1683, 3570, 1682, 3571, 1678, 1644, 3572, 3580, 3577, 1633, 3578, 3579, 3587, 3573, 3589, 3596, 3594, 1631, 3591, 3597, 3614, 3620, 3611, 3621, 3628, 1615, 3629, 3624, 3607, 3632, 3633, 3627, 3634, 1589, 3622, 3638, 3642, 3640, 3636, 3667, 3669, 3670, 3674, 3675, 3680, 1474, 3673, 3677, 3681, 3672, 3683, 1452, 3695, 3659, 3705, 3696, 3690, 3698, 3702, 1387, 1290, 3694, 3719, 1286, 3727, 3709, 3730, 3726, 3732, 3738, 3729, 3725, 3736, 3737, 3746, 3743, 3741, 3768, 1186, 1123, 3757, 3747, 1097, 1083, 3779, 1082, 3767, 3780, 3758, 3771, 3777, 1047, 1026, 3784, 1013, 3770, 3762, 3792, 3793, 907, 3795, 3798, 3791, 3797, 3794, 3808, 3818, 3810, 3811, 3822, 875, 3833, 867, 3834, 3825, 3837, 3838, 864, 3824, 3820, 3839, 3849, 3850, 833, 3845, 821, 3841, 3835, 812, 3852, 811, 3875, 3864, 3876, 3867, 3860, 3873, 807, 801, 3890, 3874, 3891, 3879, 3877, 3881, 3894, 3899, 3917, 3900, 769, 761, 3910, 3905, 3911, 3909, 3925, 3919, 3921, 3922, 3936, 3927, 682, 3912, 681, 3931, 635, 3932, 3937, 3939, 601, 3960, 3949, 3952, 3946, 3975, 526, 3966, 3976, 3977, 3983, 517, 3986, 516, 3987, 3989, 3992, 3993, 3996, 3995, 3990, 515, 3991, 512, 3994, 4001, 4004, 4009, 4010, 4002, 507, 4018, 4017, 4013, 4028, 506, 472, 425, 4023, 4026, 4036, 4029, 410, 371, 4033, 4059, 4060, 4070, 4052, 356, 4062, 4051, 4075, 4072, 4074, 4076, 4079, 4073, 4081, 354, 351, 4078, 4093, 4086, 4089, 4090, 4108, 4111, 4115, 4099, 342, 337, 4116, 4117, 336, 4118, 4120, 306, 301, 283, 4126, 4109, 4133, 4123, 4125, 282, 4135, 4144, 4146, 4136, 4139, 4156, 4160, 4170, 4167, 4153, 4171, 248, 4173, 4163, 235, 4176, 4185, 4177, 4184, 196, 4188, 4183, 4180, 151, 4267, 4242, 4246, 4250, 186, 4254, 4258, 139, 4260, 4262, 109, 102, 87 } ; static const flex_int16_t yy_def[1521] = { 0, 1508, 1, 1509, 1509, 1510, 1510, 1511, 1511, 1508, 1512, 1508, 1508, 1508, 1513, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1514, 1508, 1508, 1508, 1514, 1515, 1508, 1508, 1508, 1515, 1516, 1508, 1508, 1516, 1512, 1512, 1508, 1517, 1513, 1517, 1513, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1514, 1514, 1515, 1515, 1508, 1516, 1516, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1518, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1519, 1518, 1518, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1519, 1519, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1520, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1520, 1520, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 1512, 0, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508 } ; static const flex_int16_t yy_nxt[4334] = { 0, 10, 11, 12, 12, 13, 14, 10, 10, 10, 10, 10, 10, 10, 15, 16, 17, 18, 19, 10, 10, 20, 21, 10, 22, 23, 24, 25, 26, 27, 10, 28, 29, 30, 31, 32, 10, 33, 10, 34, 35, 15, 16, 17, 18, 19, 10, 10, 20, 21, 10, 22, 23, 24, 25, 26, 27, 10, 28, 29, 30, 31, 32, 10, 33, 10, 34, 37, 38, 39, 37, 38, 39, 42, 43, 43, 44, 42, 43, 43, 44, 47, 47, 48, 47, 47, 48, 52, 1134, 74, 55, 53, 55, 55, 131, 61, 75, 57, 80, 58, 107, 107, 51, 726, 40, 81, 59, 40, 104, 60, 615, 45, 51, 51, 51, 45, 74, 51, 49, 76, 51, 49, 61, 75, 57, 80, 58, 51, 56, 77, 51, 78, 81, 59, 52, 104, 60, 62, 53, 79, 109, 82, 51, 106, 63, 83, 76, 89, 64, 84, 102, 65, 66, 51, 67, 51, 77, 50, 78, 50, 50, 85, 105, 51, 62, 103, 79, 51, 82, 212, 106, 63, 83, 51, 89, 64, 84, 102, 65, 66, 86, 67, 68, 51, 112, 112, 69, 50, 85, 105, 70, 51, 103, 117, 87, 71, 72, 51, 88, 73, 51, 109, 90, 109, 109, 94, 51, 86, 51, 68, 91, 107, 107, 69, 118, 95, 92, 70, 96, 93, 117, 87, 71, 72, 100, 88, 73, 51, 51, 90, 112, 112, 94, 101, 97, 51, 51, 91, 98, 114, 120, 118, 95, 92, 115, 96, 93, 51, 51, 99, 50, 100, 50, 50, 116, 55, 51, 55, 55, 51, 101, 97, 51, 121, 119, 98, 114, 120, 122, 123, 124, 115, 51, 125, 128, 51, 99, 51, 127, 51, 126, 116, 51, 129, 130, 51, 51, 133, 51, 134, 121, 119, 51, 56, 132, 122, 123, 124, 135, 51, 125, 128, 51, 142, 51, 127, 51, 126, 144, 136, 129, 130, 51, 51, 133, 138, 134, 294, 139, 140, 51, 132, 51, 51, 51, 135, 137, 143, 51, 51, 142, 145, 146, 51, 51, 144, 136, 147, 149, 51, 148, 51, 150, 141, 151, 51, 51, 191, 51, 51, 51, 154, 51, 137, 143, 51, 152, 155, 145, 146, 156, 153, 51, 51, 147, 149, 51, 148, 51, 150, 141, 151, 51, 163, 51, 164, 51, 51, 154, 51, 51, 207, 51, 152, 155, 169, 51, 156, 153, 157, 51, 51, 158, 165, 51, 170, 51, 173, 159, 160, 163, 175, 164, 161, 166, 51, 176, 162, 167, 171, 168, 51, 169, 51, 51, 51, 157, 51, 172, 158, 165, 51, 170, 51, 173, 159, 160, 174, 175, 51, 161, 166, 177, 176, 162, 167, 171, 168, 51, 178, 109, 51, 109, 109, 179, 172, 180, 181, 182, 184, 51, 51, 51, 183, 174, 185, 51, 186, 51, 177, 192, 187, 51, 190, 188, 51, 178, 51, 193, 51, 196, 179, 51, 180, 181, 182, 184, 51, 189, 51, 183, 51, 185, 51, 186, 51, 51, 192, 187, 195, 190, 188, 194, 197, 51, 193, 198, 196, 51, 199, 200, 201, 202, 203, 208, 189, 211, 51, 209, 210, 51, 51, 51, 204, 51, 51, 195, 51, 205, 194, 197, 215, 51, 198, 51, 51, 199, 200, 201, 202, 203, 213, 206, 211, 217, 216, 220, 51, 51, 51, 204, 219, 221, 214, 51, 205, 51, 51, 51, 218, 222, 223, 51, 225, 51, 51, 51, 51, 51, 206, 51, 229, 216, 220, 51, 224, 51, 51, 219, 221, 214, 51, 51, 51, 51, 226, 218, 222, 223, 227, 225, 228, 51, 51, 51, 230, 231, 232, 229, 233, 235, 51, 224, 234, 236, 51, 237, 240, 51, 51, 244, 51, 226, 51, 239, 51, 227, 238, 228, 51, 241, 245, 230, 231, 232, 242, 233, 235, 51, 243, 234, 246, 51, 237, 240, 251, 256, 51, 51, 252, 51, 239, 51, 51, 238, 254, 248, 241, 253, 51, 258, 51, 242, 249, 51, 247, 243, 51, 51, 255, 257, 51, 251, 250, 51, 51, 252, 51, 264, 51, 260, 51, 254, 248, 261, 253, 259, 258, 263, 266, 249, 51, 247, 51, 262, 51, 255, 257, 51, 267, 250, 265, 51, 51, 51, 264, 51, 260, 51, 268, 271, 261, 269, 259, 51, 263, 266, 272, 270, 51, 273, 262, 282, 277, 274, 276, 267, 275, 265, 51, 51, 51, 51, 51, 51, 283, 268, 284, 51, 269, 278, 51, 51, 51, 272, 270, 51, 279, 280, 51, 277, 274, 276, 51, 275, 51, 51, 281, 287, 285, 51, 289, 295, 288, 286, 290, 292, 278, 51, 51, 51, 51, 51, 296, 279, 280, 51, 293, 291, 51, 51, 298, 297, 51, 281, 287, 285, 51, 289, 295, 288, 286, 290, 292, 51, 51, 299, 300, 315, 301, 302, 51, 51, 51, 293, 291, 303, 304, 298, 297, 305, 306, 318, 307, 51, 51, 309, 51, 51, 308, 343, 51, 314, 299, 51, 51, 301, 302, 316, 51, 317, 51, 320, 303, 304, 51, 51, 305, 306, 51, 307, 51, 310, 309, 51, 51, 308, 319, 51, 314, 51, 311, 312, 51, 51, 316, 313, 317, 330, 320, 51, 51, 326, 331, 327, 51, 51, 51, 334, 310, 332, 51, 51, 356, 319, 333, 51, 328, 311, 312, 329, 51, 51, 313, 321, 330, 51, 342, 51, 326, 331, 327, 353, 51, 322, 334, 51, 332, 323, 324, 335, 325, 333, 338, 328, 51, 51, 329, 51, 344, 339, 321, 336, 51, 342, 337, 340, 345, 51, 353, 346, 322, 347, 341, 51, 323, 324, 51, 325, 355, 352, 51, 51, 51, 51, 51, 344, 339, 348, 336, 51, 349, 337, 340, 345, 51, 350, 346, 51, 347, 341, 351, 51, 354, 357, 51, 355, 352, 358, 51, 359, 360, 362, 51, 361, 348, 369, 51, 349, 51, 51, 370, 51, 350, 363, 51, 365, 366, 351, 368, 354, 357, 371, 372, 51, 358, 367, 364, 51, 362, 51, 361, 51, 369, 51, 51, 51, 51, 370, 373, 51, 363, 51, 365, 366, 374, 368, 51, 379, 371, 372, 375, 377, 367, 364, 378, 376, 381, 380, 382, 385, 51, 51, 51, 51, 51, 373, 51, 383, 391, 384, 387, 374, 51, 386, 379, 51, 389, 375, 377, 51, 51, 378, 376, 381, 380, 382, 390, 394, 51, 51, 388, 51, 51, 392, 383, 51, 384, 387, 51, 51, 386, 51, 393, 389, 395, 397, 398, 396, 399, 51, 51, 400, 51, 390, 394, 51, 51, 388, 401, 51, 392, 402, 403, 404, 51, 51, 51, 405, 407, 393, 51, 395, 397, 406, 396, 399, 51, 51, 400, 51, 410, 51, 51, 408, 411, 401, 51, 414, 402, 403, 404, 409, 51, 51, 405, 407, 51, 412, 51, 51, 406, 413, 415, 417, 418, 51, 416, 51, 421, 51, 408, 411, 51, 51, 414, 419, 51, 420, 409, 51, 51, 51, 51, 423, 412, 51, 425, 429, 413, 415, 417, 418, 422, 416, 51, 421, 51, 51, 51, 424, 51, 51, 419, 426, 420, 51, 430, 431, 433, 435, 423, 432, 443, 425, 429, 51, 51, 439, 427, 422, 428, 445, 51, 444, 434, 51, 424, 51, 436, 51, 426, 51, 442, 430, 431, 433, 435, 440, 432, 441, 51, 437, 446, 51, 438, 427, 447, 428, 445, 51, 51, 434, 51, 448, 51, 436, 51, 51, 449, 442, 459, 451, 51, 452, 440, 450, 441, 453, 437, 446, 455, 438, 454, 51, 51, 51, 456, 458, 51, 51, 448, 460, 457, 51, 462, 51, 463, 459, 451, 461, 452, 51, 450, 51, 466, 465, 51, 469, 51, 467, 51, 464, 470, 51, 51, 51, 51, 51, 460, 457, 51, 462, 51, 463, 51, 468, 461, 51, 472, 473, 51, 466, 465, 474, 469, 51, 467, 471, 464, 470, 51, 475, 478, 51, 51, 476, 51, 51, 487, 485, 51, 479, 468, 480, 486, 472, 473, 488, 482, 477, 474, 51, 51, 51, 471, 489, 51, 481, 475, 478, 51, 490, 476, 51, 51, 487, 483, 491, 479, 484, 480, 493, 51, 492, 488, 482, 477, 51, 51, 494, 51, 495, 489, 51, 481, 51, 497, 504, 490, 51, 496, 509, 498, 483, 491, 51, 484, 51, 51, 500, 492, 51, 499, 502, 51, 503, 51, 51, 501, 51, 505, 549, 51, 497, 51, 51, 51, 496, 51, 498, 506, 51, 510, 51, 511, 507, 500, 513, 512, 499, 502, 51, 503, 51, 514, 501, 515, 505, 517, 516, 51, 518, 51, 523, 51, 508, 51, 550, 51, 510, 519, 511, 51, 51, 513, 512, 51, 51, 51, 51, 520, 514, 521, 515, 524, 517, 516, 522, 518, 51, 523, 51, 508, 525, 526, 51, 530, 519, 531, 527, 51, 529, 51, 528, 532, 533, 51, 520, 536, 521, 537, 524, 51, 535, 522, 51, 51, 534, 51, 51, 525, 51, 51, 530, 538, 531, 51, 51, 529, 542, 528, 532, 51, 51, 540, 536, 51, 537, 539, 541, 535, 51, 544, 51, 534, 51, 51, 545, 543, 547, 551, 538, 546, 51, 552, 555, 542, 548, 51, 569, 553, 540, 51, 554, 51, 539, 541, 51, 563, 544, 556, 51, 51, 51, 564, 543, 547, 551, 51, 565, 51, 552, 555, 51, 548, 51, 569, 553, 51, 567, 554, 51, 51, 51, 568, 563, 51, 556, 557, 570, 572, 564, 558, 571, 577, 559, 565, 566, 51, 51, 575, 576, 560, 561, 573, 562, 51, 574, 51, 51, 51, 51, 51, 51, 51, 557, 570, 572, 51, 558, 571, 577, 559, 580, 566, 578, 51, 575, 576, 560, 561, 573, 562, 579, 574, 51, 581, 584, 582, 583, 585, 588, 586, 595, 587, 51, 589, 51, 51, 593, 580, 51, 578, 51, 590, 592, 594, 597, 51, 591, 579, 601, 598, 51, 51, 582, 583, 585, 51, 586, 51, 587, 51, 589, 51, 51, 51, 51, 596, 599, 600, 590, 592, 602, 51, 603, 591, 51, 51, 598, 51, 606, 51, 607, 51, 604, 605, 51, 51, 614, 608, 609, 610, 51, 51, 596, 599, 600, 51, 620, 602, 51, 603, 51, 619, 51, 618, 51, 606, 617, 607, 621, 51, 51, 51, 51, 51, 608, 609, 610, 611, 611, 611, 51, 51, 622, 620, 612, 623, 625, 51, 619, 51, 618, 51, 613, 617, 624, 626, 51, 627, 628, 629, 51, 630, 51, 51, 51, 51, 51, 51, 51, 622, 631, 612, 623, 625, 633, 51, 51, 51, 632, 613, 634, 624, 626, 51, 627, 628, 629, 51, 630, 635, 638, 636, 637, 639, 51, 51, 643, 631, 51, 51, 640, 633, 641, 51, 644, 632, 51, 51, 51, 51, 51, 51, 51, 646, 642, 51, 635, 638, 636, 637, 639, 51, 647, 643, 648, 51, 645, 640, 51, 641, 652, 644, 649, 51, 51, 51, 653, 51, 51, 654, 646, 642, 650, 664, 51, 651, 51, 662, 51, 647, 51, 648, 51, 645, 51, 665, 51, 652, 51, 649, 51, 660, 663, 653, 666, 51, 654, 667, 51, 650, 51, 51, 651, 655, 662, 656, 661, 676, 51, 657, 51, 658, 665, 51, 668, 51, 659, 670, 660, 663, 51, 678, 51, 674, 667, 671, 669, 51, 675, 51, 655, 673, 656, 661, 676, 672, 657, 51, 658, 680, 677, 668, 682, 659, 670, 51, 51, 51, 51, 51, 674, 681, 671, 669, 51, 675, 688, 679, 673, 51, 51, 51, 672, 683, 684, 685, 680, 677, 51, 682, 690, 686, 687, 689, 51, 691, 51, 51, 681, 51, 51, 51, 692, 688, 679, 693, 704, 51, 697, 698, 683, 51, 51, 51, 699, 51, 51, 51, 686, 687, 689, 700, 694, 51, 51, 702, 695, 708, 51, 692, 51, 51, 693, 696, 701, 697, 698, 703, 707, 51, 51, 699, 51, 51, 51, 706, 709, 705, 700, 694, 51, 713, 702, 695, 708, 710, 714, 51, 51, 51, 696, 701, 717, 51, 703, 707, 711, 51, 712, 51, 715, 716, 706, 709, 705, 51, 51, 718, 713, 719, 1135, 720, 710, 51, 51, 615, 51, 615, 615, 51, 51, 51, 725, 711, 723, 712, 729, 728, 716, 737, 51, 51, 51, 51, 724, 51, 719, 730, 720, 721, 722, 722, 722, 722, 51, 51, 51, 733, 731, 725, 51, 723, 738, 729, 728, 51, 734, 732, 51, 51, 735, 724, 51, 739, 730, 736, 746, 740, 51, 741, 749, 51, 51, 745, 733, 731, 742, 743, 51, 747, 51, 51, 744, 734, 732, 51, 748, 750, 51, 51, 739, 51, 753, 51, 740, 752, 754, 51, 51, 51, 745, 755, 51, 742, 51, 756, 747, 751, 757, 758, 51, 762, 759, 760, 51, 51, 51, 51, 51, 51, 51, 763, 752, 754, 51, 761, 51, 767, 764, 51, 51, 51, 756, 51, 751, 757, 758, 51, 762, 759, 760, 766, 765, 51, 51, 768, 769, 772, 763, 51, 771, 779, 761, 51, 767, 764, 770, 774, 51, 51, 773, 775, 51, 776, 51, 777, 793, 778, 766, 765, 51, 51, 768, 769, 772, 51, 780, 771, 51, 51, 781, 782, 51, 770, 774, 51, 51, 773, 775, 51, 776, 51, 777, 51, 778, 784, 51, 787, 783, 51, 788, 791, 785, 780, 51, 51, 51, 781, 782, 51, 786, 789, 794, 790, 51, 51, 792, 51, 801, 795, 796, 51, 784, 797, 787, 783, 51, 788, 791, 785, 798, 51, 806, 51, 802, 51, 800, 786, 799, 51, 790, 51, 51, 792, 51, 51, 795, 51, 51, 803, 797, 51, 804, 808, 51, 809, 51, 798, 811, 806, 807, 802, 51, 800, 810, 799, 805, 812, 51, 815, 813, 51, 51, 816, 51, 822, 803, 51, 51, 804, 51, 814, 809, 817, 51, 811, 51, 807, 51, 51, 51, 810, 819, 805, 812, 821, 815, 813, 820, 818, 816, 51, 823, 51, 824, 51, 825, 51, 814, 826, 817, 51, 828, 827, 829, 51, 51, 51, 1135, 819, 51, 830, 821, 51, 51, 820, 818, 51, 51, 823, 51, 824, 836, 825, 51, 832, 826, 51, 51, 828, 827, 829, 721, 722, 722, 722, 722, 831, 830, 726, 833, 726, 726, 51, 837, 834, 835, 51, 839, 838, 51, 840, 832, 51, 51, 51, 51, 842, 51, 841, 844, 843, 51, 845, 831, 51, 846, 833, 849, 847, 51, 850, 834, 835, 51, 839, 838, 51, 840, 851, 854, 51, 51, 848, 842, 51, 841, 844, 843, 852, 51, 51, 853, 846, 855, 849, 847, 51, 850, 856, 857, 858, 859, 51, 51, 51, 851, 860, 862, 868, 848, 861, 51, 51, 864, 866, 852, 863, 865, 853, 867, 855, 51, 51, 51, 51, 51, 51, 858, 859, 869, 51, 51, 51, 860, 862, 870, 873, 861, 51, 871, 864, 51, 874, 863, 865, 51, 51, 51, 872, 877, 51, 51, 875, 876, 878, 881, 869, 51, 51, 879, 51, 51, 870, 873, 880, 883, 871, 882, 884, 874, 886, 887, 51, 885, 891, 872, 877, 51, 51, 875, 876, 51, 51, 889, 51, 888, 879, 51, 51, 890, 51, 880, 883, 51, 882, 51, 51, 886, 887, 892, 893, 51, 51, 51, 900, 894, 895, 898, 896, 51, 889, 899, 888, 51, 51, 51, 890, 51, 897, 51, 51, 901, 51, 51, 902, 906, 892, 893, 51, 903, 904, 900, 894, 895, 898, 896, 51, 51, 899, 908, 905, 907, 910, 51, 909, 897, 51, 911, 901, 51, 51, 902, 51, 912, 914, 917, 903, 904, 51, 913, 51, 915, 51, 916, 51, 918, 908, 905, 907, 910, 51, 909, 51, 51, 911, 51, 51, 919, 51, 926, 912, 914, 917, 921, 920, 923, 913, 922, 915, 925, 916, 51, 51, 51, 51, 931, 924, 51, 51, 927, 51, 51, 928, 51, 919, 51, 926, 930, 51, 933, 921, 920, 923, 51, 922, 929, 925, 932, 934, 936, 51, 935, 51, 924, 937, 51, 927, 938, 51, 928, 940, 51, 939, 941, 930, 942, 51, 51, 51, 51, 949, 944, 929, 945, 943, 51, 51, 946, 935, 948, 51, 937, 51, 51, 938, 51, 51, 940, 51, 939, 941, 51, 942, 51, 947, 950, 51, 949, 944, 51, 945, 943, 51, 951, 946, 953, 948, 954, 955, 956, 51, 957, 958, 51, 959, 51, 961, 960, 962, 51, 51, 947, 950, 952, 968, 964, 51, 51, 51, 51, 951, 966, 953, 967, 954, 955, 51, 51, 957, 51, 963, 959, 51, 961, 960, 51, 51, 965, 970, 973, 952, 51, 964, 971, 51, 51, 51, 51, 966, 969, 967, 972, 975, 51, 974, 977, 51, 963, 976, 51, 51, 51, 51, 986, 965, 970, 51, 51, 978, 51, 971, 51, 982, 979, 981, 983, 969, 990, 972, 975, 51, 974, 51, 984, 51, 976, 985, 987, 51, 980, 51, 51, 51, 51, 988, 978, 51, 51, 991, 982, 979, 981, 983, 992, 989, 51, 51, 993, 994, 51, 984, 995, 51, 985, 987, 996, 980, 997, 998, 51, 51, 988, 51, 1001, 51, 991, 999, 51, 1000, 51, 992, 989, 1002, 51, 993, 51, 1003, 51, 995, 51, 51, 51, 996, 1004, 997, 998, 1009, 51, 1005, 1006, 51, 51, 51, 999, 1007, 1000, 51, 51, 1008, 1002, 1010, 51, 1011, 1003, 1012, 1014, 1015, 51, 1013, 51, 1004, 1020, 1018, 51, 51, 1005, 1006, 51, 1016, 1017, 1019, 1007, 51, 51, 51, 1008, 1021, 1010, 51, 1011, 51, 1012, 51, 51, 51, 1013, 1022, 1024, 1032, 1018, 51, 51, 51, 1023, 51, 1016, 1017, 1019, 1025, 1026, 51, 51, 1028, 1021, 1027, 1035, 1029, 1033, 51, 1030, 1031, 51, 1040, 51, 1024, 51, 51, 51, 51, 51, 1023, 51, 1034, 51, 1036, 1025, 1026, 51, 51, 1039, 51, 1027, 1035, 1029, 1037, 51, 1030, 1031, 51, 1041, 1043, 1042, 51, 1045, 1044, 51, 1046, 1047, 51, 1034, 51, 1036, 51, 51, 1038, 1048, 1039, 1050, 1051, 51, 1053, 1049, 51, 1052, 51, 51, 1041, 1043, 1042, 51, 1045, 1044, 51, 1046, 51, 51, 1055, 51, 1056, 1054, 51, 1038, 1048, 1057, 51, 1051, 1058, 1053, 1049, 1059, 1052, 51, 51, 51, 1060, 1061, 1062, 51, 1063, 51, 1064, 51, 1073, 51, 1068, 1056, 1054, 51, 51, 51, 1057, 51, 1069, 1058, 1071, 1066, 1075, 51, 51, 1070, 51, 1060, 1061, 1065, 51, 1063, 1072, 1064, 1067, 51, 51, 1068, 1076, 51, 51, 1074, 51, 51, 51, 1069, 1081, 1071, 1066, 1077, 51, 1080, 1070, 1078, 51, 1082, 1065, 1079, 51, 1072, 51, 1067, 51, 1083, 51, 1076, 51, 1084, 1074, 1087, 51, 1085, 1088, 1081, 1089, 1090, 1077, 1091, 1080, 1086, 1078, 51, 51, 51, 1079, 1093, 51, 1092, 51, 1095, 1083, 51, 51, 1094, 1084, 51, 1097, 51, 1085, 51, 51, 1089, 1090, 1096, 1091, 1099, 1086, 1098, 1100, 1101, 1102, 1107, 1103, 1109, 1092, 1104, 1105, 51, 51, 51, 1094, 51, 51, 51, 1108, 51, 1111, 51, 51, 51, 1096, 51, 1099, 51, 1098, 1100, 1101, 1102, 1106, 1103, 1110, 51, 1104, 1105, 51, 51, 51, 51, 1112, 1114, 1113, 1108, 1115, 1111, 51, 51, 51, 1116, 51, 1120, 1121, 1123, 51, 51, 1126, 1106, 1117, 1110, 1122, 51, 1118, 1119, 51, 1124, 1125, 1112, 1114, 1113, 1129, 1130, 51, 51, 51, 51, 1116, 51, 1120, 1121, 1127, 51, 51, 51, 51, 1117, 1128, 1122, 51, 1118, 1119, 1131, 1124, 1125, 1132, 51, 1136, 1129, 1133, 51, 1138, 51, 51, 1137, 1139, 51, 51, 1127, 51, 1146, 51, 1140, 1141, 1128, 1142, 1143, 1144, 51, 1131, 1147, 51, 1145, 51, 1136, 51, 1133, 1151, 51, 51, 51, 1137, 1139, 51, 51, 51, 51, 1146, 1148, 1140, 1141, 1150, 1142, 1143, 1149, 51, 1152, 1153, 51, 51, 51, 51, 51, 1155, 1151, 1154, 51, 1156, 1157, 51, 1158, 727, 51, 1160, 51, 1148, 1161, 51, 1150, 51, 51, 1149, 51, 51, 1153, 1165, 1159, 1162, 1163, 51, 1155, 1164, 1154, 51, 1156, 51, 51, 1158, 51, 51, 1160, 1166, 1168, 1161, 1167, 1170, 51, 51, 1169, 51, 1172, 1171, 1165, 1159, 1162, 1163, 51, 1173, 1164, 1175, 51, 1174, 51, 51, 51, 51, 51, 51, 1166, 1168, 51, 1167, 1170, 51, 51, 1169, 1176, 1172, 1171, 1179, 1177, 1178, 1183, 1180, 1181, 1182, 1175, 1184, 1174, 51, 51, 51, 1186, 1188, 51, 1189, 1185, 51, 1187, 1190, 1192, 51, 51, 1176, 51, 1191, 1179, 1177, 51, 51, 1180, 1181, 51, 51, 51, 51, 51, 1193, 51, 1186, 1188, 1194, 1189, 1185, 1195, 1187, 1190, 51, 51, 51, 1196, 1197, 1191, 1198, 1199, 1200, 51, 1201, 1202, 1204, 51, 51, 1205, 51, 1193, 51, 51, 51, 1194, 51, 51, 1195, 1208, 51, 51, 1203, 51, 1196, 1197, 1206, 1198, 1207, 1200, 51, 1201, 1202, 1204, 51, 1209, 1205, 51, 1210, 1214, 1211, 51, 51, 1134, 1212, 1134, 1134, 1213, 1215, 1203, 1216, 1218, 51, 1206, 51, 1207, 1225, 51, 51, 1217, 51, 51, 1209, 1219, 1227, 1210, 1214, 1211, 1220, 51, 51, 1221, 51, 51, 1213, 1215, 1224, 51, 1218, 1223, 1222, 51, 51, 51, 51, 51, 1217, 51, 1230, 1226, 1219, 1228, 51, 1229, 1231, 1220, 1232, 1233, 1221, 1234, 1238, 51, 51, 1224, 1235, 1239, 1223, 1222, 51, 51, 51, 1236, 1237, 51, 1242, 1230, 1226, 1240, 1241, 51, 1244, 51, 51, 1232, 1245, 51, 51, 51, 51, 1243, 51, 1235, 1239, 51, 1246, 51, 51, 51, 1236, 1237, 1247, 1242, 51, 51, 1240, 1241, 1248, 1250, 51, 51, 1249, 1251, 1257, 51, 1252, 1254, 1243, 51, 1253, 51, 1258, 1255, 51, 1260, 1262, 51, 1256, 1247, 51, 51, 1264, 51, 51, 1248, 1250, 51, 51, 1249, 1251, 1257, 51, 1252, 51, 51, 1259, 1253, 51, 1258, 1255, 1261, 1260, 1265, 51, 1256, 1263, 51, 1266, 1264, 1268, 1267, 1269, 616, 1274, 51, 1270, 1275, 1271, 1281, 1272, 51, 51, 1259, 1276, 1280, 51, 1273, 1261, 51, 1265, 51, 51, 1263, 51, 1266, 51, 1268, 1267, 1269, 51, 51, 51, 1270, 1275, 1271, 1277, 1272, 51, 1278, 1279, 1276, 51, 51, 1273, 1283, 1282, 1285, 51, 1284, 727, 1286, 1287, 51, 1288, 1289, 51, 51, 51, 51, 1297, 1291, 1290, 1277, 51, 1292, 1278, 1279, 1293, 1294, 1295, 1301, 1283, 1282, 51, 51, 1284, 1302, 1286, 1287, 51, 1296, 51, 51, 51, 51, 51, 1297, 1291, 1290, 51, 51, 51, 51, 1298, 1293, 1294, 1295, 1299, 1300, 51, 1303, 51, 1305, 51, 1310, 51, 51, 1296, 51, 51, 1304, 1306, 1307, 1308, 51, 1309, 1311, 1312, 1314, 51, 1298, 51, 1315, 51, 1299, 1300, 51, 1303, 1313, 1305, 1318, 1310, 51, 51, 51, 1319, 51, 1304, 1306, 51, 51, 51, 1309, 1316, 51, 51, 51, 1317, 51, 1315, 51, 1320, 51, 1321, 51, 1313, 1322, 1318, 1323, 1325, 51, 1324, 1319, 1326, 1333, 1328, 51, 1327, 51, 1329, 1316, 51, 616, 1330, 1317, 51, 51, 1336, 1339, 51, 51, 51, 51, 1322, 51, 51, 51, 51, 1324, 51, 1326, 1333, 51, 51, 1327, 51, 1329, 1331, 1332, 1334, 1330, 1335, 51, 1337, 1336, 1338, 51, 51, 51, 1340, 51, 1341, 51, 1342, 51, 51, 1344, 51, 1343, 1348, 1345, 51, 1346, 51, 1331, 1332, 1334, 1352, 1335, 1347, 1337, 51, 1338, 1349, 1350, 1353, 1340, 51, 51, 51, 1342, 51, 51, 1344, 51, 1343, 1348, 1345, 51, 51, 51, 1351, 1354, 51, 1355, 51, 1347, 1356, 51, 51, 1349, 1350, 1353, 1357, 1359, 51, 1358, 1362, 1360, 51, 51, 1361, 1363, 1365, 51, 1364, 1366, 1367, 1351, 51, 51, 1355, 51, 51, 1356, 1368, 1369, 1371, 1372, 51, 1376, 51, 51, 1358, 1362, 1360, 51, 1370, 1361, 1363, 1365, 1377, 1364, 51, 51, 51, 51, 51, 1373, 51, 51, 1374, 1368, 1369, 1371, 1372, 1375, 1378, 1379, 1390, 51, 1380, 51, 51, 1370, 1381, 51, 1383, 1382, 1385, 51, 1384, 51, 51, 51, 1373, 51, 51, 1374, 1386, 1387, 1389, 1391, 1375, 1388, 51, 51, 51, 1380, 51, 51, 51, 1381, 51, 1383, 1382, 1385, 51, 1384, 1392, 1394, 51, 51, 1395, 51, 1396, 1386, 1387, 1389, 1391, 1393, 1388, 51, 1397, 1398, 51, 51, 1399, 1404, 51, 1403, 1400, 1402, 1401, 51, 51, 51, 51, 51, 51, 1395, 51, 1396, 51, 1409, 1411, 1419, 1393, 1405, 1408, 1397, 1410, 51, 51, 1399, 1406, 51, 1403, 1400, 1402, 1401, 51, 51, 1407, 1412, 1413, 1421, 51, 1414, 1416, 1415, 51, 51, 51, 51, 1405, 1408, 1422, 1410, 51, 1417, 51, 1406, 51, 51, 1418, 1420, 51, 1423, 51, 1407, 1412, 1413, 51, 51, 1414, 1416, 1415, 51, 51, 1424, 51, 1425, 1426, 1422, 1429, 1427, 1417, 51, 1428, 51, 51, 1418, 1420, 51, 1423, 1430, 1431, 51, 1432, 1433, 1434, 51, 1435, 1440, 1441, 51, 1424, 51, 1425, 1426, 51, 1429, 1427, 1436, 1437, 1447, 51, 51, 51, 1438, 1443, 113, 1430, 1431, 51, 1432, 1442, 51, 51, 1439, 51, 51, 51, 51, 51, 51, 51, 51, 1444, 1446, 1436, 1437, 51, 51, 1448, 51, 1438, 1443, 1445, 1449, 51, 51, 1450, 1442, 51, 1451, 1439, 1452, 51, 51, 1453, 1456, 111, 1454, 51, 1444, 1446, 51, 1455, 51, 51, 1448, 1457, 1458, 51, 1445, 1449, 51, 1459, 1450, 1460, 1461, 1451, 1463, 1452, 1462, 1468, 1453, 1456, 110, 1454, 1464, 51, 51, 1469, 1455, 1465, 1473, 1466, 1472, 51, 51, 1467, 51, 108, 1470, 51, 1460, 1461, 113, 1474, 51, 1462, 51, 51, 51, 51, 51, 1464, 51, 51, 1475, 51, 1465, 1476, 1466, 1471, 51, 1477, 1467, 51, 51, 1470, 1478, 51, 1479, 1480, 1474, 1481, 1483, 51, 1485, 1484, 1482, 111, 110, 1486, 108, 51, 51, 51, 1487, 51, 1471, 1492, 1491, 51, 51, 51, 51, 1478, 51, 1479, 1480, 51, 1481, 51, 51, 1488, 1484, 1482, 1489, 1490, 1486, 51, 1493, 51, 51, 1487, 1494, 51, 1492, 1491, 1495, 1498, 51, 1497, 51, 1496, 1508, 1503, 1508, 1499, 1507, 51, 1488, 1500, 51, 1489, 1490, 1502, 51, 1493, 1508, 51, 1504, 1494, 1505, 51, 1501, 1508, 51, 51, 1497, 51, 1496, 1506, 51, 51, 1499, 1508, 51, 1508, 1500, 51, 51, 51, 1502, 1508, 51, 1508, 1508, 1504, 1508, 1505, 1508, 1501, 1508, 1508, 1508, 1508, 1508, 1508, 1506, 36, 36, 36, 36, 41, 41, 41, 41, 46, 46, 46, 46, 54, 54, 1508, 54, 107, 107, 112, 112, 55, 55, 1508, 55, 9, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508 } ; static const flex_int16_t yy_chk[4334] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 11, 1520, 19, 14, 11, 14, 14, 72, 16, 20, 15, 22, 15, 40, 40, 19, 1519, 3, 23, 15, 4, 32, 15, 1518, 5, 15, 16, 20, 6, 19, 23, 7, 21, 22, 8, 16, 20, 15, 22, 15, 72, 14, 21, 32, 21, 23, 15, 52, 32, 15, 17, 52, 21, 1515, 24, 21, 34, 17, 24, 21, 26, 17, 24, 31, 17, 17, 26, 17, 34, 21, 35, 21, 35, 35, 24, 33, 17, 17, 31, 21, 24, 24, 143, 34, 17, 24, 31, 26, 17, 24, 31, 17, 17, 25, 17, 18, 33, 49, 49, 18, 1512, 24, 33, 18, 1507, 31, 59, 25, 18, 18, 143, 25, 18, 59, 45, 27, 45, 45, 28, 25, 25, 18, 18, 27, 108, 108, 18, 60, 28, 27, 18, 28, 27, 59, 25, 18, 18, 30, 25, 18, 28, 27, 27, 113, 113, 28, 30, 29, 60, 1503, 27, 29, 57, 62, 60, 28, 27, 57, 28, 27, 62, 30, 29, 51, 30, 51, 51, 58, 54, 29, 54, 54, 57, 30, 29, 58, 63, 61, 29, 57, 62, 64, 65, 65, 57, 63, 66, 69, 1498, 29, 61, 68, 66, 67, 58, 65, 70, 71, 68, 64, 74, 1495, 75, 63, 61, 71, 54, 73, 64, 65, 65, 76, 69, 66, 69, 67, 79, 70, 68, 73, 67, 81, 77, 70, 71, 75, 74, 74, 78, 75, 220, 78, 78, 76, 73, 1483, 1477, 79, 76, 77, 80, 81, 80, 79, 82, 83, 77, 82, 81, 77, 84, 86, 83, 85, 1476, 87, 78, 88, 220, 1475, 125, 78, 87, 84, 91, 86, 77, 80, 85, 89, 92, 82, 83, 93, 90, 88, 89, 84, 86, 92, 85, 90, 87, 78, 88, 93, 95, 91, 96, 1472, 1469, 91, 95, 125, 139, 1468, 89, 92, 98, 98, 93, 90, 94, 96, 1458, 94, 97, 1457, 99, 1447, 101, 94, 94, 95, 103, 96, 94, 97, 101, 104, 94, 97, 99, 97, 1441, 98, 94, 139, 104, 94, 97, 100, 94, 97, 99, 99, 103, 101, 94, 94, 102, 103, 100, 94, 97, 105, 104, 94, 97, 99, 97, 102, 106, 110, 105, 110, 110, 114, 100, 115, 116, 117, 119, 1440, 116, 106, 118, 102, 120, 114, 121, 115, 105, 126, 122, 118, 124, 123, 1435, 106, 117, 127, 121, 130, 114, 119, 115, 116, 117, 119, 130, 123, 124, 118, 120, 120, 122, 121, 123, 126, 126, 122, 129, 124, 123, 128, 131, 127, 127, 132, 130, 128, 133, 134, 135, 136, 137, 140, 123, 142, 132, 141, 141, 129, 131, 1434, 138, 135, 142, 129, 136, 138, 128, 131, 145, 134, 132, 133, 137, 133, 134, 135, 136, 137, 144, 138, 142, 147, 146, 149, 140, 141, 138, 138, 148, 150, 144, 146, 138, 1433, 1428, 148, 147, 151, 152, 1421, 154, 145, 1419, 1411, 1409, 149, 138, 150, 157, 146, 149, 144, 153, 1404, 147, 148, 150, 144, 152, 153, 151, 154, 155, 147, 151, 152, 156, 154, 156, 155, 157, 156, 158, 159, 160, 157, 161, 163, 158, 153, 162, 164, 161, 165, 168, 159, 160, 172, 162, 155, 163, 167, 165, 156, 166, 156, 167, 169, 173, 158, 159, 160, 170, 161, 163, 168, 171, 162, 175, 170, 165, 168, 177, 182, 164, 171, 178, 166, 167, 169, 172, 166, 180, 176, 169, 179, 180, 185, 1398, 170, 176, 173, 175, 171, 179, 177, 181, 184, 178, 177, 176, 175, 185, 178, 184, 191, 182, 187, 176, 180, 176, 188, 179, 186, 185, 190, 193, 176, 181, 175, 187, 189, 1394, 181, 184, 186, 194, 176, 192, 188, 189, 191, 191, 190, 187, 192, 195, 198, 188, 196, 186, 193, 190, 193, 199, 197, 194, 200, 189, 209, 204, 201, 203, 194, 202, 192, 197, 195, 201, 199, 202, 203, 210, 195, 211, 196, 196, 205, 1392, 1390, 198, 199, 197, 204, 206, 207, 205, 204, 201, 203, 200, 202, 209, 206, 208, 214, 213, 207, 216, 221, 215, 213, 217, 218, 205, 210, 208, 211, 213, 215, 222, 206, 207, 214, 219, 217, 216, 218, 224, 223, 221, 208, 214, 213, 217, 216, 221, 215, 213, 217, 218, 223, 219, 225, 226, 238, 227, 228, 222, 228, 224, 219, 217, 229, 230, 224, 223, 231, 232, 241, 233, 225, 230, 235, 227, 232, 234, 254, 1379, 237, 225, 229, 226, 227, 228, 239, 1378, 240, 238, 243, 229, 230, 233, 231, 231, 232, 235, 233, 234, 236, 235, 237, 241, 234, 242, 240, 237, 239, 236, 236, 254, 243, 239, 236, 240, 246, 243, 236, 1367, 245, 247, 245, 242, 246, 1366, 250, 236, 248, 1359, 1357, 267, 242, 249, 247, 245, 236, 236, 245, 1354, 248, 236, 244, 246, 250, 253, 245, 245, 247, 245, 264, 1352, 244, 250, 249, 248, 244, 244, 251, 244, 249, 252, 245, 253, 267, 245, 244, 255, 252, 244, 251, 264, 253, 251, 252, 256, 255, 264, 257, 244, 258, 252, 1346, 244, 244, 1341, 244, 266, 263, 252, 257, 251, 258, 1339, 255, 252, 259, 251, 256, 260, 251, 252, 256, 259, 261, 257, 260, 258, 252, 262, 263, 265, 268, 266, 266, 263, 269, 261, 270, 270, 272, 262, 271, 259, 278, 1328, 260, 269, 271, 279, 268, 261, 273, 265, 274, 275, 262, 277, 265, 268, 280, 281, 272, 269, 276, 273, 278, 272, 270, 271, 273, 278, 274, 280, 281, 279, 279, 282, 275, 273, 277, 274, 275, 283, 277, 276, 287, 280, 281, 284, 285, 276, 273, 286, 284, 289, 288, 290, 293, 282, 290, 287, 284, 285, 282, 283, 291, 302, 292, 297, 283, 286, 295, 287, 295, 299, 284, 285, 288, 289, 286, 284, 289, 288, 290, 301, 305, 297, 291, 298, 299, 293, 303, 291, 292, 292, 297, 303, 298, 295, 302, 304, 299, 306, 308, 309, 307, 310, 301, 305, 311, 1323, 301, 305, 307, 308, 298, 312, 310, 303, 312, 313, 314, 304, 1321, 306, 315, 317, 304, 314, 306, 308, 316, 307, 310, 312, 311, 311, 309, 320, 313, 316, 318, 321, 312, 1320, 324, 312, 313, 314, 319, 315, 317, 315, 317, 321, 322, 318, 319, 316, 323, 325, 327, 328, 322, 326, 323, 331, 324, 318, 321, 326, 320, 324, 329, 328, 330, 319, 330, 325, 1314, 1312, 333, 322, 327, 334, 336, 323, 325, 327, 328, 332, 326, 331, 331, 1311, 329, 334, 333, 332, 333, 329, 335, 330, 336, 337, 339, 341, 342, 333, 340, 348, 334, 336, 337, 342, 344, 335, 332, 335, 350, 1308, 349, 341, 339, 333, 335, 343, 340, 335, 341, 347, 337, 339, 341, 342, 345, 340, 346, 348, 343, 351, 350, 343, 335, 352, 335, 350, 345, 344, 341, 347, 353, 343, 343, 349, 351, 354, 347, 363, 356, 346, 357, 345, 355, 346, 358, 343, 351, 359, 343, 358, 355, 353, 356, 360, 362, 357, 352, 353, 364, 361, 363, 366, 1307, 367, 363, 356, 365, 357, 354, 355, 361, 370, 369, 365, 373, 359, 371, 358, 368, 374, 364, 360, 362, 366, 370, 364, 361, 368, 366, 367, 367, 371, 372, 365, 369, 376, 377, 373, 370, 369, 378, 373, 374, 371, 375, 368, 374, 372, 379, 381, 375, 377, 380, 376, 378, 387, 386, 381, 382, 372, 383, 386, 376, 377, 388, 384, 380, 378, 387, 382, 379, 375, 389, 380, 383, 379, 381, 388, 390, 380, 384, 383, 387, 385, 391, 382, 385, 383, 393, 386, 392, 388, 384, 380, 389, 391, 394, 385, 395, 389, 390, 383, 1292, 397, 404, 390, 1289, 396, 407, 398, 385, 391, 392, 385, 396, 397, 400, 392, 398, 399, 402, 393, 403, 400, 399, 401, 401, 405, 445, 394, 397, 395, 404, 405, 396, 407, 398, 406, 402, 408, 403, 409, 406, 400, 411, 410, 399, 402, 409, 403, 411, 412, 401, 413, 405, 415, 414, 408, 416, 412, 421, 445, 406, 410, 446, 416, 408, 417, 409, 415, 406, 411, 410, 414, 421, 413, 417, 418, 412, 419, 413, 422, 415, 414, 420, 416, 418, 421, 419, 406, 423, 424, 420, 427, 417, 428, 424, 446, 426, 422, 425, 429, 430, 1288, 418, 433, 419, 434, 422, 426, 432, 420, 423, 425, 431, 427, 429, 423, 432, 428, 427, 435, 428, 433, 424, 426, 439, 425, 429, 431, 430, 437, 433, 434, 434, 436, 438, 432, 436, 441, 435, 431, 438, 437, 442, 440, 444, 447, 435, 442, 439, 448, 451, 439, 444, 447, 463, 449, 437, 440, 450, 441, 436, 438, 451, 457, 441, 452, 1280, 448, 444, 459, 440, 444, 447, 449, 460, 442, 448, 451, 463, 444, 450, 463, 449, 460, 462, 450, 457, 452, 1274, 462, 457, 459, 452, 453, 464, 466, 459, 453, 465, 471, 453, 460, 461, 466, 461, 469, 470, 453, 453, 467, 453, 467, 468, 471, 468, 453, 464, 462, 469, 470, 453, 464, 466, 465, 453, 465, 471, 453, 474, 461, 472, 472, 469, 470, 453, 453, 467, 453, 473, 468, 473, 475, 478, 476, 477, 479, 482, 480, 490, 481, 474, 483, 476, 477, 488, 474, 480, 472, 481, 484, 487, 489, 492, 479, 485, 473, 496, 493, 484, 475, 476, 477, 479, 485, 480, 478, 481, 483, 483, 482, 487, 490, 488, 491, 494, 495, 484, 487, 497, 489, 498, 485, 491, 493, 493, 492, 500, 497, 501, 496, 499, 499, 498, 1262, 508, 502, 503, 505, 494, 495, 491, 494, 495, 503, 513, 497, 502, 498, 500, 512, 501, 511, 512, 500, 510, 501, 514, 513, 505, 1254, 499, 508, 502, 503, 505, 506, 506, 506, 510, 511, 515, 513, 506, 516, 518, 1246, 512, 1238, 511, 515, 506, 510, 517, 519, 514, 520, 521, 522, 1234, 523, 519, 521, 520, 518, 522, 516, 506, 515, 524, 506, 516, 518, 526, 526, 517, 524, 525, 506, 528, 517, 519, 523, 520, 521, 522, 525, 523, 529, 532, 530, 531, 534, 1233, 529, 538, 524, 1231, 1229, 535, 526, 536, 531, 539, 525, 530, 535, 528, 1228, 538, 536, 532, 541, 537, 534, 529, 532, 530, 531, 534, 537, 542, 538, 543, 539, 540, 535, 1227, 536, 547, 539, 544, 540, 542, 541, 548, 544, 1225, 549, 541, 537, 545, 554, 1212, 545, 549, 552, 1192, 542, 543, 543, 547, 540, 1184, 555, 545, 547, 548, 544, 552, 551, 553, 548, 556, 553, 549, 557, 1182, 545, 1178, 554, 545, 550, 552, 550, 551, 564, 555, 550, 557, 550, 555, 551, 558, 1157, 550, 559, 551, 553, 564, 566, 556, 562, 557, 560, 558, 550, 563, 559, 550, 561, 550, 551, 564, 560, 550, 558, 550, 569, 565, 558, 571, 550, 559, 562, 561, 560, 565, 566, 562, 570, 560, 558, 563, 563, 577, 567, 561, 570, 571, 569, 560, 572, 573, 574, 569, 565, 567, 571, 579, 575, 576, 578, 572, 580, 1147, 1145, 570, 575, 576, 577, 582, 577, 567, 583, 592, 583, 585, 586, 572, 1138, 573, 574, 587, 578, 587, 585, 575, 576, 578, 588, 584, 579, 582, 590, 584, 598, 580, 582, 588, 586, 583, 584, 589, 585, 586, 591, 597, 592, 598, 587, 589, 590, 584, 596, 599, 595, 588, 584, 595, 603, 590, 584, 598, 600, 604, 596, 599, 591, 584, 589, 607, 597, 591, 597, 601, 600, 602, 601, 605, 606, 596, 599, 595, 602, 603, 608, 603, 609, 1134, 610, 600, 1132, 1130, 616, 606, 616, 616, 604, 607, 1126, 613, 601, 612, 602, 618, 617, 606, 626, 1123, 609, 610, 605, 612, 608, 609, 619, 610, 611, 611, 611, 611, 611, 613, 617, 612, 623, 620, 613, 618, 612, 627, 618, 617, 620, 624, 622, 619, 622, 625, 612, 626, 628, 619, 625, 635, 629, 624, 630, 638, 623, 611, 633, 623, 620, 631, 632, 631, 636, 627, 628, 632, 624, 622, 633, 637, 639, 1109, 629, 628, 636, 641, 625, 629, 640, 642, 630, 638, 635, 633, 643, 1095, 631, 642, 644, 636, 639, 645, 646, 632, 650, 647, 648, 644, 639, 640, 1088, 646, 637, 641, 651, 640, 642, 647, 649, 645, 655, 652, 643, 651, 648, 644, 650, 639, 645, 646, 652, 650, 647, 648, 654, 653, 649, 653, 656, 657, 660, 651, 655, 659, 669, 649, 654, 655, 652, 658, 662, 656, 657, 661, 663, 659, 665, 1087, 667, 686, 668, 654, 653, 1082, 660, 656, 657, 660, 662, 670, 659, 658, 669, 671, 672, 663, 658, 662, 665, 661, 661, 663, 668, 665, 667, 667, 671, 668, 674, 670, 677, 673, 686, 679, 682, 675, 670, 674, 672, 673, 671, 672, 675, 676, 680, 687, 681, 682, 677, 683, 676, 693, 688, 689, 681, 674, 690, 677, 673, 679, 679, 682, 675, 691, 690, 697, 1075, 694, 1073, 692, 676, 691, 680, 681, 688, 683, 683, 692, 687, 688, 694, 689, 695, 690, 693, 696, 699, 697, 700, 691, 691, 702, 697, 698, 694, 695, 692, 701, 691, 696, 703, 698, 705, 704, 701, 702, 706, 703, 712, 695, 700, 696, 696, 706, 704, 700, 707, 1062, 702, 699, 698, 704, 707, 705, 701, 709, 696, 703, 711, 705, 704, 710, 708, 706, 708, 713, 712, 714, 709, 715, 1059, 704, 716, 707, 710, 720, 719, 721, 714, 711, 715, 1050, 709, 713, 723, 711, 1047, 1037, 710, 708, 716, 719, 713, 723, 714, 731, 715, 720, 725, 716, 725, 721, 720, 719, 721, 722, 722, 722, 722, 722, 724, 723, 727, 728, 727, 727, 724, 732, 729, 730, 728, 734, 733, 731, 735, 725, 729, 734, 730, 733, 737, 1033, 735, 740, 739, 735, 742, 724, 722, 743, 728, 745, 743, 1028, 746, 729, 730, 740, 734, 733, 732, 735, 747, 751, 745, 737, 743, 737, 739, 735, 740, 739, 748, 743, 742, 748, 743, 752, 745, 743, 746, 746, 754, 756, 757, 758, 748, 758, 747, 747, 759, 761, 766, 743, 760, 752, 751, 763, 765, 748, 762, 764, 748, 765, 752, 757, 759, 760, 764, 763, 754, 757, 758, 767, 762, 761, 756, 759, 761, 768, 771, 760, 767, 769, 763, 766, 772, 762, 764, 771, 769, 765, 770, 775, 770, 772, 773, 774, 776, 780, 767, 1015, 775, 777, 774, 768, 768, 771, 778, 782, 769, 781, 783, 772, 784, 785, 773, 783, 790, 770, 775, 778, 784, 773, 774, 782, 776, 787, 777, 786, 777, 1014, 780, 788, 781, 778, 782, 785, 781, 787, 788, 784, 785, 791, 792, 783, 790, 786, 800, 793, 794, 798, 795, 792, 787, 799, 786, 793, 794, 798, 788, 795, 797, 799, 797, 801, 791, 800, 802, 806, 791, 792, 801, 803, 804, 800, 793, 794, 798, 795, 803, 804, 799, 808, 805, 807, 810, 1009, 809, 797, 808, 811, 801, 805, 802, 802, 809, 812, 814, 817, 803, 804, 806, 813, 807, 815, 812, 816, 810, 818, 808, 805, 807, 810, 815, 809, 813, 811, 811, 816, 817, 819, 814, 827, 812, 814, 817, 821, 820, 824, 813, 823, 815, 826, 816, 820, 821, 818, 824, 832, 825, 827, 819, 828, 823, 990, 829, 826, 819, 825, 827, 831, 828, 834, 821, 820, 824, 829, 823, 830, 826, 833, 835, 838, 831, 837, 830, 825, 839, 986, 828, 840, 832, 829, 842, 839, 841, 843, 831, 844, 842, 834, 973, 840, 852, 847, 830, 848, 846, 837, 835, 849, 837, 851, 833, 839, 838, 841, 840, 843, 846, 842, 844, 841, 843, 848, 844, 847, 850, 853, 852, 852, 847, 849, 848, 846, 851, 854, 849, 855, 851, 857, 858, 859, 858, 860, 861, 853, 862, 850, 864, 863, 865, 962, 855, 850, 853, 854, 872, 868, 868, 854, 857, 860, 854, 870, 855, 871, 857, 858, 862, 859, 860, 864, 866, 862, 863, 864, 863, 861, 865, 869, 874, 877, 854, 866, 868, 875, 869, 871, 870, 872, 870, 873, 871, 876, 880, 876, 879, 882, 873, 866, 881, 880, 874, 875, 956, 892, 869, 874, 934, 877, 883, 879, 875, 933, 887, 884, 886, 888, 873, 896, 876, 880, 887, 879, 888, 889, 881, 881, 890, 893, 882, 884, 883, 892, 886, 890, 894, 883, 889, 884, 897, 887, 884, 886, 888, 898, 895, 896, 897, 899, 900, 893, 889, 901, 894, 890, 893, 902, 884, 903, 904, 899, 918, 894, 895, 907, 891, 897, 905, 898, 906, 901, 898, 895, 908, 905, 899, 906, 909, 904, 901, 903, 902, 900, 902, 910, 903, 904, 915, 909, 911, 912, 908, 912, 910, 905, 913, 906, 907, 911, 914, 908, 916, 913, 917, 909, 919, 921, 922, 885, 920, 914, 910, 927, 925, 878, 915, 911, 912, 920, 923, 924, 926, 913, 919, 917, 916, 914, 928, 916, 926, 917, 925, 919, 928, 921, 922, 920, 929, 931, 941, 925, 923, 924, 867, 930, 927, 923, 924, 926, 932, 935, 930, 932, 937, 928, 936, 944, 938, 942, 931, 939, 940, 935, 948, 856, 931, 938, 936, 845, 939, 929, 930, 941, 943, 940, 945, 932, 935, 944, 943, 947, 937, 936, 944, 938, 946, 942, 939, 940, 945, 949, 951, 950, 949, 953, 952, 948, 954, 955, 836, 943, 947, 945, 950, 952, 946, 957, 947, 959, 960, 951, 963, 958, 946, 961, 963, 953, 949, 951, 950, 961, 953, 952, 954, 954, 958, 955, 965, 957, 966, 964, 960, 946, 957, 967, 959, 960, 968, 963, 958, 969, 961, 964, 967, 966, 970, 971, 972, 822, 974, 796, 975, 970, 982, 789, 978, 966, 964, 968, 971, 965, 967, 978, 979, 968, 980, 977, 984, 969, 975, 979, 974, 970, 971, 976, 972, 974, 981, 975, 977, 976, 982, 978, 985, 977, 979, 983, 980, 983, 981, 979, 992, 980, 977, 987, 984, 991, 979, 988, 988, 993, 976, 989, 989, 981, 985, 977, 987, 994, 992, 985, 991, 995, 983, 998, 994, 996, 999, 992, 1000, 1001, 987, 1002, 991, 997, 988, 995, 1001, 993, 989, 1004, 996, 1003, 997, 1006, 994, 1002, 1000, 1005, 995, 1005, 1008, 998, 996, 1003, 999, 1000, 1001, 1007, 1002, 1011, 997, 1010, 1012, 1013, 1016, 1021, 1017, 1023, 1003, 1018, 1019, 1006, 1004, 1010, 1005, 1013, 1018, 1019, 1022, 1007, 1025, 1011, 1012, 1008, 1007, 1016, 1011, 1017, 1010, 1012, 1013, 1016, 1020, 1017, 1024, 1023, 1018, 1019, 1021, 1022, 1020, 1025, 1026, 1029, 1027, 1022, 1030, 1025, 1026, 1027, 1029, 1031, 1024, 1034, 1035, 1038, 779, 755, 1041, 1020, 1032, 1024, 1036, 753, 1032, 1032, 1034, 1039, 1040, 1026, 1029, 1027, 1044, 1045, 1031, 1040, 1032, 1035, 1031, 1030, 1034, 1035, 1042, 1038, 1036, 1039, 1041, 1032, 1043, 1036, 1044, 1032, 1032, 1046, 1039, 1040, 1048, 750, 1051, 1044, 1049, 1045, 1053, 749, 1042, 1052, 1054, 1051, 1046, 1042, 1043, 1061, 744, 1055, 1056, 1043, 1057, 1058, 1060, 1054, 1046, 1063, 741, 1060, 1048, 1051, 1049, 1049, 1067, 1052, 1053, 1061, 1052, 1054, 1055, 1058, 1056, 1057, 1061, 1064, 1055, 1056, 1066, 1057, 1058, 1065, 1064, 1068, 1069, 1063, 1067, 1060, 1065, 738, 1071, 1067, 1070, 1069, 1072, 1074, 736, 1076, 726, 1071, 1078, 1066, 1064, 1079, 718, 1066, 1076, 1072, 1065, 717, 1070, 1069, 1084, 1077, 1080, 1081, 1068, 1071, 1083, 1070, 1077, 1072, 1078, 1074, 1076, 1079, 1080, 1078, 1085, 1089, 1079, 1086, 1091, 1081, 1084, 1090, 1083, 1093, 1092, 1084, 1077, 1080, 1081, 1089, 1094, 1083, 1097, 685, 1096, 684, 1085, 1092, 1086, 1090, 1091, 1085, 1089, 1096, 1086, 1091, 1097, 1093, 1090, 1098, 1093, 1092, 1101, 1099, 1100, 1105, 1102, 1103, 1104, 1097, 1105, 1096, 1099, 1094, 1098, 1107, 1110, 1101, 1111, 1106, 678, 1108, 1112, 1114, 1102, 1103, 1098, 1111, 1113, 1101, 1099, 1110, 1100, 1102, 1103, 1112, 1104, 1106, 1105, 1108, 1115, 1107, 1107, 1110, 1116, 1111, 1106, 1117, 1108, 1112, 1113, 1114, 1115, 1118, 1119, 1113, 1120, 1121, 1122, 1116, 1124, 1125, 1128, 1120, 666, 1129, 664, 1115, 634, 1117, 1122, 1116, 1129, 1124, 1117, 1136, 1119, 1118, 1127, 1125, 1118, 1119, 1131, 1120, 1133, 1122, 1128, 1124, 1125, 1128, 1121, 1137, 1129, 1127, 1139, 1143, 1140, 1131, 1133, 1135, 1141, 1135, 1135, 1142, 1144, 1127, 1146, 1149, 1136, 1131, 1143, 1133, 1156, 1137, 1140, 1148, 1139, 1148, 1137, 1150, 1159, 1139, 1143, 1140, 1151, 1144, 1149, 1152, 1141, 1142, 1142, 1144, 1155, 1151, 1149, 1154, 1153, 1155, 1152, 1146, 1156, 1150, 1148, 1153, 1162, 1158, 1150, 1160, 1159, 1161, 1163, 1151, 1164, 1165, 1152, 1166, 1170, 1154, 1158, 1155, 1167, 1171, 1154, 1153, 1162, 621, 1164, 1168, 1169, 1171, 1174, 1162, 1158, 1172, 1173, 1160, 1176, 1161, 1163, 1164, 1177, 1165, 1169, 1166, 1170, 1175, 1167, 1167, 1171, 1168, 1179, 1174, 1172, 1175, 1168, 1169, 1180, 1174, 1173, 1180, 1172, 1173, 1181, 1185, 1185, 1181, 1183, 1186, 1193, 1176, 1187, 1189, 1175, 1177, 1188, 1183, 1194, 1190, 1179, 1196, 1198, 1193, 1191, 1180, 1190, 1187, 1200, 1196, 1186, 1181, 1185, 1191, 1200, 1183, 1186, 1193, 1188, 1187, 1194, 1189, 1195, 1188, 1195, 1194, 1190, 1197, 1196, 1201, 1198, 1191, 1199, 1199, 1202, 1200, 1204, 1203, 1205, 615, 1210, 1197, 1206, 1211, 1207, 1218, 1208, 1201, 1202, 1195, 1213, 1217, 1204, 1209, 1197, 1203, 1201, 1208, 1211, 1199, 1205, 1202, 1209, 1204, 1203, 1205, 1207, 1206, 1210, 1206, 1211, 1207, 1214, 1208, 1213, 1215, 1216, 1213, 1218, 1217, 1209, 1220, 1219, 1222, 1216, 1221, 614, 1223, 1224, 1220, 1226, 1230, 594, 1215, 1214, 1219, 1242, 1235, 1232, 1214, 1223, 1236, 1215, 1216, 1237, 1239, 1240, 1247, 1220, 1219, 1224, 1221, 1221, 1248, 1223, 1224, 1222, 1241, 1226, 1230, 1232, 1235, 1242, 1242, 1235, 1232, 1237, 1239, 1240, 1236, 1243, 1237, 1239, 1240, 1244, 1245, 1241, 1249, 1243, 1251, 1247, 1257, 593, 1245, 1241, 1244, 1248, 1250, 1252, 1253, 1255, 581, 1256, 1258, 1259, 1261, 1257, 1243, 568, 1263, 1251, 1244, 1245, 1249, 1249, 1260, 1251, 1266, 1257, 1250, 1252, 1263, 1267, 1256, 1250, 1252, 1260, 1253, 1255, 1256, 1264, 1258, 1259, 1261, 1265, 1267, 1263, 1264, 1268, 1266, 1269, 1265, 1260, 1270, 1266, 1271, 1273, 546, 1272, 1267, 1275, 1282, 1277, 533, 1276, 527, 1278, 1264, 1282, 509, 1279, 1265, 507, 504, 1285, 1290, 1268, 486, 1269, 1270, 1270, 1278, 1275, 1271, 1272, 1272, 1276, 1275, 1282, 1273, 1277, 1276, 1279, 1278, 1281, 1281, 1283, 1279, 1284, 1285, 1286, 1285, 1287, 1290, 1281, 1284, 1291, 1286, 1293, 458, 1294, 1287, 456, 1296, 1283, 1295, 1300, 1297, 1294, 1298, 455, 1281, 1281, 1283, 1304, 1284, 1299, 1286, 1291, 1287, 1301, 1302, 1305, 1291, 1300, 1296, 1293, 1294, 1299, 1295, 1296, 1297, 1295, 1300, 1297, 1301, 1302, 1298, 1303, 1306, 1305, 1309, 1304, 1299, 1310, 1303, 1310, 1301, 1302, 1305, 1313, 1316, 454, 1315, 1319, 1317, 1309, 1317, 1318, 1322, 1325, 1325, 1324, 1326, 1327, 1303, 1315, 1306, 1309, 1324, 1318, 1310, 1329, 1330, 1332, 1333, 1319, 1337, 1313, 1316, 1315, 1319, 1317, 1322, 1331, 1318, 1322, 1325, 1338, 1324, 1331, 1326, 1327, 1333, 1329, 1334, 1332, 1330, 1335, 1329, 1330, 1332, 1333, 1336, 1340, 1342, 1356, 1334, 1343, 1336, 1337, 1331, 1344, 443, 1347, 1345, 1349, 1335, 1348, 1348, 338, 1338, 1334, 1347, 1343, 1335, 1350, 1351, 1355, 1358, 1336, 1353, 1340, 1342, 1356, 1343, 1344, 1345, 1349, 1344, 1355, 1347, 1345, 1349, 1353, 1348, 1360, 1362, 1350, 1351, 1363, 1358, 1364, 1350, 1351, 1355, 1358, 1361, 1353, 1364, 1365, 1368, 300, 1361, 1369, 1374, 1363, 1373, 1370, 1372, 1371, 296, 1365, 1369, 1360, 1362, 1372, 1363, 1371, 1364, 1373, 1380, 1382, 1391, 1361, 1375, 1377, 1365, 1381, 1368, 1370, 1369, 1376, 1374, 1373, 1370, 1372, 1371, 1375, 1377, 1376, 1383, 1384, 1395, 1381, 1385, 1387, 1386, 1383, 1380, 1382, 1391, 1375, 1377, 1396, 1381, 1376, 1388, 1385, 1376, 1386, 1387, 1389, 1393, 1384, 1397, 1389, 1376, 1383, 1384, 1393, 1395, 1385, 1387, 1386, 1388, 1396, 1399, 1397, 1400, 1401, 1396, 1405, 1402, 1388, 1402, 1403, 294, 1400, 1389, 1393, 1401, 1397, 1406, 1407, 212, 1408, 1410, 1412, 1399, 1413, 1418, 1420, 183, 1399, 1405, 1400, 1401, 174, 1405, 1402, 1414, 1415, 1427, 1403, 1406, 1407, 1416, 1423, 112, 1406, 1407, 1408, 1408, 1422, 1410, 1412, 1417, 1413, 1418, 1420, 1414, 1415, 1422, 1417, 1416, 1424, 1426, 1414, 1415, 1423, 1427, 1429, 1424, 1416, 1423, 1425, 1430, 1425, 1426, 1431, 1422, 1431, 1432, 1417, 1436, 1430, 1429, 1437, 1442, 111, 1438, 1436, 1424, 1426, 1437, 1439, 1432, 1439, 1429, 1443, 1444, 1442, 1425, 1430, 1438, 1445, 1431, 1446, 1448, 1432, 1450, 1436, 1449, 1455, 1437, 1442, 109, 1438, 1451, 1449, 1446, 1456, 1439, 1452, 1462, 1453, 1461, 1443, 1444, 1454, 1448, 107, 1459, 50, 1446, 1448, 46, 1463, 1445, 1449, 1451, 1455, 1452, 1450, 1453, 1451, 1459, 1454, 1464, 1456, 1452, 1465, 1453, 1460, 1461, 1466, 1454, 1462, 1463, 1459, 1467, 1460, 1470, 1471, 1463, 1473, 1478, 1467, 1480, 1479, 1474, 42, 41, 1481, 36, 10, 1464, 1479, 1482, 1465, 1460, 1488, 1487, 1466, 1470, 1471, 1473, 1467, 1474, 1470, 1471, 1481, 1473, 1482, 1478, 1484, 1479, 1474, 1485, 1486, 1481, 1480, 1489, 1484, 1487, 1482, 1490, 1488, 1488, 1487, 1491, 1494, 1485, 1493, 1486, 1492, 9, 1501, 0, 1496, 1506, 1493, 1484, 1497, 1489, 1485, 1486, 1500, 1490, 1489, 0, 1497, 1502, 1490, 1504, 1492, 1499, 0, 1491, 1494, 1493, 1496, 1492, 1505, 1499, 1501, 1496, 0, 1506, 0, 1497, 1505, 1502, 1500, 1500, 0, 1504, 0, 0, 1502, 0, 1504, 0, 1499, 0, 0, 0, 0, 0, 0, 1505, 1509, 1509, 1509, 1509, 1510, 1510, 1510, 1510, 1511, 1511, 1511, 1511, 1513, 1513, 0, 1513, 1514, 1514, 1516, 1516, 1517, 1517, 0, 1517, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected static int yy_more_flag = 0; static int yy_more_len = 0; #define yymore() ((yy_more_flag) = 1) #define YY_MORE_ADJ (yy_more_len) #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "configlexer.lex" #line 2 "configlexer.lex" /* * configlexer.lex - lexical analyzer for NSD config file * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif #include #include #include #include #ifdef HAVE_GLOB_H # include #endif #include "options.h" #include "configparser.h" #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif struct inc_state { char* filename; int line; YY_BUFFER_STATE buffer; struct inc_state* next; }; static struct inc_state* config_include_stack = NULL; static int inc_depth = 0; static void config_start_include(const char* filename) { FILE *input; struct inc_state* s; char* nm; if(inc_depth++ > 10000000) { c_error("too many include files"); return; } if(strlen(filename) == 0) { c_error("empty include file name"); return; } s = (struct inc_state*)malloc(sizeof(*s)); if(!s) { c_error("include %s: malloc failure", filename); return; } nm = strdup(filename); if(!nm) { c_error("include %s: strdup failure", filename); free(s); return; } input = fopen(filename, "r"); if(!input) { c_error("cannot open include file '%s': %s", filename, strerror(errno)); free(s); free(nm); return; } LEXOUT(("switch_to_include_file(%s) ", filename)); s->filename = cfg_parser->filename; s->line = cfg_parser->line; s->buffer = YY_CURRENT_BUFFER; s->next = config_include_stack; config_include_stack = s; cfg_parser->filename = nm; cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); } static void config_start_include_glob(const char* filename) { /* check for wildcards */ #ifdef HAVE_GLOB glob_t g; int i, r, flags; #endif /* HAVE_GLOB */ if (cfg_parser->chroot) { int l = strlen(cfg_parser->chroot); /* chroot has trailing slash */ if (strncmp(cfg_parser->chroot, filename, l) != 0) { c_error("include file '%s' is not relative to chroot '%s'", filename, cfg_parser->chroot); return; } filename += l - 1; /* strip chroot without trailing slash */ } #ifdef HAVE_GLOB if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') && !strchr(filename, '{') && !strchr(filename, '~'))) { flags = 0 #ifdef GLOB_ERR | GLOB_ERR #endif /* do not set GLOB_NOSORT so the results are sorted and in a predictable order. */ #ifdef GLOB_BRACE | GLOB_BRACE #endif #ifdef GLOB_TILDE | GLOB_TILDE #endif ; memset(&g, 0, sizeof(g)); r = glob(filename, flags, NULL, &g); if(r) { /* some error */ globfree(&g); if(r == GLOB_NOMATCH) return; /* no matches for pattern */ config_start_include(filename); /* let original deal with it */ return; } /* process files found, if any */ for(i=(int)g.gl_pathc-1; i>=0; i--) { config_start_include(g.gl_pathv[i]); } globfree(&g); return; } #endif /* HAVE_GLOB */ config_start_include(filename); } static void config_end_include(void) { struct inc_state* s = config_include_stack; --inc_depth; if(!s) return; free(cfg_parser->filename); cfg_parser->filename = s->filename; cfg_parser->line = s->line; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(s->buffer); config_include_stack = s->next; free(s); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif #line 2317 "" #define YY_NO_INPUT 1 #line 165 "configlexer.lex" #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif #line 2326 "" #line 2328 "" #define INITIAL 0 #define quotedstring 1 #define include 2 #define include_quoted 3 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals ( void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( void ); int yyget_debug ( void ); void yyset_debug ( int debug_flag ); YY_EXTRA_TYPE yyget_extra ( void ); void yyset_extra ( YY_EXTRA_TYPE user_defined ); FILE *yyget_in ( void ); void yyset_in ( FILE * _in_str ); FILE *yyget_out ( void ); void yyset_out ( FILE * _out_str ); int yyget_leng ( void ); char *yyget_text ( void ); int yyget_lineno ( void ); void yyset_lineno ( int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( void ); #else extern int yywrap ( void ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( void ); #else static int input ( void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_load_buffer_state( ); } { #line 183 "configlexer.lex" #line 2548 "" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { (yy_more_len) = 0; if ( (yy_more_flag) ) { (yy_more_len) = (int) ((yy_c_buf_p) - (yytext_ptr)); (yy_more_flag) = 0; } yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1509 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 4267 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 184 "configlexer.lex" { LEXOUT(("SP ")); /* ignore */ } YY_BREAK case 2: YY_RULE_SETUP #line 185 "configlexer.lex" { LEXOUT(("comment(%s) ", yytext)); /* ignore */ } YY_BREAK case 3: YY_RULE_SETUP #line 186 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} YY_BREAK case 4: YY_RULE_SETUP #line 187 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;} YY_BREAK case 5: YY_RULE_SETUP #line 188 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} YY_BREAK case 6: YY_RULE_SETUP #line 189 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} YY_BREAK case 7: YY_RULE_SETUP #line 190 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;} YY_BREAK case 8: YY_RULE_SETUP #line 191 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;} YY_BREAK case 9: YY_RULE_SETUP #line 192 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SEND_BUFFER_SIZE;} YY_BREAK case 10: YY_RULE_SETUP #line 193 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RECEIVE_BUFFER_SIZE;} YY_BREAK case 11: YY_RULE_SETUP #line 194 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;} YY_BREAK case 12: YY_RULE_SETUP #line 195 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;} YY_BREAK case 13: YY_RULE_SETUP #line 196 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;} YY_BREAK case 14: YY_RULE_SETUP #line 197 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_IDENTITY;} YY_BREAK case 15: YY_RULE_SETUP #line 198 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DROP_UPDATES; } YY_BREAK case 16: YY_RULE_SETUP #line 199 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;} YY_BREAK case 17: YY_RULE_SETUP #line 200 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;} YY_BREAK case 18: YY_RULE_SETUP #line 201 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;} YY_BREAK case 19: YY_RULE_SETUP #line 202 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;} YY_BREAK case 20: YY_RULE_SETUP #line 203 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;} YY_BREAK case 21: YY_RULE_SETUP #line 204 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;} YY_BREAK case 22: YY_RULE_SETUP #line 205 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;} YY_BREAK case 23: YY_RULE_SETUP #line 206 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NSID;} YY_BREAK case 24: YY_RULE_SETUP #line 207 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;} YY_BREAK case 25: YY_RULE_SETUP #line 208 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_ONLY_SYSLOG;} YY_BREAK case 26: YY_RULE_SETUP #line 209 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;} YY_BREAK case 27: YY_RULE_SETUP #line 210 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;} YY_BREAK case 28: YY_RULE_SETUP #line 211 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_REJECT_OVERFLOW;} YY_BREAK case 29: YY_RULE_SETUP #line 212 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;} YY_BREAK case 30: YY_RULE_SETUP #line 213 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;} YY_BREAK case 31: YY_RULE_SETUP #line 214 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;} YY_BREAK case 32: YY_RULE_SETUP #line 215 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;} YY_BREAK case 33: YY_RULE_SETUP #line 216 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;} YY_BREAK case 34: YY_RULE_SETUP #line 217 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;} YY_BREAK case 35: YY_RULE_SETUP #line 218 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;} YY_BREAK case 36: YY_RULE_SETUP #line 219 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;} YY_BREAK case 37: YY_RULE_SETUP #line 220 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;} YY_BREAK case 38: YY_RULE_SETUP #line 221 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;} YY_BREAK case 39: YY_RULE_SETUP #line 222 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;} YY_BREAK case 40: YY_RULE_SETUP #line 223 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;} YY_BREAK case 41: YY_RULE_SETUP #line 224 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;} YY_BREAK case 42: YY_RULE_SETUP #line 225 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;} YY_BREAK case 43: YY_RULE_SETUP #line 226 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;} YY_BREAK case 44: YY_RULE_SETUP #line 227 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;} YY_BREAK case 45: YY_RULE_SETUP #line 228 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;} YY_BREAK case 46: YY_RULE_SETUP #line 229 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;} YY_BREAK case 47: YY_RULE_SETUP #line 230 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;} YY_BREAK case 48: YY_RULE_SETUP #line 231 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;} YY_BREAK case 49: YY_RULE_SETUP #line 232 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;} YY_BREAK case 50: YY_RULE_SETUP #line 233 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;} YY_BREAK case 51: YY_RULE_SETUP #line 234 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;} YY_BREAK case 52: YY_RULE_SETUP #line 235 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;} YY_BREAK case 53: YY_RULE_SETUP #line 236 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;} YY_BREAK case 54: YY_RULE_SETUP #line 237 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;} YY_BREAK case 55: YY_RULE_SETUP #line 238 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;} YY_BREAK case 56: YY_RULE_SETUP #line 239 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;} YY_BREAK case 57: YY_RULE_SETUP #line 240 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_QUERY;} YY_BREAK case 58: YY_RULE_SETUP #line 241 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;} YY_BREAK case 59: YY_RULE_SETUP #line 242 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;} YY_BREAK case 60: YY_RULE_SETUP #line 243 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH;} YY_BREAK case 61: YY_RULE_SETUP #line 244 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_DOMAIN_NAME;} YY_BREAK case 62: YY_RULE_SETUP #line 245 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_CERT;} YY_BREAK case 63: YY_RULE_SETUP #line 246 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_KEY;} YY_BREAK case 64: YY_RULE_SETUP #line 247 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_KEY_PW;} YY_BREAK case 65: YY_RULE_SETUP #line 248 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_KEY;} YY_BREAK case 66: YY_RULE_SETUP #line 249 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;} YY_BREAK case 67: YY_RULE_SETUP #line 250 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;} YY_BREAK case 68: YY_RULE_SETUP #line 251 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;} YY_BREAK case 69: YY_RULE_SETUP #line 252 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDE_PATTERN;} YY_BREAK case 70: YY_RULE_SETUP #line 253 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;} YY_BREAK case 71: YY_RULE_SETUP #line 254 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;} YY_BREAK case 72: YY_RULE_SETUP #line 255 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;} YY_BREAK case 73: YY_RULE_SETUP #line 256 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;} YY_BREAK case 74: YY_RULE_SETUP #line 257 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;} YY_BREAK case 75: YY_RULE_SETUP #line 258 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;} YY_BREAK case 76: YY_RULE_SETUP #line 259 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;} YY_BREAK case 77: YY_RULE_SETUP #line 260 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;} YY_BREAK case 78: YY_RULE_SETUP #line 261 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_ENABLE;} YY_BREAK case 79: YY_RULE_SETUP #line 262 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_INTERFACE;} YY_BREAK case 80: YY_RULE_SETUP #line 263 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PORT;} YY_BREAK case 81: YY_RULE_SETUP #line 264 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PATH;} YY_BREAK case 82: YY_RULE_SETUP #line 265 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;} YY_BREAK case 83: YY_RULE_SETUP #line 266 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} YY_BREAK case 84: YY_RULE_SETUP #line 267 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} YY_BREAK case 85: YY_RULE_SETUP #line 268 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;} YY_BREAK case 86: YY_RULE_SETUP #line 269 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;} YY_BREAK case 87: YY_RULE_SETUP #line 270 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;} YY_BREAK case 88: YY_RULE_SETUP #line 271 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;} YY_BREAK case 89: YY_RULE_SETUP #line 272 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;} YY_BREAK case 90: YY_RULE_SETUP #line 273 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;} YY_BREAK case 91: YY_RULE_SETUP #line 274 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RELOAD_CONFIG; } YY_BREAK case 92: YY_RULE_SETUP #line 275 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;} YY_BREAK case 93: YY_RULE_SETUP #line 276 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;} YY_BREAK case 94: YY_RULE_SETUP #line 277 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;} YY_BREAK case 95: YY_RULE_SETUP #line 278 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;} YY_BREAK case 96: YY_RULE_SETUP #line 279 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; } YY_BREAK case 97: YY_RULE_SETUP #line 280 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IP; } YY_BREAK case 98: YY_RULE_SETUP #line 281 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS; } YY_BREAK case 99: YY_RULE_SETUP #line 282 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_SERVER_NAME; } YY_BREAK case 100: YY_RULE_SETUP #line 283 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CERT_BUNDLE; } YY_BREAK case 101: YY_RULE_SETUP #line 284 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CLIENT_KEY_FILE; } YY_BREAK case 102: YY_RULE_SETUP #line 285 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CLIENT_CERT_FILE; } YY_BREAK case 103: YY_RULE_SETUP #line 286 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; } YY_BREAK case 104: YY_RULE_SETUP #line 287 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; } YY_BREAK case 105: YY_RULE_SETUP #line 288 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; } YY_BREAK case 106: YY_RULE_SETUP #line 289 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; } YY_BREAK case 107: YY_RULE_SETUP #line 290 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; } YY_BREAK case 108: YY_RULE_SETUP #line 291 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; } YY_BREAK case 109: YY_RULE_SETUP #line 292 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;} YY_BREAK case 110: YY_RULE_SETUP #line 293 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ISO;} YY_BREAK case 111: YY_RULE_SETUP #line 294 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;} YY_BREAK case 112: YY_RULE_SETUP #line 295 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;} YY_BREAK case 113: YY_RULE_SETUP #line 296 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONFINE_TO_ZONE;} YY_BREAK case 114: YY_RULE_SETUP #line 297 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;} YY_BREAK case 115: YY_RULE_SETUP #line 298 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;} YY_BREAK case 116: YY_RULE_SETUP #line 299 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;} YY_BREAK case 117: YY_RULE_SETUP #line 300 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;} YY_BREAK case 118: YY_RULE_SETUP #line 301 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;} YY_BREAK case 119: YY_RULE_SETUP #line 302 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_EXPIRE_TIME;} YY_BREAK case 120: YY_RULE_SETUP #line 303 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_STORE_IXFR;} YY_BREAK case 121: YY_RULE_SETUP #line 304 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_SIZE;} YY_BREAK case 122: YY_RULE_SETUP #line 305 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_NUMBER;} YY_BREAK case 123: YY_RULE_SETUP #line 306 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CREATE_IXFR;} YY_BREAK case 124: YY_RULE_SETUP #line 307 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} YY_BREAK case 125: YY_RULE_SETUP #line 308 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} YY_BREAK case 126: YY_RULE_SETUP #line 309 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;} YY_BREAK case 127: YY_RULE_SETUP #line 310 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;} YY_BREAK case 128: YY_RULE_SETUP #line 311 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;} YY_BREAK case 129: YY_RULE_SETUP #line 312 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;} YY_BREAK case 130: YY_RULE_SETUP #line 313 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_PORT;} YY_BREAK case 131: YY_RULE_SETUP #line 314 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_XFR_ONLY;} YY_BREAK case 132: YY_RULE_SETUP #line 315 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_CERT_BUNDLE; } YY_BREAK case 133: YY_RULE_SETUP #line 316 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PROXY_PROTOCOL_PORT; } YY_BREAK case 134: YY_RULE_SETUP #line 317 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ANSWER_COOKIE;} YY_BREAK case 135: YY_RULE_SETUP #line 318 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET;} YY_BREAK case 136: YY_RULE_SETUP #line 319 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET_FILE;} YY_BREAK case 137: YY_RULE_SETUP #line 320 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_STAGING_SECRET;} YY_BREAK case 138: YY_RULE_SETUP #line 321 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_MAX;} YY_BREAK case 139: YY_RULE_SETUP #line 322 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_PIPELINE;} YY_BREAK case 140: YY_RULE_SETUP #line 323 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY; } YY_BREAK case 141: YY_RULE_SETUP #line 324 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ENABLE; } YY_BREAK case 142: YY_RULE_SETUP #line 325 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY_ZONE; } YY_BREAK case 143: YY_RULE_SETUP #line 326 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY_ZONES; } YY_BREAK case 144: YY_RULE_SETUP #line 327 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER; } YY_BREAK case 145: YY_RULE_SETUP #line 328 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_COUNT; } YY_BREAK case 146: YY_RULE_SETUP #line 329 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_FEED_ZONE; } YY_BREAK case 147: YY_RULE_SETUP #line 330 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_TIMEOUT; } YY_BREAK case 148: YY_RULE_SETUP #line 331 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG; } YY_BREAK case 149: YY_RULE_SETUP #line 332 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_MEMBER_PATTERN; } YY_BREAK case 150: YY_RULE_SETUP #line 333 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_PRODUCER_ZONE; } YY_BREAK case 151: /* rule 151 can match eol */ YY_RULE_SETUP #line 334 "configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK case 152: YY_RULE_SETUP #line 336 "configlexer.lex" { yyless(yyleng - (yyleng - 8)); LEXOUT(("v(%s) ", yytext)); return VAR_SERVERS; } YY_BREAK case 153: YY_RULE_SETUP #line 341 "configlexer.lex" { yyless(yyleng - (yyleng - 13)); LEXOUT(("v(%s) ", yytext)); return VAR_BINDTODEVICE; } YY_BREAK case 154: YY_RULE_SETUP #line 346 "configlexer.lex" { yyless(yyleng - (yyleng - 7)); LEXOUT(("v(%s) ", yytext)); return VAR_SETFIB; } YY_BREAK case 155: YY_RULE_SETUP #line 352 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CPU_AFFINITY; } YY_BREAK case 156: YY_RULE_SETUP #line 353 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_CPU_AFFINITY; } YY_BREAK case 157: YY_RULE_SETUP #line 354 "configlexer.lex" { char *str = yytext; LEXOUT(("v(%s) ", yytext)); /* Skip server- */ while (*str != '\0' && (*str < '0' || *str > '9')) { str++; } c_lval.llng = strtoll(str, NULL, 10); return VAR_SERVER_CPU_AFFINITY; } YY_BREAK /* Quoted strings. Strip leading and ending quotes */ case 158: YY_RULE_SETUP #line 366 "configlexer.lex" { BEGIN(quotedstring); LEXOUT(("QS ")); } YY_BREAK case YY_STATE_EOF(quotedstring): #line 367 "configlexer.lex" { c_error("EOF inside quoted string"); BEGIN(INITIAL); } YY_BREAK case 159: YY_RULE_SETUP #line 371 "configlexer.lex" { LEXOUT(("STR(%s) ", yytext)); yymore(); } YY_BREAK case 160: /* rule 160 can match eol */ YY_RULE_SETUP #line 372 "configlexer.lex" { cfg_parser->line++; yymore(); } YY_BREAK case 161: YY_RULE_SETUP #line 373 "configlexer.lex" { LEXOUT(("QE ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; c_lval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } YY_BREAK /* include: directive */ case 162: YY_RULE_SETUP #line 382 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); BEGIN(include); } YY_BREAK case YY_STATE_EOF(include): #line 383 "configlexer.lex" { c_error("EOF inside include directive"); BEGIN(INITIAL); } YY_BREAK case 163: YY_RULE_SETUP #line 387 "configlexer.lex" { LEXOUT(("ISP ")); /* ignore */ } YY_BREAK case 164: /* rule 164 can match eol */ YY_RULE_SETUP #line 388 "configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK case 165: YY_RULE_SETUP #line 389 "configlexer.lex" { LEXOUT(("IQS ")); BEGIN(include_quoted); } YY_BREAK case 166: YY_RULE_SETUP #line 390 "configlexer.lex" { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext); BEGIN(INITIAL); } YY_BREAK case YY_STATE_EOF(include_quoted): #line 395 "configlexer.lex" { c_error("EOF inside quoted string"); BEGIN(INITIAL); } YY_BREAK case 167: YY_RULE_SETUP #line 399 "configlexer.lex" { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } YY_BREAK case 168: /* rule 168 can match eol */ YY_RULE_SETUP #line 400 "configlexer.lex" { cfg_parser->line++; yymore(); } YY_BREAK case 169: YY_RULE_SETUP #line 401 "configlexer.lex" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; config_start_include_glob(yytext); BEGIN(INITIAL); } YY_BREAK case YY_STATE_EOF(INITIAL): #line 407 "configlexer.lex" { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (!config_include_stack) { yyterminate(); } else { fclose(yyin); config_end_include(); } } YY_BREAK case 170: YY_RULE_SETUP #line 417 "configlexer.lex" { LEXOUT(("unquotedstr(%s) ", yytext)); c_lval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } YY_BREAK case 171: YY_RULE_SETUP #line 420 "configlexer.lex" ECHO; YY_BREAK #line 3542 "" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1509 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1509 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 1508); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_init_buffer( YY_CURRENT_BUFFER, input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf ); yyfree( (void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr ) { return yy_scan_bytes( yystr, (int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg ) { fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 420 "configlexer.lex" nsd-4.12.0/config.guess0000700000175000017500000014267615002373060014320 0ustar mozziemozzie#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-08-22' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nsd-4.12.0/config.sub0000700000175000017500000010720215002373060013745 0ustar mozziemozzie#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-09-19' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \ | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- ) ;; uclinux-uclibc*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nsd-4.12.0/install-sh0000700000175000017500000003610115002373060013765 0ustar mozziemozzie#!/bin/sh # install - install a program, script, or datafile scriptversion=2023-11-23.18; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Report bugs to . GNU Automake home page: . General help using GNU software: ." while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nsd-4.12.0/config.h.in0000644000175000017500000007034615002373060014027 0ustar mozziemozzie/* config.h.in. Generated from configure.ac by autoheader. */ /* apply the noreturn attribute to a function that exits the program */ #undef ATTR_NORETURN /* apply the weak attribute to a symbol */ #undef ATTR_WEAK /* Define this to enable BIND8 like NSTATS & XSTATS. */ #undef BIND8_STATS /* NSD default chroot directory */ #undef CHROOTDIR /* Command line arguments used with configure */ #undef CONFCMDLINE /* NSD config dir */ #undef CONFIGDIR /* Pathname to the NSD configuration file */ #undef CONFIGFILE /* Pathname to the NSD cookies secrets file. */ #undef COOKIESECRETSFILE /* number of arguments for CPU_OR is three */ #undef CPU_OR_THREE_ARGS /* Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work */ #undef DARWIN_BROKEN_SETREUID /* Whether ERR_load_SSL_strings is deprecated */ #undef DEPRECATED_ERR_LOAD_SSL_STRINGS /* Whether SHA1_Init is deprecated */ #undef DEPRECATED_SHA1_INIT /* default dnstap socket path */ #undef DNSTAP_SOCKET_PATH /* Define to the default maximum message length with EDNS. */ #undef EDNS_MAX_MESSAGE_LEN /* Define to the default facility for syslog. */ #undef FACILITY /* Define to 1 if you have the 'accept4' function. */ #undef HAVE_ACCEPT4 /* Define to 1 if you have the 'alarm' function. */ #undef HAVE_ALARM /* Define to 1 if you have the 'arc4random' function. */ #undef HAVE_ARC4RANDOM /* Define to 1 if you have the 'arc4random_uniform' function. */ #undef HAVE_ARC4RANDOM_UNIFORM /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the 'ASN1_STRING_get0_data' function. */ #undef HAVE_ASN1_STRING_GET0_DATA /* Whether the C compiler accepts the "format" attribute */ #undef HAVE_ATTR_FORMAT /* Whether the C compiler accepts the "noreturn" attribute */ #undef HAVE_ATTR_NORETURN /* Whether the C compiler accepts the "unused" attribute */ #undef HAVE_ATTR_UNUSED /* Whether the C compiler accepts the "weak" attribute */ #undef HAVE_ATTR_WEAK /* Define to 1 if you have the 'b64_ntop' function. */ #undef HAVE_B64_NTOP /* Define to 1 if you have the 'b64_pton' function. */ #undef HAVE_B64_PTON /* Define to 1 if you have the 'basename' function. */ #undef HAVE_BASENAME /* Define to 1 if your system has a working 'chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the 'chroot' function. */ #undef HAVE_CHROOT /* Define to 1 if you have the 'clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if the system has the type 'cpuid_t'. */ #undef HAVE_CPUID_T /* Define to 1 if the system has the type 'cpuset_t'. */ #undef HAVE_CPUSET_T /* Define to 1 if the system has the type 'cpu_set_t'. */ #undef HAVE_CPU_SET_T /* Define to 1 if you have the 'CRYPTO_memcmp' function. */ #undef HAVE_CRYPTO_MEMCMP /* if time.h provides ctime_r prototype */ #undef HAVE_CTIME_R_PROTO /* Define to 1 if you have the declaration of 'reallocarray', and to 0 if you don't. */ #undef HAVE_DECL_REALLOCARRAY /* Define to 1 if you have the declaration of 'SSL_CTX_set_ecdh_auto', and to 0 if you don't. */ #undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO /* Define to 1 if you have the declaration of 'SSL_CTX_set_tmp_ecdh', and to 0 if you don't. */ #undef HAVE_DECL_SSL_CTX_SET_TMP_ECDH /* Define to 1 if you have the 'dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the 'EC_KEY_new_by_curve_name' function. */ #undef HAVE_EC_KEY_NEW_BY_CURVE_NAME /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the 'endpwent' function. */ #undef HAVE_ENDPWENT /* Define to 1 if you have the 'ERR_load_crypto_strings' function. */ #undef HAVE_ERR_LOAD_CRYPTO_STRINGS /* Define to 1 if you have the 'ERR_load_SSL_strings' function. */ #undef HAVE_ERR_LOAD_SSL_STRINGS /* Define to 1 if you have the 'event_base_free' function. */ #undef HAVE_EVENT_BASE_FREE /* Define to 1 if you have the 'event_base_get_method' function. */ #undef HAVE_EVENT_BASE_GET_METHOD /* Define to 1 if you have the 'event_base_new' function. */ #undef HAVE_EVENT_BASE_NEW /* Define to 1 if you have the 'event_base_once' function. */ #undef HAVE_EVENT_BASE_ONCE /* Define to 1 if you have the header file. */ #undef HAVE_EVENT_H /* Define to 1 if you have the 'evhttp_free' function. */ #undef HAVE_EVHTTP_FREE /* Define to 1 if you have the 'EVP_cleanup' function. */ #undef HAVE_EVP_CLEANUP /* Define to 1 if you have the 'EVP_MAC_CTX_get_mac_size' function. */ #undef HAVE_EVP_MAC_CTX_GET_MAC_SIZE /* Define to 1 if you have the 'EVP_MAC_CTX_new' function. */ #undef HAVE_EVP_MAC_CTX_NEW /* Define to 1 if you have the 'EVP_MAC_CTX_set_params' function. */ #undef HAVE_EVP_MAC_CTX_SET_PARAMS /* Define to 1 if you have the 'ev_default_loop' function. */ #undef HAVE_EV_DEFAULT_LOOP /* Define to 1 if you have the 'ev_loop' function. */ #undef HAVE_EV_LOOP /* Define to 1 if you have the 'explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the 'fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the 'freeaddrinfo' function. */ #undef HAVE_FREEADDRINFO /* Define to 1 if fseeko (and ftello) are declared in stdio.h. */ #undef HAVE_FSEEKO /* Define to 1 if you have the 'gai_strerror' function. */ #undef HAVE_GAI_STRERROR /* Define to 1 if you have the 'getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the 'gethostname' function. */ #undef HAVE_GETHOSTNAME /* Define to 1 if you have the 'getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the 'getnameinfo' function. */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the 'getpwnam' function. */ #undef HAVE_GETPWNAM /* Define to 1 if you have the 'getrandom' function. */ #undef HAVE_GETRANDOM /* Define to 1 if you have the 'glob' function. */ #undef HAVE_GLOB /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the 'HMAC_CTX_new' function. */ #undef HAVE_HMAC_CTX_NEW /* Define to 1 if you have the 'HMAC_CTX_reset' function. */ #undef HAVE_HMAC_CTX_RESET /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define to 1 if you have the 'inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the 'inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the 'inet_pton' function. */ #undef HAVE_INET_PTON /* Define to 1 if you have the 'initgroups' function. */ #undef HAVE_INITGROUPS /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the 'crypto' library (-lcrypto). */ #undef HAVE_LIBCRYPTO /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the 'localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the header file. */ #undef HAVE_LOGIN_CAP_H /* Define to 1 if your system has a GNU libc compatible 'malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the 'memcpy' function. */ #undef HAVE_MEMCPY /* Define to 1 if you have the 'memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the 'memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the 'mmap' function. */ #undef HAVE_MMAP /* If sys/socket.h has a struct mmsghdr. */ #undef HAVE_MMSGHDR /* Define to 1 if you have the 'munmap' function. */ #undef HAVE_MUNMAP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_CORE_NAMES_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define to 1 if you have the 'OPENSSL_init_crypto' function. */ #undef HAVE_OPENSSL_INIT_CRYPTO /* Define to 1 if you have the 'OPENSSL_init_ssl' function. */ #undef HAVE_OPENSSL_INIT_SSL /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_OCSP_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_RAND_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_X509V3_H /* Define to 1 if you have the 'ppoll' function. */ #undef HAVE_PPOLL /* Define to 1 if you have the 'pselect' function. */ #undef HAVE_PSELECT /* if sys/select.h provides pselect prototype */ #undef HAVE_PSELECT_PROTO /* Define to 1 if you have the 'pwrite' function. */ #undef HAVE_PWRITE /* If we have reallocarray(3) */ #undef HAVE_REALLOCARRAY /* Define if recvmmsg is implemented */ #undef HAVE_RECVMMSG /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H /* Define this if sched_setaffinity is available */ #undef HAVE_SCHED_SETAFFINITY /* Define if sendmmsg is implemented */ #undef HAVE_SENDMMSG /* Define to 1 if you have the 'setproctitle' function. */ #undef HAVE_SETPROCTITLE /* Define to 1 if you have the 'setregid' function. */ #undef HAVE_SETREGID /* Define to 1 if you have the 'setresgid' function. */ #undef HAVE_SETRESGID /* Define to 1 if you have the 'setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the 'setreuid' function. */ #undef HAVE_SETREUID /* Define to 1 if you have the 'setusercontext' function. */ #undef HAVE_SETUSERCONTEXT /* Define to 1 if you have the 'SHA1_Init' function. */ #undef HAVE_SHA1_INIT /* Define to 1 if you have the 'sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the 'sigprocmask' function. */ #undef HAVE_SIGPROCMASK /* Define to 1 if you have the 'snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the 'socket' function. */ #undef HAVE_SOCKET /* Define if you have the SSL libraries installed. */ #undef HAVE_SSL /* Define to 1 if you have the 'SSL_CTX_set_security_level' function. */ #undef HAVE_SSL_CTX_SET_SECURITY_LEVEL /* Define to 1 if you have the 'SSL_get1_peer_certificate' function. */ #undef HAVE_SSL_GET1_PEER_CERTIFICATE /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the 'strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the 'strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the 'strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the 'strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the 'strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the 'strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the 'strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the 'strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the 'strptime' function. */ #undef HAVE_STRPTIME /* Define to 1 if you have the 'strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if 'sun_len' is a member of 'struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* Define to 1 if 'st_mtimensec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIMENSEC /* Define to 1 if 'st_mtim.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC /* If time.h has a struct timespec (for pselect). */ #undef HAVE_STRUCT_TIMESPEC /* Define to 1 if you have the 'sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if systemd should be used */ #undef HAVE_SYSTEMD /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BITYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_CPUSET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RANDOM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define if TLS 1.3 is supported by OpenSSL */ #undef HAVE_TLS_1_3 /* Define to 1 if you have the 'tzset' function. */ #undef HAVE_TZSET /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define this if you have double va_list definitions. */ #undef HAVE_VA_LIST_DOUBLE_DEF /* Define to 1 if you have the 'vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define to 1 if 'fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if 'vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if you have the 'writev' function. */ #undef HAVE_WRITEV /* Define to the default nsd identity. */ #undef IDENTITY /* Define this to enable IPv6 support. */ #undef INET6 /* If flex defines yy_current_buffer as a macro */ #undef LEX_DEFINES_YY_CURRENT_BUFFER /* Define to the maximum message length to pass to syslog. */ #undef MAXSYSLOGMSGLEN /* Define this to cleanup memory at exit (eg. for valgrind, etc.) */ #undef MEMCLEAN /* Define if memcmp() does not compare unsigned bytes */ #undef MEMCMP_IS_BROKEN /* Define this to enable response minimalization to reduce truncation. */ #undef MINIMAL_RESPONSES /* Define if mkdir has one argument. */ #undef MKDIR_HAS_ONE_ARG /* Undefine this to enable internal runtime checks. */ #undef NDEBUG /* Define if the network stack does not fully support nonblocking io (causes lower performance). */ #undef NONBLOCKING_IS_BROKEN /* Define to the default nsd-control port. */ #undef NSD_CONTROL_PORT /* Define to nsd-control proto version. */ #undef NSD_CONTROL_VERSION /* Define the default metrics HTTP endpoint port. */ #undef NSD_METRICS_PORT /* Pathname to start nsd from nsd-control */ #undef NSD_START_PATH /* Define this to enable NSEC3 support. */ #undef NSEC3 /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define this to use packed structure alignment. */ #undef PACKED_STRUCTS /* Pathname to the NSD pidfile */ #undef PIDFILE /* Define this to enable rate limiting. */ #undef RATELIMIT /* Define this to set ratelimit to off by default. */ #undef RATELIMIT_DEFAULT_OFF /* If reallocarray needs defines to appear in the headers */ #undef REALLOCARRAY_NEEDS_DEFINES /* Return type of signal handlers, but autoconf 2.70 says 'your code may safely assume C89 semantics that RETSIGTYPE is void.' */ #undef RETSIGTYPE /* The size of 'off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T /* The size of 'void*', as computed by sizeof. */ #undef SIZEOF_VOIDP /* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* strptime is available from time.h with some defines. */ #undef STRPTIME_NEEDS_DEFINES /* use default strptime. */ #undef STRPTIME_WORKS /* Define to the backlog to be used with listen. */ #undef TCP_BACKLOG /* Define to the default maximum message length. */ #undef TCP_MAX_MESSAGE_LEN /* Define to the default tcp port. */ #undef TCP_PORT /* Define to the default tcp timeout. */ #undef TCP_TIMEOUT /* Define to the default DNS over TLS port. */ #undef TLS_PORT /* Define to the default maximum udp message length. */ #undef UDP_MAX_MESSAGE_LEN /* Define to the default udp port. */ #undef UDP_PORT /* the user name to drop privileges to */ #undef USER /* Define to 1 to enable dnstap support */ #undef USE_DNSTAP /* Define this to show the role of processes in the logfile for debugging purposes. */ #undef USE_LOG_PROCESS_ROLE /* Define this to expose NSD statistics via a prometheus metrics HTTP endpoint. */ #undef USE_METRICS /* Define if you want to use internal select based events */ #undef USE_MINI_EVENT /* Define this to enable mmap instead of malloc. Experimental. */ #undef USE_MMAP_ALLOC /* Define this to configure to use the radix tree. */ #undef USE_RADIX_TREE /* Enable extensions on AIX, Interix, z/OS. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by C23 Annex F. */ #ifndef __STDC_WANT_IEC_60559_EXT__ # undef __STDC_WANT_IEC_60559_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Define this to enable TCP fast open. */ #undef USE_TCP_FASTOPEN /* Define this to enable per-zone statistics gathering. */ #undef USE_ZONE_STATS /* Define to the default zone verification udp port. */ #undef VERIFY_PORT /* Define to the NSD version to answer version.server query. */ #undef VERSION /* Pathname to the NSD xfrd zone timer state file. */ #undef XFRDFILE /* Pathname to where the NSD transfer dir is created. */ #undef XFRDIR /* Define to 1 if 'lex' declares 'yytext' as a 'char *' by default, not a 'char[]'. */ #undef YYTEXT_POINTER /* Pathname to the NSD zone list file. */ #undef ZONELISTFILE /* NSD default location for zone files. Empty string or NULL to disable. */ #undef ZONESDIR /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to 1 if necessary to make fseeko visible. */ #undef _LARGEFILE_SOURCE /* Define to 1 on platforms where this makes off_t a 64-bit type. */ #undef _LARGE_FILES /* Enable for compile on Minix */ #undef _NETBSD_SOURCE /* Number of bits in time_t, on hosts where this is settable. */ #undef _TIME_BITS /* Define to 1 on platforms where this makes time_t a 64-bit type. */ #undef __MINGW_USE_VC2005_COMPAT /* Define to empty if 'const' does not conform to ANSI C. */ #undef const /* Define as 'int' if doesn't define. */ #undef gid_t /* in_addr_t */ #undef in_addr_t /* Define to '__inline__' or '__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define "int16_t" to "short" if "int16_t" is missing */ #undef int16_t /* Define "int32_t" to "int" if "int32_t" is missing */ #undef int32_t /* Define "int64_t" to "long long" if "int64_t" is missing */ #undef int64_t /* Define "int8_t" to "char" if "int8_t" is missing */ #undef int8_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to 'long int' if does not define. */ #undef off_t /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define "sig_atomic_t" to "int" if "sig_atomic_t" is missing */ #undef sig_atomic_t /* Define as 'unsigned int' if doesn't define. */ #undef size_t /* Define "socklen_t" to "int" if "socklen_t" is missing */ #undef socklen_t /* Fallback member name for socket family in struct sockaddr_storage */ #undef ss_family /* Define "ssize_t" to "int" if "ssize_t" is missing */ #undef ssize_t /* Define "suseconds_t" to "time_t" if "suseconds_t" is missing */ #undef suseconds_t /* Define as 'int' if doesn't define. */ #undef uid_t /* Define "uint16_t" to "unsigned short" if "uint16_t" is missing */ #undef uint16_t /* Define "uint32_t" to "unsigned int" if "uint32_t" is missing */ #undef uint32_t /* Define "uint64_t" to "unsigned long long" if "uint64_t" is missing */ #undef uint64_t /* Define "uint8_t" to "unsigned char" if "uint8_t" is missing */ #undef uint8_t /* Define "uintptr_t" to "void*" if "uintptr_t" is missing */ #undef uintptr_t /* Define as 'fork' if 'vfork' does not work. */ #undef vfork /* define before includes as it specifies what standard to use. */ #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \ || !defined (HAVE_CTIME_R_PROTO) \ || defined (STRPTIME_NEEDS_DEFINES) || defined(REALLOCARRAY_NEEDS_DEFINES) # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 # endif # ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 200112 # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE 1 # endif # ifndef _OPENBSD_SOURCE # define _OPENBSD_SOURCE 1 # endif # ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 # endif # ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 # endif # ifndef _STDC_C99 # define _STDC_C99 1 # endif # ifndef _ALL_SOURCE # define _ALL_SOURCE 1 # endif #endif #ifdef HAVE_VA_LIST_DOUBLE_DEF /* workaround double va_list definition on some platforms */ # ifndef _VA_LIST_DEFINED # define _VA_LIST_DEFINED # endif #endif #include #include #include #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif #ifdef HAVE_ATTR_FORMAT #define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ #define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ #if defined(__cplusplus) #define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) #define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ #define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ #ifndef AF_INET6 #define AF_INET6 28 #endif /* AF_INET6 */ /* maximum nesting of included files */ #define MAXINCLUDES 10 #ifndef HAVE_B64_NTOP int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); #endif /* !HAVE_B64_NTOP */ #ifndef HAVE_B64_PTON int b64_pton(char const *src, uint8_t *target, size_t targsize); #endif /* !HAVE_B64_PTON */ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ #ifndef HAVE_SNPRINTF #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ #ifndef HAVE_INET_PTON int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_EXPLICIT_BZERO #define explicit_bzero nsd_explicit_bzero void explicit_bzero(void* buf, size_t len); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_REALLOCARRAY void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif #ifndef HAVE_STRPTIME #define HAVE_STRPTIME 1 char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif #if (HAVE_CPU_SET_T || HAVE_CPUSET_T) #include "compat/cpuset.h" #endif #ifndef HAVE_SETPROCTITLE #ifdef __linux__ #define HAVE_SETPROCTITLE 1 #include void setproctitle(const char *fmt, ...); #endif #endif #ifdef MEMCMP_IS_BROKEN #include "compat/memcmp.h" #define memcmp memcmp_nsd int memcmp(const void *x, const void *y, size_t n); #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif /* provide timespec def if not available */ #ifndef CONFIG_DEFINES #define CONFIG_DEFINES #ifndef HAVE_STRUCT_TIMESPEC #ifndef __timespec_defined #define __timespec_defined 1 struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* !__timespec_defined */ #endif /* !HAVE_STRUCT_TIMESPEC */ #endif /* !CONFIG_DEFINES */ #ifdef PACKED_STRUCTS #define ATTR_PACKED __attribute__((packed)) #else #define ATTR_PACKED #endif nsd-4.12.0/configure0000755000175000017500000132177615002373060013722 0ustar mozziemozzie#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.72 for NSD 4.12.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case e in #( e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else case e in #( e) exitcode=1; echo positional parameters were not saved. ;; esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else case e in #( e) as_have_required=no ;; esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi ;; esac fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/NLnetLabs/nsd/issues or $0: nsd-bugs@nlnetlabs.nl about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi ;; esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' t clear :clear s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' PACKAGE_VERSION='4.12.0' PACKAGE_STRING='NSD 4.12.0' PACKAGE_BUGREPORT='https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_func_c_list= enable_option_checking=no enable_year2038=no ac_subst_vars='LTLIBOBJS subdirs SYSTEMD_DAEMON_LIBS SYSTEMD_DAEMON_CFLAGS SYSTEMD_LIBS SYSTEMD_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG DNSTAP_OBJ DNSTAP_SRC opt_dnstap_socket_path ENABLE_DNSTAP PROTOC_C SSL_LIBS HAVE_SSL ratelimit_default ratelimit host_os host_vendor host_cpu host build_os build_vendor build_cpu build CPP LIBOBJS INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM LN_S YFLAGS LEXLIB LEX_OUTPUT_ROOT user chrootdir xfrdir cookiesecretsfile zonelistfile xfrdfile zonesdir piddir pidfile logfile nsd_conf_file configdir OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC YACC LEX EGREP GREP AWK SED target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_configdir with_nsd_conf_file with_logfile with_pidfile with_dbfile with_zonesdir with_xfrdfile with_zonelistfile with_cookiesecretsfile with_xfrdir with_chroot with_user enable_flto enable_pie enable_relro_now with_libevent enable_largefile enable_recvmmsg with_facility with_tcp_timeout enable_root_server enable_ipv6 enable_bind8_stats enable_zone_stats enable_checking enable_log_role enable_memclean enable_ratelimit enable_ratelimit_default_is_off with_ssl enable_nsec3 enable_minimal_responses enable_mmap enable_radix_tree enable_packed enable_dnstap with_dnstap_socket_path with_protobuf_c with_libfstrm enable_systemd enable_tcp_fastopen enable_westmere enable_haswell enable_year2038 ' ac_precious_vars='build_alias host_alias target_alias SED AWK GREP EGREP LEX YACC CC CFLAGS LDFLAGS LIBS CPPFLAGS YFLAGS CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR SYSTEMD_CFLAGS SYSTEMD_LIBS SYSTEMD_DAEMON_CFLAGS SYSTEMD_DAEMON_LIBS' ac_subdirs_all='simdzone' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: '$ac_option' Try '$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # 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.12.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, 'make install' will install all the files in '$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify an installation prefix other than '$ac_default_prefix' using '--prefix', for instance '--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/nsd] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of NSD 4.12.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --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 problems for IPv6 --enable-root-server Configure NSD as a root server (obsolete) --disable-ipv6 Disables IPv6 support --enable-bind8-stats Enables BIND8 like NSTATS & XSTATS and statistics in nsd-control --enable-zone-stats Enable per-zone statistics gathering (needs --enable-bind8-stats) --enable-checking Enable internal runtime checks --enable-log-role Shows the role of processes in the logfile (enable this only for debugging purposes) --enable-memclean Cleanup memory (at exit) for eg. valgrind, memcheck --enable-ratelimit Enable rate limiting --enable-ratelimit-default-is-off Enable this to set default of ratelimit to off (enable in nsd.conf), otherwise ratelimit is enabled by default if --enable-ratelimit is enabled --disable-nsec3 Disable NSEC3 support --disable-minimal-responses Disable response minimization. More truncation. --enable-mmap Use mmap instead of malloc. Experimental. --disable-radix-tree You can disable the radix tree and use the red-black tree for the main lookups, the red-black tree uses less memory, but uses some more CPU. --enable-packed Enable packed structure alignment, uses less memory, but unaligned reads. --enable-dnstap Enable dnstap support (requires fstrm, protobuf-c) --enable-systemd compile with systemd support --enable-tcp-fastopen Enable TCP Fast Open --disable-westmere Disable Westmere (SSE4.2) parser kernel --disable-haswell Disable Haswell (AVX2) parser kernel --enable-year2038 support timestamps after 2038 Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-configdir=dir NSD configuration directory --with-nsd_conf_file=path Pathname to the NSD configuration file --with-logfile=path Pathname to the default log file --with-pidfile=path Pathname to the NSD pidfile --with-dbfile=path Pathname to the NSD database (obsolete) --with-zonesdir=dir NSD default location for zone files --with-xfrdfile=path Pathname to the NSD xfrd zone timer state file --with-zonelistfile=path Pathname to the NSD zone list file --with-cookiesecretsfile=path Pathname to the NSD cookie secrets file --with-xfrdir=path Pathname to where the NSD transfer dir is created --with-chroot=dir NSD default chroot directory --with-user=username User name or ID to answer the queries with --with-libevent=pathname use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr /usr/local/opt/libevent or you can specify an explicit path), useful when the zone count is high. --with-facility=name Syslog default facility (LOG_DAEMON) --with-tcp-timeout=number Limit the default tcp timeout --with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr /usr/local/opt/openssl) --with-dnstap-socket-path=pathname set default dnstap socket path --with-protobuf-c=path Path where protobuf-c is installed, for dnstap --with-libfstrm=path Path where libfstrm is installed, for dnstap Some influential environment variables: SED location of the sed program AWK location of the awk program GREP location of the grep program EGREP location of the egrep program LEX location of the lex program with GNU extensions (flex) YACC location of the yacc program with GNU extensions (bison) CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of '-d' given by some make applications. CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path SYSTEMD_CFLAGS C compiler flags for SYSTEMD, overriding pkg-config SYSTEMD_LIBS linker flags for SYSTEMD, overriding pkg-config SYSTEMD_DAEMON_CFLAGS C compiler flags for SYSTEMD_DAEMON, overriding pkg-config SYSTEMD_DAEMON_LIBS linker flags for SYSTEMD_DAEMON, overriding pkg-config Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF NSD configure 4.12.0 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) eval "$3=yes" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status ;; esac fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else case e in #( e) eval "$4=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid; break else case e in #( e) as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=$ac_mid; break else case e in #( e) as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else case e in #( e) ac_lo= ac_hi= ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid else case e in #( e) as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval (void) { return $2; } static unsigned long int ulongval (void) { return $2; } #include #include int main (void) { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : echo >>conftest.val; read $3 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.12.0, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See 'config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* C89 style stringification. */ #define noexpand_stringify(a) #a const char *stringified = noexpand_stringify(arbitrary+token=sequence); /* C89 style token pasting. Exercises some of the corner cases that e.g. old MSVC gets wrong, but not very hard. */ #define noexpand_concat(a,b) a##b #define expand_concat(a,b) noexpand_concat(a,b) extern int vA; extern int vbee; #define aye A #define bee B int *pvA = &expand_concat(v,aye); int *pvbee = &noexpand_concat(v,bee); /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' /* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif // See if C++-style comments work. #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Work around memory leak warnings. free (ia); // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' /* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" as_fn_append ac_header_c_list " vfork.h vfork_h HAVE_VFORK_H" as_fn_append ac_func_c_list " fork HAVE_FORK" as_fn_append ac_func_c_list " vfork HAVE_VFORK" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; esac fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" # # Setup the standard programs # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Setting-Output-Variables.html cmdln="`echo $@ | sed -e 's/\\\\/\\\\\\\\/g' | sed -e 's/"/\\\\"/'g`" printf "%s\n" "#define CONFCMDLINE \"$cmdln\"" >>confdefs.h CFLAGS="$CFLAGS" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. # So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else case e in #( e) ac_file='' ;; esac fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See 'config.log' for more details" "$LINENO" 5; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) # catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will # work properly (i.e., refer to 'conftest.exe'), while it won't with # 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); if (!f) return 1; return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use '--host'. See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext \ conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else case e in #( e) ac_cv_safe_to_define___extensions__=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else case e in #( e) MINIX= ;; esac fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi if test "$ac_cv_header_minix_config_h" = "yes"; then printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h fi case "$prefix" in NONE) case "$sysconfdir" in '${prefix}/etc') sysconfdir=/etc ;; esac case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac ;; esac # # Determine configuration directory # configdir=$sysconfdir/nsd # Check whether --with-configdir was given. if test ${with_configdir+y} then : withval=$with_configdir; configdir=$withval fi cat >>confdefs.h <<_ACEOF #define CONFIGDIR "`eval echo $configdir`" _ACEOF # # Determine configuration file nsd_conf_file=${configdir}/nsd.conf # Check whether --with-nsd_conf_file was given. if test ${with_nsd_conf_file+y} then : withval=$with_nsd_conf_file; nsd_conf_file=$withval fi # the eval is to evaluate shell expansion twice, once # for $nsd_conf_file and once for the ${prefix} within it. cat >>confdefs.h <<_ACEOF #define CONFIGFILE "`eval echo $nsd_conf_file`" _ACEOF # # Default logfile # logfile=${localstatedir}/log/nsd.log # Check whether --with-logfile was given. if test ${with_logfile+y} then : withval=$with_logfile; logfile=$withval fi # # Database directory # dbdir=${localstatedir}/db/nsd # # Determine the pidfile location. Check if /var/run exists, if so set pidfile # to /var/run/nsd.pid by default # if test -d ${localstatedir}/run; then pidfile=${localstatedir}/run/nsd.pid else pidfile=${dbdir}/nsd.pid fi # Check whether --with-pidfile was given. if test ${with_pidfile+y} then : withval=$with_pidfile; pidfile=$withval fi cat >>confdefs.h <<_ACEOF #define PIDFILE "`eval echo $pidfile`" _ACEOF # Check whether --with-dbfile was given. if test ${with_dbfile+y} then : withval=$with_dbfile; fi piddir=`dirname $pidfile` # # Determine the default directory for the zone files # zonesdir=$configdir # Check whether --with-zonesdir was given. if test ${with_zonesdir+y} then : withval=$with_zonesdir; zonesdir=$withval fi cat >>confdefs.h <<_ACEOF #define ZONESDIR "`eval echo $zonesdir`" _ACEOF # default xfrd file location. xfrdfile=${dbdir}/xfrd.state # Check whether --with-xfrdfile was given. if test ${with_xfrdfile+y} then : withval=$with_xfrdfile; xfrdfile=$withval fi cat >>confdefs.h <<_ACEOF #define XFRDFILE "`eval echo $xfrdfile`" _ACEOF # default zonelist file location. zonelistfile=${dbdir}/zone.list # Check whether --with-zonelistfile was given. if test ${with_zonelistfile+y} then : withval=$with_zonelistfile; zonelistfile=$withval fi cat >>confdefs.h <<_ACEOF #define ZONELISTFILE "`eval echo $zonelistfile`" _ACEOF # default cookiesecrets file location. cookiesecretsfile=${dbdir}/cookiesecrets.txt # Check whether --with-cookiesecretsfile was given. if test ${with_cookiesecretsfile+y} then : withval=$with_cookiesecretsfile; cookiesecretsfile=$withval fi cat >>confdefs.h <<_ACEOF #define COOKIESECRETSFILE "`eval echo $cookiesecretsfile`" _ACEOF # default xfr dir location. xfrdir="/tmp" # Check whether --with-xfrdir was given. if test ${with_xfrdir+y} then : withval=$with_xfrdir; xfrdir=$withval fi cat >>confdefs.h <<_ACEOF #define XFRDIR "`eval echo $xfrdir`" _ACEOF # nsd sbin location. tmpinstantiate execprefix with defaults if not yet done. if test "x${exec_prefix}" = "xNONE"; then if test "x${prefix}" = "xNONE"; then exec_prefix="$ac_default_prefix" else exec_prefix="${prefix}"; fi nsd_start_path="`eval echo $sbindir`/nsd" exec_prefix="NONE" else nsd_start_path="`eval echo $sbindir`/nsd" fi printf "%s\n" "#define NSD_START_PATH \"$nsd_start_path\"" >>confdefs.h # # Determine default chroot directory # # Check whether --with-chroot was given. if test ${with_chroot+y} then : withval=$with_chroot; chrootdir=$withval cat >>confdefs.h <<_ACEOF #define CHROOTDIR "`eval echo $chrootdir`" _ACEOF fi # # Determine the user name to drop privileges to # user=nsd # Check whether --with-user was given. if test ${with_user+y} then : withval=$with_user; user=$withval fi printf "%s\n" "#define USER \"$user\"" >>confdefs.h ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in sed gsed do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in #( *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; #( *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in #( *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; #( *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else case e in #( e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in #( *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; #( *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" EGREP_TRADITIONAL=$EGREP ac_cv_path_EGREP_TRADITIONAL=$EGREP for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LEX+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 printf "%s\n" "$LEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %{ #ifdef __cplusplus extern "C" #endif int yywrap(void); %} %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ #ifdef __cplusplus yyless ((yyinput () != 0)); #else yyless ((input () != 0)); #endif } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int yywrap (void) { return 1; } int main (void) { return ! yylex (); } _ACEOF { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex output file root" >&5 printf %s "checking for lex output file root... " >&6; } if test ${ac_cv_prog_lex_root+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_lex_root=unknown { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 printf "%s\n" "$ac_cv_prog_lex_root" >&6; } if test "$ac_cv_prog_lex_root" = unknown then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot find output from $LEX; giving up on $LEX" >&5 printf "%s\n" "$as_me: WARNING: cannot find output from $LEX; giving up on $LEX" >&2;} LEX=: LEXLIB= fi LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test ${LEXLIB+y} then : else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex library" >&5 printf %s "checking for lex library... " >&6; } if test ${ac_cv_lib_lex+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_LIBS="$LIBS" ac_found=false for ac_cv_lib_lex in 'none needed' -lfl -ll 'not found'; do case $ac_cv_lib_lex in #( 'none needed') : ;; #( 'not found') : break ;; #( *) : LIBS="$ac_cv_lib_lex $ac_save_LIBS" ;; #( *) : ;; esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_found=: fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if $ac_found; then break fi done LIBS="$ac_save_LIBS" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 printf "%s\n" "$ac_cv_lib_lex" >&6; } if test "$ac_cv_lib_lex" = 'not found' then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: required lex library not found; giving up on $LEX" >&5 printf "%s\n" "$as_me: WARNING: required lex library not found; giving up on $LEX" >&2;} LEX=: LEXLIB= elif test "$ac_cv_lib_lex" = 'none needed' then : LEXLIB='' else case e in #( e) LEXLIB=$ac_cv_lib_lex ;; esac fi ;; esac fi if test "$LEX" != : then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 printf %s "checking whether yytext is a pointer... " >&6; } if test ${ac_cv_prog_lex_yytext_pointer+y} then : printf %s "(cached) " >&6 else case e in #( e) # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 printf "%s\n" "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then printf "%s\n" "#define YYTEXT_POINTER 1" >>confdefs.h fi fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 printf "%s\n" "$YACC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir ;; esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test "$LEX" != ":" -a "$LEX" != ""; then # Solaris provides anemic tools, and they don't offer GNU extensions like # 'flex -i'. Solaris also does not offer GNU replacements in /usr/gnu/bin. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lex accepts -i" >&5 printf %s "checking whether lex accepts -i... " >&6; } if echo "%%" | $LEX -i -t >/dev/null 2>&1 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "unable to find a lexer that supports -i. If one is available then set the LEX variable" "$LINENO" 5 ;; esac fi # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, # but later could define it as a macro and then we should not redefine it. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if lex defines yy_current_buffer" >&5 printf %s "checking if lex defines yy_current_buffer... " >&6; } cat <conftest.lex %% EOF $LEX -i -t conftest.lex >> conftest.c 2>/dev/null if $GREP "^#define yy_current_buffer" conftest.c >/dev/null; then printf "%s\n" "#define LEX_DEFINES_YY_CURRENT_BUFFER 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f conftest.lex conftest.c fi # Checks for typedefs, structures, and compiler characteristics. # allow user to override the -g -O2 flags. if test "x$CFLAGS" = "x" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -g" >&5 printf %s "checking whether $CC supports -g... " >&6; } cache=`echo g | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -g -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -g" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi # we do not use O3 because it causes miscompilations. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -O2" >&5 printf %s "checking whether $CC supports -O2... " >&6; } cache=`echo O2 | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -O2 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -O2" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi # Check whether --enable-flto was given. if test ${enable_flto+y} then : enableval=$enable_flto; fi if test "x$enable_flto" != "xno" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports -flto" >&5 printf %s "checking if $CC supports -flto... " >&6; } BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -flto" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : if $CC $CFLAGS -o conftest conftest.c 2>&1 | $GREP -e "warning: no debug symbols in executable" -e "warning: object" >/dev/null; then CFLAGS="$BAKCFLAGS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o else case e in #( e) CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi # Check whether --enable-pie was given. if test ${enable_pie+y} then : enableval=$enable_pie; fi if test "x$enable_pie" = "xyes" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports PIE" >&5 printf %s "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 (void) { ; 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o else case e in #( e) LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi # Check whether --enable-relro_now was given. if test ${enable_relro_now+y} then : enableval=$enable_relro_now; fi if test "x$enable_relro_now" = "xyes" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wl,-z,relro,-z,now" >&5 printf %s "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 (void) { ; 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o else case e in #( e) LDFLAGS="$BAKLDFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 printf %s "checking for an ANSI C-conforming const... " >&6; } if test ${ac_cv_c_const+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_const=yes else case e in #( e) ac_cv_c_const=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then printf "%s\n" "#define const /**/" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "uid_t" "ac_cv_type_uid_t" "$ac_includes_default" if test "x$ac_cv_type_uid_t" = xyes then : else case e in #( e) printf "%s\n" "#define uid_t int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "gid_t" "ac_cv_type_gid_t" "$ac_includes_default" if test "x$ac_cv_type_gid_t" = xyes then : else case e in #( e) printf "%s\n" "#define gid_t int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default " if test "x$ac_cv_type_pid_t" = xyes then : else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ LLP64 #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' else case e in #( e) ac_pid_type='__int64' ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else case e in #( e) printf "%s\n" "#define size_t unsigned int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : else case e in #( e) printf "%s\n" "#define off_t long int" >>confdefs.h ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"format\" attribute" >&5 printf %s "checking whether the C compiler (${CC-cc}) accepts the \"format\" attribute... " >&6; } if test ${ac_cv_c_format_attribute+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_format_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); int main (void) { f ("%s", "str"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_format_attribute="yes" else case e in #( e) ac_cv_c_format_attribute="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_format_attribute" >&5 printf "%s\n" "$ac_cv_c_format_attribute" >&6; } if test $ac_cv_c_format_attribute = yes; then printf "%s\n" "#define HAVE_ATTR_FORMAT 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute" >&5 printf %s "checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute... " >&6; } if test ${ac_cv_c_unused_attribute+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_unused_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void f (char *u __attribute__((unused))); int main (void) { f ("x"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_unused_attribute="yes" else case e in #( e) ac_cv_c_unused_attribute="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_unused_attribute" >&5 printf "%s\n" "$ac_cv_c_unused_attribute" >&6; } if test $ac_cv_c_unused_attribute = yes; then printf "%s\n" "#define HAVE_ATTR_UNUSED 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute" >&5 printf %s "checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute... " >&6; } if test ${ac_cv_c_weak_attribute+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_weak_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include __attribute__((weak)) void f(int x) { printf("%d", x); } int main (void) { f(1); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_weak_attribute="yes" else case e in #( e) ac_cv_c_weak_attribute="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_weak_attribute" >&5 printf "%s\n" "$ac_cv_c_weak_attribute" >&6; } if test $ac_cv_c_weak_attribute = yes; then printf "%s\n" "#define HAVE_ATTR_WEAK 1" >>confdefs.h printf "%s\n" "#define ATTR_WEAK __attribute__((weak))" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"noreturn\" attribute" >&5 printf %s "checking whether the C compiler (${CC-cc}) accepts the \"noreturn\" attribute... " >&6; } if test ${ac_cv_c_noreturn_attribute+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_noreturn_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include __attribute__((noreturn)) void f(int x) { printf("%d", x); } int main (void) { f(1); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_noreturn_attribute="yes" else case e in #( e) ac_cv_c_noreturn_attribute="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_noreturn_attribute" >&5 printf "%s\n" "$ac_cv_c_noreturn_attribute" >&6; } if test $ac_cv_c_noreturn_attribute = yes; then printf "%s\n" "#define HAVE_ATTR_NORETURN 1" >>confdefs.h printf "%s\n" "#define ATTR_NORETURN __attribute__((__noreturn__))" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memcmp compares unsigned" >&5 printf %s "checking if memcmp compares unsigned... " >&6; } if test "$cross_compiling" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compile no" >&5 printf "%s\n" "cross-compile no" >&6; } printf "%s\n" "#define MEMCMP_IS_BROKEN 1" >>confdefs.h case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main(void) { char a = 255, b = 0; if(memcmp(&a, &b, 1) < 0) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "#define MEMCMP_IS_BROKEN 1" >>confdefs.h case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ctime_r works with two arguments" >&5 printf %s "checking whether ctime_r works with two arguments... " >&6; } if test ${ac_cv_c_ctime_c+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_ctime_c=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void testing (void) { time_t clock; char current_time[40]; ctime_r(&clock, current_time); } int main (void) { testing(); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_ctime_c="yes" else case e in #( e) ac_cv_c_ctime_c="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_ctime_c" >&5 printf "%s\n" "$ac_cv_c_ctime_c" >&6; } if test $ac_cv_c_ctime_c = no; then CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" fi # Checks for libraries. # Check for SSL, original taken from # http://www.gnu.org/software/ac-archive/htmldoc/check_ssl.html and # modified for NSD. # check for libevent # Check whether --with-libevent was given. if test ${with_libevent+y} then : withval=$with_libevent; else case e in #( e) withval="yes" ;; esac fi if test x_$withval = x_yes -o x_$withval != x_no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libevent" >&5 printf %s "checking for libevent... " >&6; } if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr /usr/local/opt/libevent" fi for dir in $withval; do thedir="$dir" if test -f "$dir/include/event.h" -o -f "$dir/include/event2/event.h"; then found_libevent="yes" if test "$thedir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$thedir/include" fi break; fi done if test x_$found_libevent != x_yes; then if test -f "$dir/event.h" -a \( -f "$dir/libevent.la" -o -f "$dir/libev.la" \) ; then # libevent source directory { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found in $thedir" >&5 printf "%s\n" "found in $thedir" >&6; } CPPFLAGS="$CPPFLAGS -I$thedir -I$thedir/include" # remove evdns from linking ev_files_o=`ls $thedir/*.o | $GREP -v evdns\.o | $GREP -v bufferevent_openssl\.o` cp $ev_files_o . LDFLAGS="$ev_files_o $LDFLAGS -lm" else as_fn_error $? "Cannot find the libevent library. You can restart ./configure --with-libevent=no to use a builtin alternative." "$LINENO" 5 fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found in $thedir" >&5 printf "%s\n" "found in $thedir" >&6; } if test ! -f $thedir/lib/libevent.a -a ! -f $thedir/lib/libevent.so -a -d "$thedir/lib/event2"; then LDFLAGS="$LDFLAGS -L$thedir/lib/event2" if test "x$enable_rpath" = xyes; then if echo "$thedir/lib/event2" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib/event2" fi fi else if test "$thedir" != "/usr" -a "$thedir" != ""; then LDFLAGS="$LDFLAGS -L$thedir/lib" if test "x$enable_rpath" = xyes; then if echo "$thedir/lib" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib" fi fi fi fi fi # check for library used by libevent after 1.3c { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char clock_gettime (void); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else case e in #( e) ac_cv_search_clock_gettime=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # is the event.h header libev or libevent? ac_fn_c_check_header_compile "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default " if test "x$ac_cv_header_event_h" = xyes then : printf "%s\n" "#define HAVE_EVENT_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else case e in #( e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; esac fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "EV_VERSION_MAJOR" "ac_cv_have_decl_EV_VERSION_MAJOR" "$ac_includes_default #include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_EV_VERSION_MAJOR" = xyes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing event_set" >&5 printf %s "checking for library containing event_set... " >&6; } if test ${ac_cv_search_event_set+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char event_set (void); int main (void) { return event_set (); ; return 0; } _ACEOF for ac_lib in '' ev do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_event_set=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_event_set+y} then : break fi done if test ${ac_cv_search_event_set+y} then : else case e in #( e) ac_cv_search_event_set=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 printf "%s\n" "$ac_cv_search_event_set" >&6; } ac_res=$ac_cv_search_event_set if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing event_set" >&5 printf %s "checking for library containing event_set... " >&6; } if test ${ac_cv_search_event_set+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char event_set (void); int main (void) { return event_set (); ; return 0; } _ACEOF for ac_lib in '' event do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_event_set=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_event_set+y} then : break fi done if test ${ac_cv_search_event_set+y} then : else case e in #( e) ac_cv_search_event_set=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 printf "%s\n" "$ac_cv_search_event_set" >&6; } ac_res=$ac_cv_search_event_set if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi ;; esac fi ac_fn_c_check_func "$LINENO" "event_base_free" "ac_cv_func_event_base_free" if test "x$ac_cv_func_event_base_free" = xyes then : printf "%s\n" "#define HAVE_EVENT_BASE_FREE 1" >>confdefs.h fi # only in libevent 1.2 and later ac_fn_c_check_func "$LINENO" "event_base_once" "ac_cv_func_event_base_once" if test "x$ac_cv_func_event_base_once" = xyes then : printf "%s\n" "#define HAVE_EVENT_BASE_ONCE 1" >>confdefs.h fi # only in libevent 1.4.1 and later ac_fn_c_check_func "$LINENO" "event_base_new" "ac_cv_func_event_base_new" if test "x$ac_cv_func_event_base_new" = xyes then : printf "%s\n" "#define HAVE_EVENT_BASE_NEW 1" >>confdefs.h fi # only in libevent 1.4.1 and later ac_fn_c_check_func "$LINENO" "event_base_get_method" "ac_cv_func_event_base_get_method" if test "x$ac_cv_func_event_base_get_method" = xyes then : printf "%s\n" "#define HAVE_EVENT_BASE_GET_METHOD 1" >>confdefs.h fi # only in libevent 1.4.3 and later ac_fn_c_check_func "$LINENO" "ev_loop" "ac_cv_func_ev_loop" if test "x$ac_cv_func_ev_loop" = xyes then : printf "%s\n" "#define HAVE_EV_LOOP 1" >>confdefs.h fi # only in libev. (tested on 3.51) ac_fn_c_check_func "$LINENO" "ev_default_loop" "ac_cv_func_ev_default_loop" if test "x$ac_cv_func_ev_default_loop" = xyes then : printf "%s\n" "#define HAVE_EV_DEFAULT_LOOP 1" >>confdefs.h fi # only in libev. (tested on 4.00) # prometheus metrics depend on libevent 2.0 and later, and is therefore # only enabled when the required version is found and used for ac_func in evhttp_free do : ac_fn_c_check_func "$LINENO" "evhttp_free" "ac_cv_func_evhttp_free" if test "x$ac_cv_func_evhttp_free" = xyes then : printf "%s\n" "#define HAVE_EVHTTP_FREE 1" >>confdefs.h printf "%s\n" "#define USE_METRICS /**/" >>confdefs.h printf "%s\n" "#define NSD_METRICS_PORT 9100" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: disabling prometheus metrics" >&5 printf "%s\n" "$as_me: disabling prometheus metrics" >&6;} ;; esac fi done else printf "%s\n" "#define USE_MINI_EVENT 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Prometheus metrics are disabled with the builtin libevent alternative" >&5 printf "%s\n" "$as_me: Prometheus metrics are disabled with the builtin libevent alternative" >&6;} fi # Checks for header files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test ${ac_cv_header_sys_wait_h+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main (void) { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_sys_wait_h=yes else case e in #( e) ac_cv_header_sys_wait_h=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "time.h" "ac_cv_header_time_h" "$ac_includes_default " if test "x$ac_cv_header_time_h" = xyes then : printf "%s\n" "#define HAVE_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default " if test "x$ac_cv_header_arpa_inet_h" = xyes then : printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "signal.h" "ac_cv_header_signal_h" "$ac_includes_default " if test "x$ac_cv_header_signal_h" = xyes then : printf "%s\n" "#define HAVE_SIGNAL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default " if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default " if test "x$ac_cv_header_strings_h" = xyes then : printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default " if test "x$ac_cv_header_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default " if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default " if test "x$ac_cv_header_netinet_in_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "$ac_includes_default " if test "x$ac_cv_header_netinet_tcp_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default " if test "x$ac_cv_header_stddef_h" = xyes then : printf "%s\n" "#define HAVE_STDDEF_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default " if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default " if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default " if test "x$ac_cv_header_sys_un_h" = xyes then : printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "syslog.h" "ac_cv_header_syslog_h" "$ac_includes_default " if test "x$ac_cv_header_syslog_h" = xyes then : printf "%s\n" "#define HAVE_SYSLOG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default " if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default " if test "x$ac_cv_header_sys_select_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdarg.h" "ac_cv_header_stdarg_h" "$ac_includes_default " if test "x$ac_cv_header_stdarg_h" = xyes then : printf "%s\n" "#define HAVE_STDARG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default " if test "x$ac_cv_header_stdint_h" = xyes then : printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default " if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/bitypes.h" "ac_cv_header_sys_bitypes_h" "$ac_includes_default " if test "x$ac_cv_header_sys_bitypes_h" = xyes then : printf "%s\n" "#define HAVE_SYS_BITYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "tcpd.h" "ac_cv_header_tcpd_h" "$ac_includes_default " if test "x$ac_cv_header_tcpd_h" = xyes then : printf "%s\n" "#define HAVE_TCPD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "glob.h" "ac_cv_header_glob_h" "$ac_includes_default " if test "x$ac_cv_header_glob_h" = xyes then : printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default " if test "x$ac_cv_header_grp_h" = xyes then : printf "%s\n" "#define HAVE_GRP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default " if test "x$ac_cv_header_endian_h" = xyes then : printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default " if test "x$ac_cv_header_sys_random_h" = xyes then : printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default " if test "x$ac_cv_header_ifaddrs_h" = xyes then : printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for double definition of struct va_list" >&5 printf %s "checking for double definition of struct va_list... " >&6; } if test ${ac_cv_c_va_list_def+y} then : printf %s "(cached) " >&6 else case e in #( e) cat >conftest.c < #include int foo(void); EOF if test -z "`$CC -Werror -D_XOPEN_SOURCE=600 -c conftest.c 2>&1`"; then eval "ac_cv_c_va_list_def=no" else eval "ac_cv_c_va_list_def=yes" fi rm -f conftest* ;; esac fi if test $ac_cv_c_va_list_def = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : printf "%s\n" "#define HAVE_VA_LIST_DOUBLE_DEF /**/" >>confdefs.h else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strptime needs defines" >&5 printf %s "checking whether strptime needs defines... " >&6; } if test ${ac_cv_c_strptime_needs_defs+y} then : printf %s "(cached) " >&6 else case e in #( e) cat >conftest.c < int testing (void) { struct tm t; const char *timestr="201201"; return strptime(timestr, "%Y%m", &t) != 0; } EOF if test -z "`$CC -Wall -Werror -c conftest.c 2>&1`"; then eval "ac_cv_c_strptime_needs_defs=no" else eval "ac_cv_c_strptime_needs_defs=yes" fi rm -f conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_strptime_needs_defs" >&5 printf "%s\n" "$ac_cv_c_strptime_needs_defs" >&6; } if test $ac_cv_c_strptime_needs_defs = yes; then printf "%s\n" "#define STRPTIME_NEEDS_DEFINES 1" >>confdefs.h fi # check wether strptime also works { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inet_pton" >&5 printf %s "checking for library containing inet_pton... " >&6; } if test ${ac_cv_search_inet_pton+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char inet_pton (void); int main (void) { return inet_pton (); ; return 0; } _ACEOF for ac_lib in '' nsl do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_inet_pton=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_inet_pton+y} then : break fi done if test ${ac_cv_search_inet_pton+y} then : else case e in #( e) ac_cv_search_inet_pton=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_pton" >&5 printf "%s\n" "$ac_cv_search_inet_pton" >&6; } ac_res=$ac_cv_search_inet_pton if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 printf %s "checking for library containing socket... " >&6; } if test ${ac_cv_search_socket+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char socket (void); int main (void) { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_socket+y} then : break fi done if test ${ac_cv_search_socket+y} then : else case e in #( e) ac_cv_search_socket=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 printf "%s\n" "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strptime works" >&5 printf %s "checking whether strptime works... " >&6; } if test c${cross_compiling} = cno; then if test "$cross_compiling" = yes then : eval "ac_cv_c_strptime_works=maybe" else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 600 #include int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : eval "ac_cv_c_strptime_works=yes" else case e in #( e) eval "ac_cv_c_strptime_works=no" ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi else eval "ac_cv_c_strptime_works=maybe" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_strptime_works" >&5 printf "%s\n" "$ac_cv_c_strptime_works" >&6; } if test $ac_cv_c_strptime_works = no; then case " $LIBOBJS " in *" strptime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strptime.$ac_objext" ;; esac else printf "%s\n" "#define STRPTIME_WORKS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if nonblocking sockets work" >&5 printf %s "checking if nonblocking sockets work... " >&6; } if echo $host | grep mingw >/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (windows)" >&5 printf "%s\n" "no (windows)" >&6; } printf "%s\n" "#define NONBLOCKING_IS_BROKEN 1" >>confdefs.h else if test "$cross_compiling" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: crosscompile(yes)" >&5 printf "%s\n" "crosscompile(yes)" >&6; } else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif int main(void) { int port; int sfd, cfd; int num = 10; int i, p; struct sockaddr_in a; /* test if select and nonblocking reads work well together */ /* open port. fork child to send 10 messages. select to read. then try to nonblocking read the 10 messages then, nonblocking read must give EAGAIN */ port = 12345 + (time(0)%32); sfd = socket(PF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket"); return 1; } memset(&a, 0, sizeof(a)); a.sin_family = AF_INET; a.sin_port = htons(port); a.sin_addr.s_addr = inet_addr("127.0.0.1"); if(bind(sfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("bind"); return 1; } if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) { perror("fcntl"); return 1; } cfd = socket(PF_INET, SOCK_DGRAM, 0); if(cfd == -1) { perror("client socket"); return 1; } a.sin_port = 0; if(bind(cfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("client bind"); return 1; } a.sin_port = htons(port); /* no handler, causes exit in 10 seconds */ alarm(10); /* send and receive on the socket */ if((p=fork()) == 0) { for(i=0; i&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "#define NONBLOCKING_IS_BROKEN 1" >>confdefs.h ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mkdir has one arg" >&5 printf %s "checking whether mkdir has one arg... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif int main (void) { (void)mkdir("directory"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define MKDIR_HAS_ONE_ARG 1" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." else CPPFLAGS="-I." fi if test "$srcdir" != "."; then CPPFLAGS="$CPPFLAGS -I$srcdir" if test -f $srcdir/config.h; then as_fn_error $? "$srcdir/config.h is in the way, please remove it" "$LINENO" 5 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else case e in #( e) # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else case e in #( e) # Broken: fails on valid input. continue ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else case e in #( e) # Passes both tests. ac_preproc_ok=: break ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP ;; esac fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else case e in #( e) # Broken: fails on valid input. continue ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else case e in #( e) # Passes both tests. ac_preproc_ok=: break ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See 'config.log' for more details" "$LINENO" 5; } ;; esac fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5 printf %s "checking for egrep -e... " >&6; } if test ${ac_cv_path_EGREP_TRADITIONAL+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$EGREP_TRADITIONAL"; then ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue # Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. # Check for GNU $ac_path_EGREP_TRADITIONAL case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; #( *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" "$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then : fi else ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi if test "$ac_cv_path_EGREP_TRADITIONAL" then : ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E" else case e in #( e) if test -z "$EGREP_TRADITIONAL"; then ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue # Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. # Check for GNU $ac_path_EGREP_TRADITIONAL case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; #( *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" "$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5 printf "%s\n" "$ac_cv_path_EGREP_TRADITIONAL" >&6; } EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int8_t" >&5 printf %s "checking for int8_t... " >&6; } if test ${ac_cv_type_int8_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_int8_t=yes else case e in #( e) ac_cv_type_int8_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int8_t" >&5 printf "%s\n" "$ac_cv_type_int8_t" >&6; } if test $ac_cv_type_int8_t = no; then printf "%s\n" "#define int8_t char" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int16_t" >&5 printf %s "checking for int16_t... " >&6; } if test ${ac_cv_type_int16_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_int16_t=yes else case e in #( e) ac_cv_type_int16_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int16_t" >&5 printf "%s\n" "$ac_cv_type_int16_t" >&6; } if test $ac_cv_type_int16_t = no; then printf "%s\n" "#define int16_t short" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int32_t" >&5 printf %s "checking for int32_t... " >&6; } if test ${ac_cv_type_int32_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_int32_t=yes else case e in #( e) ac_cv_type_int32_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int32_t" >&5 printf "%s\n" "$ac_cv_type_int32_t" >&6; } if test $ac_cv_type_int32_t = no; then printf "%s\n" "#define int32_t int" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int64_t" >&5 printf %s "checking for int64_t... " >&6; } if test ${ac_cv_type_int64_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])int64_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_int64_t=yes else case e in #( e) ac_cv_type_int64_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int64_t" >&5 printf "%s\n" "$ac_cv_type_int64_t" >&6; } if test $ac_cv_type_int64_t = no; then printf "%s\n" "#define int64_t long long" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5 printf %s "checking for uint8_t... " >&6; } if test ${ac_cv_type_uint8_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])uint8_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_uint8_t=yes else case e in #( e) ac_cv_type_uint8_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint8_t" >&5 printf "%s\n" "$ac_cv_type_uint8_t" >&6; } if test $ac_cv_type_uint8_t = no; then printf "%s\n" "#define uint8_t unsigned char" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5 printf %s "checking for uint16_t... " >&6; } if test ${ac_cv_type_uint16_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])uint16_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_uint16_t=yes else case e in #( e) ac_cv_type_uint16_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5 printf "%s\n" "$ac_cv_type_uint16_t" >&6; } if test $ac_cv_type_uint16_t = no; then printf "%s\n" "#define uint16_t unsigned short" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5 printf %s "checking for uint32_t... " >&6; } if test ${ac_cv_type_uint32_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_uint32_t=yes else case e in #( e) ac_cv_type_uint32_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5 printf "%s\n" "$ac_cv_type_uint32_t" >&6; } if test $ac_cv_type_uint32_t = no; then printf "%s\n" "#define uint32_t unsigned int" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5 printf %s "checking for uint64_t... " >&6; } if test ${ac_cv_type_uint64_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])uint64_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_uint64_t=yes else case e in #( e) ac_cv_type_uint64_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5 printf "%s\n" "$ac_cv_type_uint64_t" >&6; } if test $ac_cv_type_uint64_t = no; then printf "%s\n" "#define uint64_t unsigned long long" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 printf %s "checking for socklen_t... " >&6; } if test ${ac_cv_type_socklen_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])socklen_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_socklen_t=yes else case e in #( e) ac_cv_type_socklen_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5 printf "%s\n" "$ac_cv_type_socklen_t" >&6; } if test $ac_cv_type_socklen_t = no; then printf "%s\n" "#define socklen_t int" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sig_atomic_t" >&5 printf %s "checking for sig_atomic_t... " >&6; } if test ${ac_cv_type_sig_atomic_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])sig_atomic_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_sig_atomic_t=yes else case e in #( e) ac_cv_type_sig_atomic_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_sig_atomic_t" >&5 printf "%s\n" "$ac_cv_type_sig_atomic_t" >&6; } if test $ac_cv_type_sig_atomic_t = no; then printf "%s\n" "#define sig_atomic_t int" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5 printf %s "checking for ssize_t... " >&6; } if test ${ac_cv_type_ssize_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_ssize_t=yes else case e in #( e) ac_cv_type_ssize_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_ssize_t" >&5 printf "%s\n" "$ac_cv_type_ssize_t" >&6; } if test $ac_cv_type_ssize_t = no; then printf "%s\n" "#define ssize_t int" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suseconds_t" >&5 printf %s "checking for suseconds_t... " >&6; } if test ${ac_cv_type_suseconds_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])suseconds_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_suseconds_t=yes else case e in #( e) ac_cv_type_suseconds_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_suseconds_t" >&5 printf "%s\n" "$ac_cv_type_suseconds_t" >&6; } if test $ac_cv_type_suseconds_t = no; then printf "%s\n" "#define suseconds_t time_t" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" " #if HAVE_SYS_TYPES_H # include #endif #if HAVE_NETINET_IN_H # include #endif " if test "x$ac_cv_type_in_addr_t" = xyes then : else case e in #( e) printf "%s\n" "#define in_addr_t uint32_t" >>confdefs.h ;; esac fi ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "ss_family" "ac_cv_member_struct_sockaddr_storage_ss_family" "$ac_includes_default #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_storage_ss_family" = xyes then : else case e in #( e) ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "__ss_family" "ac_cv_member_struct_sockaddr_storage___ss_family" "$ac_includes_default #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_storage___ss_family" = xyes then : printf "%s\n" "#define ss_family __ss_family" >>confdefs.h fi ;; esac fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" " $ac_includes_default #ifdef HAVE_SYS_UN_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1" >>confdefs.h fi # Checks for library functions. # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 printf %s "checking for working chown... " >&6; } if test ${ac_cv_func_chown_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. *-gnu*) ac_cv_func_chown_works=yes ;; # If we don't know, assume the worst. *) ac_cv_func_chown_works=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main (void) { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_chown_works=yes else case e in #( e) ac_cv_func_chown_works=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f conftest.chown ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 printf "%s\n" "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h fi ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done if test "x$ac_cv_func_fork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 printf %s "checking for working fork... " >&6; } if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* By R. Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes else case e in #( e) ac_cv_func_fork_works=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 printf %s "checking for working vfork... " >&6; } if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #include #ifdef HAVE_VFORK_H # include #endif static void do_nothing (int sig) { (void) sig; } /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void sparc_address_test (int arg) { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main (void) { pid_t parent = getpid (); pid_t child; sparc_address_test (0); /* On Solaris 2.4, changes by the child to the signal handler also munge signal handlers in the parent. To detect this, start by putting the parent's handler in a known state. */ signal (SIGTERM, SIG_DFL); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* Alter the child's signal handler. */ if (signal (SIGTERM, do_nothing) != SIG_DFL) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child munge the parent's signal handler? */ || signal (SIGTERM, SIG_DFL) != SIG_DFL /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes else case e in #( e) ac_cv_func_vfork_works=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_VFORK 1" >>confdefs.h else printf "%s\n" "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 printf %s "checking for GNU libc compatible malloc... " >&6; } if test ${ac_cv_func_malloc_0_nonnull+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ | hpux* | solaris* | cygwin* | mingw* | windows* | msys* ) ac_cv_func_malloc_0_nonnull=yes ;; # If we don't know, assume the worst. *) ac_cv_func_malloc_0_nonnull=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { void *p = malloc (0); int result = !p; free (p); return result; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_malloc_0_nonnull=yes else case e in #( e) ac_cv_func_malloc_0_nonnull=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes then : printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h else case e in #( e) printf "%s\n" "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac printf "%s\n" "#define malloc rpl_malloc" >>confdefs.h ;; esac fi printf "%s\n" "#define RETSIGTYPE void" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for declarations of fseeko and ftello" >&5 printf %s "checking for declarations of fseeko and ftello... " >&6; } if test ${ac_cv_func_fseeko_ftello+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __hpux && !defined _LARGEFILE_SOURCE # include # if LONG_MAX >> 31 == 0 # error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" # endif #endif #include /* for off_t */ #include int main (void) { int (*fp1) (FILE *, off_t, int) = fseeko; off_t (*fp2) (FILE *) = ftello; return fseeko (stdin, 0, 0) && fp1 (stdin, 0, 0) && ftello (stdin) >= 0 && fp2 (stdin) >= 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_fseeko_ftello=yes else case e in #( e) ac_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE=1" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __hpux && !defined _LARGEFILE_SOURCE # include # if LONG_MAX >> 31 == 0 # error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" # endif #endif #include /* for off_t */ #include int main (void) { int (*fp1) (FILE *, off_t, int) = fseeko; off_t (*fp2) (FILE *) = ftello; return fseeko (stdin, 0, 0) && fp1 (stdin, 0, 0) && ftello (stdin) >= 0 && fp2 (stdin) >= 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_fseeko_ftello="need _LARGEFILE_SOURCE" else case e in #( e) ac_cv_func_fseeko_ftello=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fseeko_ftello" >&5 printf "%s\n" "$ac_cv_func_fseeko_ftello" >&6; } if test "$ac_cv_func_fseeko_ftello" != no then : printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h fi if test "$ac_cv_func_fseeko_ftello" = "need _LARGEFILE_SOURCE" then : printf "%s\n" "#define _LARGEFILE_SOURCE 1" >>confdefs.h fi # Check whether --enable-largefile was given. if test ${enable_largefile+y} then : enableval=$enable_largefile; fi if test "$enable_largefile,$enable_year2038" != no,no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable large file support" >&5 printf %s "checking for $CC option to enable large file support... " >&6; } if test ${ac_cv_sys_largefile_opts+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CC="$CC" ac_opt_found=no for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1" "-n32"; do if test x"$ac_opt" != x"none needed" then : CC="$ac_save_CC $ac_opt" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef FTYPE # define FTYPE off_t #endif /* Check that FTYPE can represent 2**63 - 1 correctly. We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_opt" = x"none needed" then : # GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t. CC="$CC -DFTYPE=ino_t" if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) CC="$CC -D_FILE_OFFSET_BITS=64" if ac_fn_c_try_compile "$LINENO" then : ac_opt='-D_FILE_OFFSET_BITS=64' fi rm -f core conftest.err conftest.$ac_objext conftest.beam ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam fi ac_cv_sys_largefile_opts=$ac_opt ac_opt_found=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test $ac_opt_found = no || break done CC="$ac_save_CC" test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_opts" >&5 printf "%s\n" "$ac_cv_sys_largefile_opts" >&6; } ac_have_largefile=yes case $ac_cv_sys_largefile_opts in #( "none needed") : ;; #( "supported through gnulib") : ;; #( "support not detected") : ac_have_largefile=no ;; #( "-D_FILE_OFFSET_BITS=64") : printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h ;; #( "-D_LARGE_FILES=1") : printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h ;; #( "-n32") : CC="$CC -n32" ;; #( *) : as_fn_error $? "internal error: bad value for \$ac_cv_sys_largefile_opts" "$LINENO" 5 ;; esac if test "$enable_year2038" != no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option for timestamps after 2038" >&5 printf %s "checking for $CC option for timestamps after 2038... " >&6; } if test ${ac_cv_sys_year2038_opts+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CPPFLAGS="$CPPFLAGS" ac_opt_found=no for ac_opt in "none needed" "-D_TIME_BITS=64" "-D__MINGW_USE_VC2005_COMPAT" "-U_USE_32_BIT_TIME_T -D__MINGW_USE_VC2005_COMPAT"; do if test x"$ac_opt" != x"none needed" then : CPPFLAGS="$ac_save_CPPFLAGS $ac_opt" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that time_t can represent 2**32 - 1 correctly. */ #define LARGE_TIME_T \\ ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30))) int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535 && LARGE_TIME_T % 65537 == 0) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_year2038_opts="$ac_opt" ac_opt_found=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test $ac_opt_found = no || break done CPPFLAGS="$ac_save_CPPFLAGS" test $ac_opt_found = yes || ac_cv_sys_year2038_opts="support not detected" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_year2038_opts" >&5 printf "%s\n" "$ac_cv_sys_year2038_opts" >&6; } ac_have_year2038=yes case $ac_cv_sys_year2038_opts in #( "none needed") : ;; #( "support not detected") : ac_have_year2038=no ;; #( "-D_TIME_BITS=64") : printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h ;; #( "-D__MINGW_USE_VC2005_COMPAT") : printf "%s\n" "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h ;; #( "-U_USE_32_BIT_TIME_T"*) : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "the 'time_t' type is currently forced to be 32-bit. It will stop working after mid-January 2038. Remove _USE_32BIT_TIME_T from the compiler flags. See 'config.log' for more details" "$LINENO" 5; } ;; #( *) : as_fn_error $? "internal error: bad value for \$ac_cv_sys_year2038_opts" "$LINENO" 5 ;; esac fi fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void*" >&5 printf %s "checking size of void*... " >&6; } if test ${ac_cv_sizeof_voidp+y} then : printf %s "(cached) " >&6 else case e in #( e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void*))" "ac_cv_sizeof_voidp" "$ac_includes_default" then : else case e in #( e) if test "$ac_cv_type_voidp" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void*) See 'config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_voidp=0 fi ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_voidp" >&5 printf "%s\n" "$ac_cv_sizeof_voidp" >&6; } printf "%s\n" "#define SIZEOF_VOIDP $ac_cv_sizeof_voidp" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 printf %s "checking size of off_t... " >&6; } if test ${ac_cv_sizeof_off_t+y} then : printf %s "(cached) " >&6 else case e in #( e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default" then : else case e in #( e) if test "$ac_cv_type_off_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See 'config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } printf "%s\n" "#define SIZEOF_OFF_T $ac_cv_sizeof_off_t" >>confdefs.h ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" if test "x$ac_cv_func_getrandom" = xyes then : printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random" if test "x$ac_cv_func_arc4random" = xyes then : printf "%s\n" "#define HAVE_ARC4RANDOM 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "arc4random_uniform" "ac_cv_func_arc4random_uniform" if test "x$ac_cv_func_arc4random_uniform" = xyes then : printf "%s\n" "#define HAVE_ARC4RANDOM_UNIFORM 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing setusercontext" >&5 printf %s "checking for library containing setusercontext... " >&6; } if test ${ac_cv_search_setusercontext+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char setusercontext (void); int main (void) { return setusercontext (); ; return 0; } _ACEOF for ac_lib in '' util do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_setusercontext=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_setusercontext+y} then : break fi done if test ${ac_cv_search_setusercontext+y} then : else case e in #( e) ac_cv_search_setusercontext=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_setusercontext" >&5 printf "%s\n" "$ac_cv_search_setusercontext" >&6; } ac_res=$ac_cv_search_setusercontext if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ac_fn_c_check_header_compile "$LINENO" "login_cap.h" "ac_cv_header_login_cap_h" "$ac_includes_default " if test "x$ac_cv_header_login_cap_h" = xyes then : printf "%s\n" "#define HAVE_LOGIN_CAP_H 1" >>confdefs.h fi fi ac_fn_c_check_func "$LINENO" "tzset" "ac_cv_func_tzset" if test "x$ac_cv_func_tzset" = xyes then : printf "%s\n" "#define HAVE_TZSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "alarm" "ac_cv_func_alarm" if test "x$ac_cv_func_alarm" = xyes then : printf "%s\n" "#define HAVE_ALARM 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "chroot" "ac_cv_func_chroot" if test "x$ac_cv_func_chroot" = xyes then : printf "%s\n" "#define HAVE_CHROOT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" if test "x$ac_cv_func_dup2" = xyes then : printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "endpwent" "ac_cv_func_endpwent" if test "x$ac_cv_func_endpwent" = xyes then : printf "%s\n" "#define HAVE_ENDPWENT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname" if test "x$ac_cv_func_gethostname" = xyes then : printf "%s\n" "#define HAVE_GETHOSTNAME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" if test "x$ac_cv_func_memset" = xyes then : printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memcpy" "ac_cv_func_memcpy" if test "x$ac_cv_func_memcpy" = xyes then : printf "%s\n" "#define HAVE_MEMCPY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" if test "x$ac_cv_func_pwrite" = xyes then : printf "%s\n" "#define HAVE_PWRITE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = xyes then : printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = xyes then : printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strchr" "ac_cv_func_strchr" if test "x$ac_cv_func_strchr" = xyes then : printf "%s\n" "#define HAVE_STRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" if test "x$ac_cv_func_strdup" = xyes then : printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes then : printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp" if test "x$ac_cv_func_strncasecmp" = xyes then : printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtol" "ac_cv_func_strtol" if test "x$ac_cv_func_strtol" = xyes then : printf "%s\n" "#define HAVE_STRTOL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "writev" "ac_cv_func_writev" if test "x$ac_cv_func_writev" = xyes then : printf "%s\n" "#define HAVE_WRITEV 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" if test "x$ac_cv_func_getaddrinfo" = xyes then : printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" if test "x$ac_cv_func_getnameinfo" = xyes then : printf "%s\n" "#define HAVE_GETNAMEINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "freeaddrinfo" "ac_cv_func_freeaddrinfo" if test "x$ac_cv_func_freeaddrinfo" = xyes then : printf "%s\n" "#define HAVE_FREEADDRINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gai_strerror" "ac_cv_func_gai_strerror" if test "x$ac_cv_func_gai_strerror" = xyes then : printf "%s\n" "#define HAVE_GAI_STRERROR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction" if test "x$ac_cv_func_sigaction" = xyes then : printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sigprocmask" "ac_cv_func_sigprocmask" if test "x$ac_cv_func_sigprocmask" = xyes then : printf "%s\n" "#define HAVE_SIGPROCMASK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strptime" "ac_cv_func_strptime" if test "x$ac_cv_func_strptime" = xyes then : printf "%s\n" "#define HAVE_STRPTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" if test "x$ac_cv_func_strftime" = xyes then : printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" if test "x$ac_cv_func_localtime_r" = xyes then : printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setusercontext" "ac_cv_func_setusercontext" if test "x$ac_cv_func_setusercontext" = xyes then : printf "%s\n" "#define HAVE_SETUSERCONTEXT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "glob" "ac_cv_func_glob" if test "x$ac_cv_func_glob" = xyes then : printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups" if test "x$ac_cv_func_initgroups" = xyes then : printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid" if test "x$ac_cv_func_setresuid" = xyes then : printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid" if test "x$ac_cv_func_setreuid" = xyes then : printf "%s\n" "#define HAVE_SETREUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresgid" "ac_cv_func_setresgid" if test "x$ac_cv_func_setresgid" = xyes then : printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setregid" "ac_cv_func_setregid" if test "x$ac_cv_func_setregid" = xyes then : printf "%s\n" "#define HAVE_SETREGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getpwnam" "ac_cv_func_getpwnam" if test "x$ac_cv_func_getpwnam" = xyes then : printf "%s\n" "#define HAVE_GETPWNAM 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" if test "x$ac_cv_func_mmap" = xyes then : printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll" if test "x$ac_cv_func_ppoll" = xyes then : printf "%s\n" "#define HAVE_PPOLL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "accept4" "ac_cv_func_accept4" if test "x$ac_cv_func_accept4" = xyes then : printf "%s\n" "#define HAVE_ACCEPT4 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" if test "x$ac_cv_func_getifaddrs" = xyes then : printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "struct mmsghdr" "ac_cv_type_struct_mmsghdr" " $ac_includes_default #include " if test "x$ac_cv_type_struct_mmsghdr" = xyes then : printf "%s\n" "#define HAVE_MMSGHDR 1" >>confdefs.h fi # Check whether --enable-recvmmsg was given. if test ${enable_recvmmsg+y} then : enableval=$enable_recvmmsg; fi case "$enable_recvmmsg" in yes) ac_fn_c_check_func "$LINENO" "recvmmsg" "ac_cv_func_recvmmsg" if test "x$ac_cv_func_recvmmsg" = xyes then : if test "$cross_compiling" = yes then : printf "%s\n" "#define HAVE_RECVMMSG 1" >>confdefs.h else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_UNISTD_H #include #endif #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = recvmmsg(s, 0, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } _ACEOF if ac_fn_c_try_run "$LINENO" then : printf "%s\n" "#define HAVE_RECVMMSG 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi fi ac_fn_c_check_func "$LINENO" "sendmmsg" "ac_cv_func_sendmmsg" if test "x$ac_cv_func_sendmmsg" = xyes then : if test "$cross_compiling" = yes then : printf "%s\n" "#define HAVE_SENDMMSG 1" >>confdefs.h else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_UNISTD_H #include #endif #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = sendmmsg(s, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } _ACEOF if ac_fn_c_try_run "$LINENO" then : printf "%s\n" "#define HAVE_SENDMMSG 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi fi ;; no|*) ;; esac # check if setreuid en setregid fail, on MacOSX10.4(darwin8). if echo $target_os | $GREP -i darwin8 > /dev/null; then printf "%s\n" "#define DARWIN_BROKEN_SETREUID 1" >>confdefs.h fi # GNU HURD needs _GNU_SOURCE defined for cpu affinity gear if echo $target_os | $EGREP -i 'linux|hurd' > /dev/null; then printf "%s\n" "#define _GNU_SOURCE, 1, Define this if on Linux or GNU Hurd for cpu affinity interface 1" >>confdefs.h fi # see comment on _GNU_SOURCE above ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default " if test "x$ac_cv_header_sched_h" = xyes then : printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/cpuset.h" "ac_cv_header_sys_cpuset_h" "$ac_includes_default " if test "x$ac_cv_header_sys_cpuset_h" = xyes then : printf "%s\n" "#define HAVE_SYS_CPUSET_H 1" >>confdefs.h fi # Check for cpu_set_t (Linux) and cpuset_t (FreeBSD and NetBSD) ac_fn_c_check_type "$LINENO" "cpu_set_t" "ac_cv_type_cpu_set_t" " $ac_includes_default #if HAVE_SCHED_H # include #endif #if HAVE_SYS_CPUSET_H # include #endif " if test "x$ac_cv_type_cpu_set_t" = xyes then : printf "%s\n" "#define HAVE_CPU_SET_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "cpuset_t" "ac_cv_type_cpuset_t" " $ac_includes_default #if HAVE_SCHED_H # include #endif #if HAVE_SYS_CPUSET_H # include #endif " if test "x$ac_cv_type_cpuset_t" = xyes then : printf "%s\n" "#define HAVE_CPUSET_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "cpuid_t" "ac_cv_type_cpuid_t" " $ac_includes_default #if HAVE_SCHED_H # include #endif #if HAVE_SYS_CPUSET_H # include #endif " if test "x$ac_cv_type_cpuid_t" = xyes then : printf "%s\n" "#define HAVE_CPUID_T 1" >>confdefs.h fi if test x"$ac_cv_type_cpuset_t" = xyes -o x"$ac_cv_type_cpu_set_t" = xyes then : ac_fn_c_check_func "$LINENO" "cpuset_create" "ac_cv_func_cpuset_create" if test "x$ac_cv_func_cpuset_create" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_destroy" "ac_cv_func_cpuset_destroy" if test "x$ac_cv_func_cpuset_destroy" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_zero" "ac_cv_func_cpuset_zero" if test "x$ac_cv_func_cpuset_zero" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_set" "ac_cv_func_cpuset_set" if test "x$ac_cv_func_cpuset_set" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_clr" "ac_cv_func_cpuset_clr" if test "x$ac_cv_func_cpuset_clr" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_isset" "ac_cv_func_cpuset_isset" if test "x$ac_cv_func_cpuset_isset" = xyes then : fi ac_fn_c_check_func "$LINENO" "cpuset_size" "ac_cv_func_cpuset_size" if test "x$ac_cv_func_cpuset_size" = xyes then : fi case " $LIBOBJS " in *" cpuset.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS cpuset.$ac_objext" ;; esac ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CPU_OR works with three arguments" >&5 printf %s "checking whether CPU_OR works with three arguments... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SYS_CPUSET_H # include #endif #include #ifdef HAVE_CPUSET_T #define MY_CPUSET_TYPE cpuset_t #endif #ifdef HAVE_CPU_SET_T #define MY_CPUSET_TYPE cpu_set_t #endif void testing (void) { MY_CPUSET_TYPE a, b; memset(&a, 0, sizeof(a)); memset(&b, 0, sizeof(b)); CPU_OR(&a, &a, &b); } int main (void) { testing(); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define CPU_OR_THREE_ARGS 1" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi # # sched_setaffinity must be checked using proper includes. # also needs _GNU_SOURCE on Linux and Hurd; see above. # also see https://github.com/NLnetLabs/nsd/issues/82. # { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_setaffinity" >&5 printf %s "checking for sched_setaffinity... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SYS_CPUSET_H #include #endif #ifdef HAVE_CPUSET_T #define MY_CPUSET_TYPE cpuset_t #endif #ifdef HAVE_CPU_SET_T #define MY_CPUSET_TYPE cpu_set_t #endif void testing (void) { MY_CPUSET_TYPE set; CPU_ZERO(&set); (void)sched_setaffinity(-1, sizeof(set), &set); } int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # # Checking for missing functions we can replace # ac_fn_c_check_func "$LINENO" "basename" "ac_cv_func_basename" if test "x$ac_cv_func_basename" = xyes then : printf "%s\n" "#define HAVE_BASENAME 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" basename.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS basename.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton" if test "x$ac_cv_func_inet_aton" = xyes then : printf "%s\n" "#define HAVE_INET_ATON 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" inet_aton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_aton.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton" if test "x$ac_cv_func_inet_pton" = xyes then : printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" inet_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" if test "x$ac_cv_func_inet_ntop" = xyes then : printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" inet_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_ntop.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" snprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS snprintf.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes then : printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strptime" "ac_cv_func_strptime" if test "x$ac_cv_func_strptime" = xyes then : printf "%s\n" "#define HAVE_STRPTIME 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strptime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strptime.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "b64_pton" "ac_cv_func_b64_pton" if test "x$ac_cv_func_b64_pton" = xyes then : printf "%s\n" "#define HAVE_B64_PTON 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" b64_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS b64_pton.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "b64_ntop" "ac_cv_func_b64_ntop" if test "x$ac_cv_func_b64_ntop" = xyes then : printf "%s\n" "#define HAVE_B64_NTOP 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" b64_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS b64_ntop.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect" if test "x$ac_cv_func_pselect" = xyes then : printf "%s\n" "#define HAVE_PSELECT 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" pselect.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS pselect.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" if test "x$ac_cv_func_memmove" = xyes then : printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" memmove.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memmove.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" if test "x$ac_cv_func_setproctitle" = xyes then : printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" setproctitle.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS setproctitle.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes then : printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" explicit_bzero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS explicit_bzero.$ac_objext" ;; esac ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for reallocarray" >&5 printf %s "checking for reallocarray... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef _OPENBSD_SOURCE #define _OPENBSD_SOURCE 1 #endif $ac_includes_default #include int main(void) { void* p = reallocarray(NULL, 10, 100); free(p); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h ac_fn_check_decl "$LINENO" "reallocarray" "ac_cv_have_decl_reallocarray" " $ac_includes_default #include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_reallocarray" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_REALLOCARRAY $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : else case e in #( e) printf "%s\n" "#define REALLOCARRAY_NEEDS_DEFINES 1" >>confdefs.h ;; esac fi else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pselect prototype in sys/select.h" >&5 printf %s "checking for pselect prototype in sys/select.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "[^a-zA-Z_]*pselect[^a-zA-Z_]" >/dev/null 2>&1 then : printf "%s\n" "#define HAVE_PSELECT_PROTO 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -rf conftest* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ctime_r prototype in time.h" >&5 printf %s "checking for ctime_r prototype in time.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "[^a-zA-Z_]*ctime_r[^a-zA-Z_]" >/dev/null 2>&1 then : printf "%s\n" "#define HAVE_CTIME_R_PROTO 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -rf conftest* ac_fn_c_check_type "$LINENO" "struct timespec" "ac_cv_type_struct_timespec" " $ac_includes_default #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_TIME_H #include #endif " if test "x$ac_cv_type_struct_timespec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h fi printf "%s\n" "#define IDENTITY \"unidentified server\"" >>confdefs.h printf "%s\n" "#define VERSION PACKAGE_STRING" >>confdefs.h printf "%s\n" "#define TCP_BACKLOG 256" >>confdefs.h printf "%s\n" "#define TCP_PORT \"53\"" >>confdefs.h printf "%s\n" "#define TCP_MAX_MESSAGE_LEN 65535" >>confdefs.h printf "%s\n" "#define UDP_PORT \"53\"" >>confdefs.h printf "%s\n" "#define UDP_MAX_MESSAGE_LEN 512" >>confdefs.h printf "%s\n" "#define EDNS_MAX_MESSAGE_LEN 1232" >>confdefs.h printf "%s\n" "#define TLS_PORT \"853\"" >>confdefs.h printf "%s\n" "#define MAXSYSLOGMSGLEN 512" >>confdefs.h printf "%s\n" "#define NSD_CONTROL_PORT 8952" >>confdefs.h printf "%s\n" "#define NSD_CONTROL_VERSION 1" >>confdefs.h printf "%s\n" "#define VERIFY_PORT \"5347\"" >>confdefs.h facility=LOG_DAEMON # Check whether --with-facility was given. if test ${with_facility+y} then : withval=$with_facility; facility=$withval fi printf "%s\n" "#define FACILITY $facility" >>confdefs.h tcp_timeout=120 # Check whether --with-tcp_timeout was given. if test ${with_tcp_timeout+y} then : withval=$with_tcp_timeout; tcp_timeout=$withval fi printf "%s\n" "#define TCP_TIMEOUT $tcp_timeout" >>confdefs.h # Check whether --enable-root-server was given. if test ${enable_root_server+y} then : enableval=$enable_root_server; fi # Check whether --enable-ipv6 was given. if test ${enable_ipv6+y} then : enableval=$enable_ipv6; fi case "$enable_ipv6" in no) ;; yes|*) printf "%s\n" "#define INET6 /**/" >>confdefs.h ;; esac # Check whether --enable-bind8-stats was given. if test ${enable_bind8_stats+y} then : enableval=$enable_bind8_stats; fi case "$enable_bind8_stats" in yes|'') printf "%s\n" "#define BIND8_STATS /**/" >>confdefs.h ;; no|*) ;; esac # Check whether --enable-zone-stats was given. if test ${enable_zone_stats+y} then : enableval=$enable_zone_stats; fi case "$enable_zone_stats" in yes) printf "%s\n" "#define USE_ZONE_STATS /**/" >>confdefs.h printf "%s\n" "#define BIND8_STATS /**/" >>confdefs.h ;; no|''|*) ;; esac # Check whether --enable-checking was given. if test ${enable_checking+y} then : enableval=$enable_checking; fi case "$enable_checking" in yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -W" >&5 printf %s "checking whether $CC supports -W... " >&6; } cache=`echo W | $SED 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC -W -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -W" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wall" >&5 printf %s "checking whether $CC supports -Wall... " >&6; } cache=`echo Wall | $SED 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC -Wall -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -Wall" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wextra" >&5 printf %s "checking whether $CC supports -Wextra... " >&6; } cache=`echo Wextra | $SED 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC -Wextra -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -Wextra" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 printf %s "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } cache=`echo Wdeclaration-after-statement | $SED 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC -Wdeclaration-after-statement -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -Wdeclaration-after-statement" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi ;; no|*) printf "%s\n" "#define NDEBUG /**/" >>confdefs.h ;; esac # Check whether --enable-log-role was given. if test ${enable_log_role+y} then : enableval=$enable_log_role; fi case "$enable_log_role" in yes) printf "%s\n" "#define USE_LOG_PROCESS_ROLE /**/" >>confdefs.h ;; no|*) ;; esac # Check whether --enable-memclean was given. if test ${enable_memclean+y} then : enableval=$enable_memclean; fi if test "$enable_memclean" = "yes"; then printf "%s\n" "#define MEMCLEAN 1" >>confdefs.h fi # Check whether --enable-ratelimit was given. if test ${enable_ratelimit+y} then : enableval=$enable_ratelimit; fi case "$enable_ratelimit" in yes) printf "%s\n" "#define RATELIMIT /**/" >>confdefs.h ratelimit="xx" ;; no|*) ratelimit="" ;; esac # Check whether --enable-ratelimit-default-is-off was given. if test ${enable_ratelimit_default_is_off+y} then : enableval=$enable_ratelimit_default_is_off; fi case "$enable_ratelimit_default_is_off" in yes) printf "%s\n" "#define RATELIMIT_DEFAULT_OFF /**/" >>confdefs.h ratelimit_default="off" ;; no|*) ratelimit_default="on" ;; esac # we need SSL for TSIG (and maybe also for NSEC3). # Check whether --with-ssl was given. if test ${with_ssl+y} then : withval=$with_ssl; else case e in #( e) withval="yes" ;; esac fi if test x_$withval != x_no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL" >&5 printf %s "checking for SSL... " >&6; } if test -n "$withval"; then if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then ssldir="$withval" found_ssl="yes" withval="" ssldir_include="$ssldir" CPPFLAGS="$CPPFLAGS -I$ssldir_include"; ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else as_fn_error $? "Could not find openssl lib file, $ssldir_lib/libssl.so,a, pass like \"/usr/local\" or \"/usr/include/openssl11\"" "$LINENO" 5 fi fi fi fi if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr /usr/local/opt/openssl" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes"; if test x_$ssldir != x_/usr; then CPPFLAGS="$CPPFLAGS -I$ssldir/include"; fi ssldir_include="$ssldir/include" if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then ssldir_lib="$ssldir/lib64" else ssldir_lib="$ssldir/lib" fi break; fi done if test x_$found_ssl != x_yes; then as_fn_error $? "Cannot find the SSL libraries in $withval" "$LINENO" 5 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found in $ssldir" >&5 printf "%s\n" "found in $ssldir" >&6; } HAVE_SSL=yes printf "%s\n" "#define HAVE_SSL /**/" >>confdefs.h if test x_$ssldir != x_/usr; then LDFLAGS="$LDFLAGS -L$ssldir_lib"; fi if test x_$ssldir = x_/usr/sfw; then LDFLAGS="$LDFLAGS -R$ssldir_lib"; fi fi fi if test x$HAVE_SSL = x"yes"; then # check if libssl needs libdl BAKLIBS="$LIBS" LIBS="-lssl $LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libssl needs libdl" >&5 printf %s "checking if libssl needs libdl... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char SSL_CTX_new (void); int main (void) { return SSL_CTX_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBS="$BAKLIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 printf %s "checking for library containing dlopen... " >&6; } if test ${ac_cv_search_dlopen+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char dlopen (void); int main (void) { return dlopen (); ; return 0; } _ACEOF for ac_lib in '' dl do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_dlopen+y} then : break fi done if test ${ac_cv_search_dlopen+y} then : else case e in #( e) ac_cv_search_dlopen=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 printf "%s\n" "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext # remove space after -ldl if there. LIBS=`echo "$LIBS" | sed -e 's/ $//'` # Check for -pthread BAKLIBS="$LIBS" LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int EVP_sha256(void); (void)EVP_sha256(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : else case e in #( e) BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pthread" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libcrypto needs -pthread" >&5 printf %s "checking if libcrypto needs -pthread... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char EVP_sha256 (void); int main (void) { return EVP_sha256 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } CFLAGS="$BAKCFLAGS" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$BAKLIBS" if test -n "$ssldir"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EVP_sha256 in -lcrypto" >&5 printf %s "checking for EVP_sha256 in -lcrypto... " >&6; } if test ${ac_cv_lib_crypto_EVP_sha256+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char EVP_sha256 (void); int main (void) { return EVP_sha256 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_crypto_EVP_sha256=yes else case e in #( e) ac_cv_lib_crypto_EVP_sha256=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_EVP_sha256" >&5 printf "%s\n" "$ac_cv_lib_crypto_EVP_sha256" >&6; } if test "x$ac_cv_lib_crypto_EVP_sha256" = xyes then : printf "%s\n" "#define HAVE_LIBCRYPTO 1" >>confdefs.h LIBS="-lcrypto $LIBS" else case e in #( e) as_fn_error $? "OpenSSL found in $ssldir, but version 0.9.7 or higher is required" "$LINENO" 5 ;; esac fi fi SSL_LIBS="-lssl" ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_ssl_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_SSL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/err.h" "ac_cv_header_openssl_err_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_err_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_ERR_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/rand.h" "ac_cv_header_openssl_rand_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_rand_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_RAND_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/ocsp.h" "ac_cv_header_openssl_ocsp_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_ocsp_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_OCSP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/core_names.h" "ac_cv_header_openssl_core_names_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_core_names_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_CORE_NAMES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/x509v3.h" "ac_cv_header_openssl_x509v3_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_x509v3_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_X509V3_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "HMAC_CTX_reset" "ac_cv_func_HMAC_CTX_reset" if test "x$ac_cv_func_HMAC_CTX_reset" = xyes then : printf "%s\n" "#define HAVE_HMAC_CTX_RESET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "HMAC_CTX_new" "ac_cv_func_HMAC_CTX_new" if test "x$ac_cv_func_HMAC_CTX_new" = xyes then : printf "%s\n" "#define HAVE_HMAC_CTX_NEW 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "EVP_cleanup" "ac_cv_func_EVP_cleanup" if test "x$ac_cv_func_EVP_cleanup" = xyes then : printf "%s\n" "#define HAVE_EVP_CLEANUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "ERR_load_crypto_strings" "ac_cv_func_ERR_load_crypto_strings" if test "x$ac_cv_func_ERR_load_crypto_strings" = xyes then : printf "%s\n" "#define HAVE_ERR_LOAD_CRYPTO_STRINGS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "OPENSSL_init_crypto" "ac_cv_func_OPENSSL_init_crypto" if test "x$ac_cv_func_OPENSSL_init_crypto" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_INIT_CRYPTO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "CRYPTO_memcmp" "ac_cv_func_CRYPTO_memcmp" if test "x$ac_cv_func_CRYPTO_memcmp" = xyes then : printf "%s\n" "#define HAVE_CRYPTO_MEMCMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "EC_KEY_new_by_curve_name" "ac_cv_func_EC_KEY_new_by_curve_name" if test "x$ac_cv_func_EC_KEY_new_by_curve_name" = xyes then : printf "%s\n" "#define HAVE_EC_KEY_NEW_BY_CURVE_NAME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "EVP_MAC_CTX_new" "ac_cv_func_EVP_MAC_CTX_new" if test "x$ac_cv_func_EVP_MAC_CTX_new" = xyes then : printf "%s\n" "#define HAVE_EVP_MAC_CTX_NEW 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "EVP_MAC_CTX_set_params" "ac_cv_func_EVP_MAC_CTX_set_params" if test "x$ac_cv_func_EVP_MAC_CTX_set_params" = xyes then : printf "%s\n" "#define HAVE_EVP_MAC_CTX_SET_PARAMS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "EVP_MAC_CTX_get_mac_size" "ac_cv_func_EVP_MAC_CTX_get_mac_size" if test "x$ac_cv_func_EVP_MAC_CTX_get_mac_size" = xyes then : printf "%s\n" "#define HAVE_EVP_MAC_CTX_GET_MAC_SIZE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "SHA1_Init" "ac_cv_func_SHA1_Init" if test "x$ac_cv_func_SHA1_Init" = xyes then : printf "%s\n" "#define HAVE_SHA1_INIT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "ASN1_STRING_get0_data" "ac_cv_func_ASN1_STRING_get0_data" if test "x$ac_cv_func_ASN1_STRING_get0_data" = xyes then : printf "%s\n" "#define HAVE_ASN1_STRING_GET0_DATA 1" >>confdefs.h fi if test "$ac_cv_func_SHA1_Init" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if SHA1_Init is deprecated" >&5 printf %s "checking if SHA1_Init is deprecated... " >&6; } cache=`echo SHA1_Init | sed 'y%.=/+-%___p_%'` if eval test \${cv_cc_deprecated_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo ' #include ' >conftest.c echo 'void f(void){ (void)SHA1_Init(NULL); }' >>conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then eval "cv_cc_deprecated_$cache=no" else eval "cv_cc_deprecated_$cache=yes" fi rm -f conftest conftest.o conftest.c ;; esac fi if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define DEPRECATED_SHA1_INIT 1" >>confdefs.h : else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi fi ac_fn_check_decl "$LINENO" "SSL_CTX_set_ecdh_auto" "ac_cv_have_decl_SSL_CTX_set_ecdh_auto" " $ac_includes_default #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_OPENSSL_CONF_H #include #endif #ifdef HAVE_OPENSSL_ENGINE_H #include #endif #include #include #ifdef HAVE_OPENSSL_X509V3_h #include #endif " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_SSL_CTX_set_ecdh_auto" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_SSL_CTX_SET_ECDH_AUTO $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "SSL_CTX_set_tmp_ecdh" "ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" " $ac_includes_default #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_OPENSSL_CONF_H #include #endif #ifdef HAVE_OPENSSL_ENGINE_H #include #endif #include #include #ifdef HAVE_OPENSSL_X509V3_h #include #endif " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_SSL_CTX_SET_TMP_ECDH $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "TLS1_3_VERSION" "ac_cv_have_decl_TLS1_3_VERSION" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TLS1_3_VERSION" = xyes then : printf "%s\n" "#define HAVE_TLS_1_3 1" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No TLS 1.3, therefore XFR-over-TLS is disabled" >&5 printf "%s\n" "$as_me: WARNING: No TLS 1.3, therefore XFR-over-TLS is disabled" >&2;} ;; esac fi BAKLIBS="$LIBS" LIBS="-lssl $LIBS" ac_fn_c_check_func "$LINENO" "OPENSSL_init_ssl" "ac_cv_func_OPENSSL_init_ssl" if test "x$ac_cv_func_OPENSSL_init_ssl" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_INIT_SSL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "SSL_get1_peer_certificate" "ac_cv_func_SSL_get1_peer_certificate" if test "x$ac_cv_func_SSL_get1_peer_certificate" = xyes then : printf "%s\n" "#define HAVE_SSL_GET1_PEER_CERTIFICATE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "SSL_CTX_set_security_level" "ac_cv_func_SSL_CTX_set_security_level" if test "x$ac_cv_func_SSL_CTX_set_security_level" = xyes then : printf "%s\n" "#define HAVE_SSL_CTX_SET_SECURITY_LEVEL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "ERR_load_SSL_strings" "ac_cv_func_ERR_load_SSL_strings" if test "x$ac_cv_func_ERR_load_SSL_strings" = xyes then : printf "%s\n" "#define HAVE_ERR_LOAD_SSL_STRINGS 1" >>confdefs.h fi if test "$ac_cv_func_ERR_load_SSL_strings" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ERR_load_SSL_strings is deprecated" >&5 printf %s "checking if ERR_load_SSL_strings is deprecated... " >&6; } cache=`echo ERR_load_SSL_strings | sed 'y%.=/+-%___p_%'` if eval test \${cv_cc_deprecated_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo ' #include ' >conftest.c echo 'void f(void){ (void)ERR_load_SSL_strings(); }' >>conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then eval "cv_cc_deprecated_$cache=no" else eval "cv_cc_deprecated_$cache=yes" fi rm -f conftest conftest.o conftest.c ;; esac fi if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define DEPRECATED_ERR_LOAD_SSL_STRINGS 1" >>confdefs.h : else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi fi LIBS="$BAKLIBS" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore TLS is disabled" >&5 printf "%s\n" "$as_me: WARNING: No SSL, therefore TLS is disabled" >&2;} fi # Check whether --enable-nsec3 was given. if test ${enable_nsec3+y} then : enableval=$enable_nsec3; fi case "$enable_nsec3" in no) ;; yes) printf "%s\n" "#define NSEC3 /**/" >>confdefs.h ;; *) if test x$HAVE_SSL = x"yes"; then printf "%s\n" "#define NSEC3 /**/" >>confdefs.h else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore NSEC3 is disabled" >&5 printf "%s\n" "$as_me: WARNING: No SSL, therefore NSEC3 is disabled" >&2;} fi ;; esac # Check whether --enable-minimal-responses was given. if test ${enable_minimal_responses+y} then : enableval=$enable_minimal_responses; fi case "$enable_minimal_responses" in no) ;; yes|*) printf "%s\n" "#define MINIMAL_RESPONSES /**/" >>confdefs.h ;; esac # Check whether --enable-mmap was given. if test ${enable_mmap+y} then : enableval=$enable_mmap; fi case "$enable_mmap" in yes) ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default " if test "x$ac_cv_header_sys_mman_h" = xyes then : printf "%s\n" "#define HAVE_SYS_MMAN_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uintptr_t" >&5 printf %s "checking for uintptr_t... " >&6; } if test ${ac_cv_type_uintptr_t+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP_TRADITIONAL "(^|[^a-zA-Z_0-9])uintptr_t[^a-zA-Z_0-9]" >/dev/null 2>&1 then : ac_cv_type_uintptr_t=yes else case e in #( e) ac_cv_type_uintptr_t=no ;; esac fi rm -rf conftest* ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uintptr_t" >&5 printf "%s\n" "$ac_cv_type_uintptr_t" >&6; } if test $ac_cv_type_uintptr_t = no; then printf "%s\n" "#define uintptr_t void*" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" if test "x$ac_cv_func_mmap" = xyes then : printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "munmap" "ac_cv_func_munmap" if test "x$ac_cv_func_munmap" = xyes then : printf "%s\n" "#define HAVE_MUNMAP 1" >>confdefs.h fi printf "%s\n" "#define USE_MMAP_ALLOC /**/" >>confdefs.h ;; no|*) ;; esac # Check whether --enable-radix-tree was given. if test ${enable_radix_tree+y} then : enableval=$enable_radix_tree; fi case "$enable_radix_tree" in no) ;; yes|*) printf "%s\n" "#define USE_RADIX_TREE /**/" >>confdefs.h ;; esac # Check whether --enable-packed was given. if test ${enable_packed+y} then : enableval=$enable_packed; fi case "$enable_packed" in yes) printf "%s\n" "#define PACKED_STRUCTS /**/" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-address-of-packed-member" >&5 printf %s "checking whether $CC supports -Wno-address-of-packed-member... " >&6; } cache=`echo Wno-address-of-packed-member | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 else case e in #( e) echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wno-address-of-packed-member -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c ;; esac fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : CFLAGS="$CFLAGS -Wno-address-of-packed-member" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } : fi ;; no|*) ;; esac # check for dnstap if requested # Check whether --enable-dnstap was given. if test ${enable_dnstap+y} then : enableval=$enable_dnstap; opt_dnstap=$enableval else case e in #( e) opt_dnstap=no ;; esac fi # Check whether --with-dnstap-socket-path was given. if test ${with_dnstap_socket_path+y} then : withval=$with_dnstap_socket_path; opt_dnstap_socket_path=$withval else case e in #( e) opt_dnstap_socket_path="${localstatedir}/run/nsd-dnstap.sock" ;; esac fi if test "x$opt_dnstap" != "xno"; then # Extract the first word of "protoc-c", so it can be a program name with args. set dummy protoc-c; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PROTOC_C+y} then : printf %s "(cached) " >&6 else case e in #( e) case $PROTOC_C in [\\/]* | ?:[\\/]*) ac_cv_path_PROTOC_C="$PROTOC_C" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PROTOC_C="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi PROTOC_C=$ac_cv_path_PROTOC_C if test -n "$PROTOC_C"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PROTOC_C" >&5 printf "%s\n" "$PROTOC_C" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$PROTOC_C"; then as_fn_error $? "The protoc-c program was not found. Please install protobuf-c!" "$LINENO" 5 fi # Check whether --with-protobuf-c was given. if test ${with_protobuf_c+y} then : withval=$with_protobuf_c; # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f $withval/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I$withval/include/google" else CFLAGS="$CFLAGS -I$withval/include" fi LDFLAGS="$LDFLAGS -L$withval/lib" else case e in #( e) # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f /usr/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/include/google" else if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/local/include/google" LDFLAGS="$LDFLAGS -L/usr/local/lib" fi fi ;; esac fi # Check whether --with-libfstrm was given. if test ${with_libfstrm+y} then : withval=$with_libfstrm; CFLAGS="$CFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing fstrm_iothr_init" >&5 printf %s "checking for library containing fstrm_iothr_init... " >&6; } if test ${ac_cv_search_fstrm_iothr_init+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char fstrm_iothr_init (void); int main (void) { return fstrm_iothr_init (); ; return 0; } _ACEOF for ac_lib in '' fstrm do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_fstrm_iothr_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_fstrm_iothr_init+y} then : break fi done if test ${ac_cv_search_fstrm_iothr_init+y} then : else case e in #( e) ac_cv_search_fstrm_iothr_init=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fstrm_iothr_init" >&5 printf "%s\n" "$ac_cv_search_fstrm_iothr_init" >&6; } ac_res=$ac_cv_search_fstrm_iothr_init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else case e in #( e) as_fn_error $? "The fstrm library was not found. Please install fstrm!" "$LINENO" 5 ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing protobuf_c_message_pack" >&5 printf %s "checking for library containing protobuf_c_message_pack... " >&6; } if test ${ac_cv_search_protobuf_c_message_pack+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char protobuf_c_message_pack (void); int main (void) { return protobuf_c_message_pack (); ; return 0; } _ACEOF for ac_lib in '' protobuf-c do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_protobuf_c_message_pack=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_protobuf_c_message_pack+y} then : break fi done if test ${ac_cv_search_protobuf_c_message_pack+y} then : else case e in #( e) ac_cv_search_protobuf_c_message_pack=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_protobuf_c_message_pack" >&5 printf "%s\n" "$ac_cv_search_protobuf_c_message_pack" >&6; } ac_res=$ac_cv_search_protobuf_c_message_pack if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else case e in #( e) as_fn_error $? "The protobuf-c library was not found. Please install protobuf-c!" "$LINENO" 5 ;; esac fi printf "%s\n" "#define USE_DNSTAP 1" >>confdefs.h ENABLE_DNSTAP=1 hdr_dnstap_socket_path="`echo $opt_dnstap_socket_path | sed -e 's/\\\\/\\\\\\\\/g'`" printf "%s\n" "#define DNSTAP_SOCKET_PATH \"$hdr_dnstap_socket_path\"" >>confdefs.h DNSTAP_SRC="dnstap/dnstap.c dnstap/dnstap.pb-c.c dnstap/dnstap_collector.c" DNSTAP_OBJ="dnstap.o dnstap_collector.o dnstap.pb-c.o" dnstap_config="dnstap/dnstap_config.h" else ENABLE_DNSTAP=0 fi # Include systemd.m4 - begin # macros for configuring systemd # Copyright 2015, Sami Kerola, CloudFlare. # BSD licensed. # Check whether --enable-systemd was given. if test ${enable_systemd+y} then : enableval=$enable_systemd; else case e in #( e) enable_systemd=no ;; esac fi have_systemd=no if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi if test -z "$PKG_CONFIG"; then as_fn_error $? "pkg-config not found" "$LINENO" 5 fi if test "x$enable_systemd" != xno then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsystemd" >&5 printf %s "checking for libsystemd... " >&6; } if test -n "$SYSTEMD_CFLAGS"; then pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SYSTEMD_LIBS"; then pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1` else SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SYSTEMD_PKG_ERRORS" >&5 have_systemd=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_systemd=no else SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_systemd=yes fi if test "x$have_systemd" != "xyes" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsystemd-daemon" >&5 printf %s "checking for libsystemd-daemon... " >&6; } if test -n "$SYSTEMD_DAEMON_CFLAGS"; then pkg_cv_SYSTEMD_DAEMON_CFLAGS="$SYSTEMD_DAEMON_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd-daemon\""; } >&5 ($PKG_CONFIG --exists --print-errors "libsystemd-daemon") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SYSTEMD_DAEMON_CFLAGS=`$PKG_CONFIG --cflags "libsystemd-daemon" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SYSTEMD_DAEMON_LIBS"; then pkg_cv_SYSTEMD_DAEMON_LIBS="$SYSTEMD_DAEMON_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd-daemon\""; } >&5 ($PKG_CONFIG --exists --print-errors "libsystemd-daemon") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SYSTEMD_DAEMON_LIBS=`$PKG_CONFIG --libs "libsystemd-daemon" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SYSTEMD_DAEMON_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd-daemon" 2>&1` else SYSTEMD_DAEMON_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd-daemon" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SYSTEMD_DAEMON_PKG_ERRORS" >&5 have_systemd_daemon=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_systemd_daemon=no else SYSTEMD_DAEMON_CFLAGS=$pkg_cv_SYSTEMD_DAEMON_CFLAGS SYSTEMD_DAEMON_LIBS=$pkg_cv_SYSTEMD_DAEMON_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_systemd_daemon=yes fi if test "x$have_systemd_daemon" = "xyes" then : have_systemd=yes fi fi case $enable_systemd:$have_systemd in #( yes:no) : as_fn_error $? "systemd enabled but libsystemd not found" "$LINENO" 5 ;; #( *:yes) : printf "%s\n" "#define HAVE_SYSTEMD 1" >>confdefs.h LIBS="$LIBS $SYSTEMD_LIBS" ;; #( *) : ;; esac fi # Include systemd.m4 - end # Check whether --enable-tcp-fastopen was given. if test ${enable_tcp_fastopen+y} then : enableval=$enable_tcp_fastopen; fi case "$enable_tcp_fastopen" in yes) ac_fn_check_decl "$LINENO" "TCP_FASTOPEN" "ac_cv_have_decl_TCP_FASTOPEN" "$ac_includes_default #include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TCP_FASTOPEN" = xyes then : else case e in #( e) as_fn_error $? "TCP Fast Open is not available: please rerun without --enable-tcp-fastopen" "$LINENO" 5 ;; esac fi printf "%s\n" "#define USE_TCP_FASTOPEN 1" >>confdefs.h ;; no|*) ;; esac if test $ac_cv_func_getaddrinfo = no; then case " $LIBOBJS " in *" fake-rfc2553.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS fake-rfc2553.$ac_objext" ;; esac fi # big fat warning if test "$enable_checking" = "yes"; then echo "************************************************" echo "* You have activated \"--enable-checking\" *" echo "* *" echo "* This will instruct NSD to be stricter *" echo "* when validating its input. This could lead *" echo "* to a reduced service level. *" echo "* *" echo "************************************************" fi ac_config_files="$ac_config_files Makefile $dnstap_config" # Arguments introduced specifically for simdzone. # Check whether --enable-westmere was given. if test ${enable_westmere+y} then : enableval=$enable_westmere; fi # Check whether --enable-haswell was given. if test ${enable_haswell+y} then : enableval=$enable_haswell; fi subdirs="$subdirs simdzone" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # 'ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs # Check whether --enable-year2038 was given. if test ${enable_year2038+y} then : enableval=$enable_year2038; fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # 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.12.0, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ '$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ NSD config.status 4.12.0 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: '$1' Try '$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: '$1' Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "$dnstap_config") CONFIG_FILES="$CONFIG_FILES $dnstap_config" ;; *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 printf "%s\n" "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nsd-4.12.0/aclocal.m40000644000175000017500000003276415002373056013653 0ustar mozziemozzie# generated automatically by aclocal 1.17 -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 13 (pkgconf) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, see . dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. dnl dnl If pkg-config is not found or older than specified, it will result dnl in an empty PKG_CONFIG variable. To avoid widespread issues with dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting. dnl You can specify [PKG_CONFIG=false] as an action instead, which would dnl result in pkg-config tests failing, but no bogus error messages. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi if test -z "$PKG_CONFIG"; then m4_default([$2], [AC_MSG_ERROR([pkg-config not found])]) fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES nsd-4.12.0/zonec.h0000644000175000017500000000221015002373054013257 0ustar mozziemozzie/* * zonec.h -- zone compiler. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef ZONEC_H #define ZONEC_H #include "namedb.h" #define NSEC_WINDOW_COUNT 256 #define NSEC_WINDOW_BITS_COUNT 256 #define NSEC_WINDOW_BITS_SIZE (NSEC_WINDOW_BITS_COUNT / 8) #define IPSECKEY_NOGATEWAY 0 /* RFC 4025 */ #define IPSECKEY_IP4 1 #define IPSECKEY_IP6 2 #define IPSECKEY_DNAME 3 #define AMTRELAY_NOGATEWAY 0 /* RFC 8777 */ #define AMTRELAY_IP4 1 #define AMTRELAY_IP6 2 #define AMTRELAY_DNAME 3 #define LINEBUFSZ 1024 #define DEFAULT_TTL 3600 /* parse a zone into memory. name is origin. zonefile is file to read. * returns number of errors; failure may have read a partial zone */ unsigned int zonec_read( struct namedb *database, struct domain_table *domains, const char *name, const char *zonefile, struct zone *zone); /** check SSHFP type for failures and emit warnings */ void check_sshfp(void); void apex_rrset_checks(struct namedb* db, rrset_type* rrset, domain_type* domain); #endif /* ZONEC_H */ nsd-4.12.0/zonec.c0000644000175000017500000003046415002373054013266 0ustar mozziemozzie/* * zonec.c -- zone compiler. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include #include #ifdef HAVE_SYS_STAT_H #include #endif #include #ifdef HAVE_NETDB_H #include #endif #include "zonec.h" #include "dname.h" #include "dns.h" #include "namedb.h" #include "rdata.h" #include "region-allocator.h" #include "util.h" #include "options.h" #include "nsec3.h" #include "zone.h" /* * Compares two rdata arrays. * * Returns: * * zero if they are equal * non-zero if not * */ static int zrdatacmp(uint16_t type, const union rdata_atom *rdatas, size_t rdata_count, rr_type *b) { assert(rdatas); assert(b); /* One is shorter than another */ if (rdata_count != b->rdata_count) return 1; /* Compare element by element */ for (size_t i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(type, i)) { if (rdata_atom_domain(rdatas[i]) != rdata_atom_domain(b->rdatas[i])) { return 1; } } else if(rdata_atom_is_literal_domain(type, i)) { if (rdata_atom_size(rdatas[i]) != rdata_atom_size(b->rdatas[i])) return 1; if (!dname_equal_nocase(rdata_atom_data(rdatas[i]), rdata_atom_data(b->rdatas[i]), rdata_atom_size(rdatas[i]))) return 1; } else { if (rdata_atom_size(rdatas[i]) != rdata_atom_size(b->rdatas[i])) { return 1; } if (memcmp(rdata_atom_data(rdatas[i]), rdata_atom_data(b->rdatas[i]), rdata_atom_size(rdatas[i])) != 0) { return 1; } } } /* Otherwise they are equal */ return 0; } /* * Find rrset type for any zone */ static rrset_type* domain_find_rrset_any(domain_type *domain, uint16_t type) { rrset_type *result = domain->rrsets; while (result) { if (rrset_rrtype(result) == type) { return result; } result = result->next; } return NULL; } /* * Check for DNAME type. Nothing is allowed below it */ static int check_dname(zone_type* zone) { domain_type* domain; for(domain = zone->apex; domain && domain_is_subdomain(domain, zone->apex); domain=domain_next(domain)) { if(domain->is_existing) { /* there may not be DNAMEs above it */ domain_type* parent = domain->parent; #ifdef NSEC3 if(domain_has_only_NSEC3(domain, NULL)) continue; #endif while(parent) { if(domain_find_rrset_any(parent, TYPE_DNAME)) { log_msg(LOG_ERR, "While checking node %s,", domain_to_string(domain)); log_msg(LOG_ERR, "DNAME at %s has data below it. " "This is not allowed (rfc 2672).", domain_to_string(parent)); return 0; } parent = parent->parent; } } } return 1; } static int has_soa(domain_type* domain) { rrset_type* p = NULL; if(!domain) return 0; for(p = domain->rrsets; p; p = p->next) if(rrset_rrtype(p) == TYPE_SOA) return 1; return 0; } struct zonec_state { struct namedb *database; struct domain_table *domains; struct region *rr_region; struct zone *zone; struct domain *domain; size_t errors; size_t records; }; int32_t zonec_accept( zone_parser_t *parser, const zone_name_t *owner, uint16_t type, uint16_t class, uint32_t ttl, uint16_t rdlength, const uint8_t *rdata, void *user_data) { struct rr *rr; struct rrset *rrset; const struct dname *dname; struct domain *domain; struct buffer buffer; int priority; union rdata_atom *rdatas; ssize_t rdata_count; struct zonec_state *state = (struct zonec_state *)user_data; assert(state); // emulate packet buffer to leverage rdata_wireformat_to_rdata_atoms buffer_create_from(&buffer, rdata, rdlength); priority = parser->options.secondary ? ZONE_WARNING : ZONE_ERROR; // limit to IN class if (class != CLASS_IN) zone_log(parser, priority, "only class IN is supported"); dname = dname_make(state->rr_region, owner->octets, 1); assert(dname); domain = domain_table_insert(state->domains, dname); assert(domain); rdatas = NULL; rdata_count = rdata_wireformat_to_rdata_atoms( state->database->region, state->domains, type, rdlength, &buffer, &rdatas); // number of atoms must not exceed maximum of 65535 (all empty strings) assert(rdata_count >= 0); assert(rdata_count <= MAX_RDLENGTH); /* we have the zone already */ if (type == TYPE_SOA) { if (domain != state->zone->apex) { char s[MAXDOMAINLEN*5]; snprintf(s, sizeof(s), "%s", domain_to_string(domain)); zone_log(parser, priority, "SOA record with invalid domain name, '%s' is not '%s'", domain_to_string(state->zone->apex), s); } else if (has_soa(domain)) { zone_log(parser, priority, "this SOA record was already encountered"); } domain->is_apex = 1; } if (!domain_is_subdomain(domain, state->zone->apex)) { char s[MAXDOMAINLEN*5]; snprintf(s, sizeof(s), "%s", domain_to_string(state->zone->apex)); zone_log(parser, priority, "out of zone data: %s is outside the zone for fqdn %s", s, domain_to_string(domain)); if (!parser->options.secondary) { region_free_all(state->rr_region); return ZONE_SEMANTIC_ERROR; } } /* Do we have this type of rrset already? */ rrset = domain_find_rrset(domain, state->zone, type); if (!rrset) { rrset = region_alloc(state->database->region, sizeof(*rrset)); rrset->zone = state->zone; rrset->rr_count = 0; rrset->rrs = region_alloc(state->database->region, sizeof(*rr)); switch (type) { case TYPE_CNAME: if (!domain_find_non_cname_rrset(domain, state->zone)) break; zone_log(parser, priority, "CNAME and other data at the same name"); break; case TYPE_RRSIG: case TYPE_NXT: case TYPE_SIG: case TYPE_NSEC: case TYPE_NSEC3: break; default: if (!domain_find_rrset(domain, state->zone, TYPE_CNAME)) break; zone_log(parser, priority, "CNAME and other data at the same name"); break; } /* Add it */ domain_add_rrset(domain, rrset); } else { struct rr *rrs; if (type != TYPE_RRSIG && ttl != rrset->rrs[0].ttl) { zone_log(parser, ZONE_WARNING, "%s TTL %"PRIu32" does not match TTL %u of %s RRset", domain_to_string(domain), ttl, rrset->rrs[0].ttl, rrtype_to_string(type)); } /* Search for possible duplicates... */ for (int i = 0; i < rrset->rr_count; i++) { if (zrdatacmp(type, rdatas, rdata_count, &rrset->rrs[i]) != 0) continue; /* Discard the duplicates... */ for (size_t j = 0; j < (size_t)rdata_count; j++) { size_t size; if (rdata_atom_is_domain(type, j)) continue; size = rdata_atom_size(rdatas[j]) + sizeof(uint16_t); region_recycle(state->database->region, rdatas[j].data, size); } region_recycle(state->database->region, rdatas, sizeof(*rdatas) * rdata_count); region_free_all(state->rr_region); return 0; } switch (type) { case TYPE_CNAME: zone_log(parser, priority, "multiple CNAMEs at the same name"); break; case TYPE_DNAME: zone_log(parser, priority, "multiple DNAMEs at the same name"); break; default: break; } /* Add it... */ rrs = rrset->rrs; rrset->rrs = region_alloc_array(state->database->region, rrset->rr_count + 1, sizeof(*rr)); memcpy(rrset->rrs, rrs, rrset->rr_count * sizeof(*rr)); region_recycle(state->database->region, rrs, rrset->rr_count * sizeof(*rr)); } rr = &rrset->rrs[rrset->rr_count++]; rr->owner = domain; rr->rdatas = rdatas; rr->ttl = ttl; rr->type = type; rr->klass = class; rr->rdata_count = rdata_count; /* Check we have SOA */ if (rr->owner == state->zone->apex) apex_rrset_checks(state->database, rrset, rr->owner); state->records++; region_free_all(state->rr_region); return 0; } static int32_t zonec_include( zone_parser_t *parser, const char *file, const char *path, void *user_data) { char **paths; struct zonec_state *state; struct namedb *database; struct zone *zone; (void)parser; (void)file; state = (struct zonec_state *)user_data; database = state->database; zone = state->zone; assert((zone->includes.count == 0) == (zone->includes.paths == NULL)); for (size_t i=0; i < zone->includes.count; i++) if (strcmp(path, zone->includes.paths[i]) == 0) return 0; paths = region_alloc_array( database->region, zone->includes.count + 1, sizeof(*paths)); if (zone->includes.count) { const size_t size = zone->includes.count * sizeof(*paths); memcpy(paths, zone->includes.paths, size); region_recycle(database->region, zone->includes.paths, size); } paths[zone->includes.count] = region_strdup(database->region, path); zone->includes.count++; zone->includes.paths = paths; return 0; } static void zonec_log( zone_parser_t *parser, uint32_t category, const char *file, size_t line, const char *message, void *user_data) { int priority; struct zonec_state *state = (struct zonec_state *)user_data; assert(state); (void)parser; switch (category) { case ZONE_INFO: priority = LOG_INFO; break; case ZONE_WARNING: priority = LOG_WARNING; break; default: priority = LOG_ERR; state->errors++; break; } if (file) log_msg(priority, "%s:%zu: %s", file, line, message); else log_msg(priority, "%s", message); } /* * Reads the specified zone into the memory * nsd_options can be NULL if no config file is passed. */ unsigned int zonec_read( struct namedb *database, struct domain_table *domains, const char *name, const char *zonefile, struct zone *zone) { const struct dname *origin; zone_parser_t parser; zone_options_t options; zone_name_buffer_t name_buffer; zone_rdata_buffer_t rdata_buffer; struct zonec_state state; zone_buffers_t buffers = { 1, &name_buffer, &rdata_buffer }; state.database = database; state.domains = domains; state.rr_region = region_create(xalloc, free); state.zone = zone; state.domain = NULL; state.errors = 0; state.records = 0; origin = domain_dname(zone->apex); memset(&options, 0, sizeof(options)); options.origin.octets = dname_name(origin); options.origin.length = origin->name_size; options.default_ttl = DEFAULT_TTL; options.default_class = CLASS_IN; options.secondary = zone_is_slave(zone->opts) != 0; options.pretty_ttls = true; /* non-standard, for backwards compatibility */ options.log.callback = &zonec_log; options.accept.callback = &zonec_accept; options.include.callback = &zonec_include; /* Parse and process all RRs. */ if (zone_parse(&parser, &options, &buffers, zonefile, &state) != 0) { region_destroy(state.rr_region); return state.errors; } /* Check if zone file contained a correct SOA record */ if (!zone) { log_msg(LOG_ERR, "zone configured as '%s' has no content.", name); state.errors++; } else if (!zone->soa_rrset || zone->soa_rrset->rr_count == 0) { log_msg(LOG_ERR, "zone configured as '%s' has no SOA record", name); state.errors++; } else if (dname_compare(domain_dname(zone->soa_rrset->rrs[0].owner), origin) != 0) { log_msg(LOG_ERR, "zone configured as '%s', but SOA has owner '%s'", name, domain_to_string(zone->soa_rrset->rrs[0].owner)); state.errors++; } if(!zone_is_slave(zone->opts) && !check_dname(zone)) state.errors++; region_destroy(state.rr_region); return state.errors; } void apex_rrset_checks(namedb_type* db, rrset_type* rrset, domain_type* domain) { uint32_t soa_minimum; unsigned i; zone_type* zone = rrset->zone; assert(domain == zone->apex); (void)domain; if (rrset_rrtype(rrset) == TYPE_SOA) { zone->soa_rrset = rrset; /* BUG #103 add another soa with a tweaked ttl */ if(zone->soa_nx_rrset == 0) { zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); zone->soa_nx_rrset->rr_count = 1; zone->soa_nx_rrset->next = 0; zone->soa_nx_rrset->zone = zone; zone->soa_nx_rrset->rrs = region_alloc(db->region, sizeof(rr_type)); } memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); /* check the ttl and MINIMUM value and set accordingly */ memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } } else if (rrset_rrtype(rrset) == TYPE_NS) { zone->ns_rrset = rrset; } else if (rrset_rrtype(rrset) == TYPE_RRSIG) { for (i = 0; i < rrset->rr_count; ++i) { if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY){ zone->is_secure = 1; break; } } } } nsd-4.12.0/xfrd.h0000644000175000017500000003622615002373054013122 0ustar mozziemozzie/* * xfrd.h - XFR (transfer) Daemon header file. Coordinates SOA updates. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_H #define XFRD_H #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "rbtree.h" #include "namedb.h" #include "options.h" #include "dns.h" #include "tsig.h" struct nsd; struct region; struct buffer; struct xfrd_tcp; struct xfrd_tcp_set; struct notify_zone; struct udb_ptr; typedef struct xfrd_state xfrd_state_type; typedef struct xfrd_xfr xfrd_xfr_type; typedef struct xfrd_zone xfrd_zone_type; typedef struct xfrd_soa xfrd_soa_type; /* * The global state for the xfrd daemon process. * The time_t times are epochs in secs since 1970, absolute times. */ struct xfrd_state { /* time when daemon was last started */ time_t xfrd_start_time; struct region* region; struct event_base* event_base; struct nsd* nsd; struct xfrd_tcp_set* tcp_set; /* packet buffer for udp packets */ struct buffer* packet; /* udp waiting list, double linked list */ struct xfrd_zone *udp_waiting_first, *udp_waiting_last; /* number of udp sockets (for sending queries) in use */ size_t udp_use_num; /* activated waiting list, double linked list */ struct xfrd_zone *activated_first; /* current time is cached */ uint8_t got_time; time_t current_time; /* counter for xfr file numbers */ uint64_t xfrfilenumber; /* the zonestat array size that we last saw and is safe to use */ unsigned zonestat_safe; /* size currently of the clear array */ size_t zonestat_clear_num; /* array of malloced entries with cumulative cleared stat values */ struct nsdst** zonestat_clear; /* array of child_count size with cumulative cleared stat values */ struct nsdst* stat_clear; /* timer for NSD reload */ struct timeval reload_timeout; struct event reload_handler; int reload_added; /* last reload must have caught all zone updates before this time */ time_t reload_cmd_last_sent; time_t reload_cmd_first_sent; uint8_t reload_failed; uint8_t can_send_reload; pid_t reload_pid; /* timeout for lost sigchild and reaping children */ struct event child_timer; int child_timer_added; /* timeout event for zonefiles_write events */ struct event write_timer; /* set to 1 if zones have received xfrs since the last write_timer */ int write_zonefile_needed; /* communication channel with server_main */ struct event ipc_handler; int ipc_handler_flags; /* 2 * nsd->child_count communication channels from the serve childs */ struct event *notify_events; struct xfrd_tcp *notify_pipes; /* sending ipc to server_main */ uint8_t need_to_send_shutdown; uint8_t need_to_send_reload; uint8_t need_to_send_stats; uint8_t need_to_send_quit; uint8_t ipc_send_blocked; struct udb_ptr* last_task; /* xfrd shutdown flag */ uint8_t shutdown; /* tree of zones, by apex name, contains xfrd_zone_type*. Only secondary zones. */ rbtree_type *zones; /* tree of zones, by apex name, contains notify_zone*. All zones. */ rbtree_type *notify_zones; /* number of notify_zone active using UDP socket */ int notify_udp_num; /* first and last notify_zone* entries waiting for a UDP socket */ struct notify_zone *notify_waiting_first, *notify_waiting_last; /* tree of catalog consumer zones. Processing is disabled if > 1. */ rbtree_type *catalog_consumer_zones; /* tree of updated catalog producer zones for which the content to serve */ rbtree_type *catalog_producer_zones; }; /* * XFR daemon SOA information kept in network format. * This is in packet order. */ struct xfrd_soa { /* name of RR is zone apex dname */ uint16_t type; /* = TYPE_SOA */ uint16_t klass; /* = CLASS_IN */ uint32_t ttl; uint16_t rdata_count; /* = 7 */ /* format is 1 octet length, + wireformat dname. one more octet since parse_dname_wire_from_packet needs it. maximum size is allocated to avoid memory alloc/free. */ uint8_t prim_ns[MAXDOMAINLEN + 2]; uint8_t email[MAXDOMAINLEN + 2]; uint32_t serial; uint32_t refresh; uint32_t retry; uint32_t expire; uint32_t minimum; } ATTR_PACKED; /* * XFRD state for a single zone */ struct xfrd_zone { rbnode_type node; /* name of the zone */ const dname_type* apex; const char* apex_str; /* Three types of soas: * NSD: in use by running server * disk: stored on disk in db/diff file * notified: from notification, could be available on a master. * And the time the soa was acquired (start time for timeouts). * If the time==0, no SOA is available. */ xfrd_soa_type soa_nsd; time_t soa_nsd_acquired; xfrd_soa_type soa_disk; time_t soa_disk_acquired; xfrd_soa_type soa_notified; time_t soa_notified_acquired; enum xfrd_zone_state { xfrd_zone_ok, xfrd_zone_refreshing, xfrd_zone_expired } state; /* master to try to transfer from, number for persistence */ struct acl_options* master; int master_num; int next_master; /* -1 or set by notify where to try next */ /* round of xfrattempts, -1 is waiting for timeout */ int round_num; struct zone_options* zone_options; int fresh_xfr_timeout; /* handler for timeouts */ struct timeval timeout; struct event zone_handler; int zone_handler_flags; int event_added; /* tcp connection zone is using, or -1 */ int tcp_conn; /* zone is waiting for a tcp connection */ uint8_t tcp_waiting; /* next zone in waiting list */ xfrd_zone_type* tcp_waiting_next; xfrd_zone_type* tcp_waiting_prev; /* zone is in its tcp send queue */ uint8_t in_tcp_send; /* next zone in tcp send queue */ xfrd_zone_type* tcp_send_next; xfrd_zone_type* tcp_send_prev; /* zone is waiting for a udp connection (tcp is preferred) */ uint8_t udp_waiting; /* next zone in waiting list for UDP */ xfrd_zone_type* udp_waiting_next; xfrd_zone_type* udp_waiting_prev; /* zone has been activated to run now (after the other events * but before blocking in select again) */ uint8_t is_activated; xfrd_zone_type* activated_next; xfrd_zone_type* activated_prev; /* xfr message handling data */ /* query id */ uint16_t query_id; xfrd_xfr_type *latest_xfr; int multi_master_first_master; /* >0: first check master_num */ int multi_master_update_check; /* -1: not update >0: last update master_num */ } ATTR_PACKED; /* * State for a single zone XFR */ struct xfrd_xfr { xfrd_xfr_type *next; xfrd_xfr_type *prev; uint16_t query_type; uint8_t sent; /* written to tasklist (tri-state) */ time_t acquired; /* time xfr was acquired */ uint32_t msg_seq_nr; /* number of messages already handled */ uint32_t msg_old_serial, msg_new_serial; /* host byte order */ size_t msg_rr_count; uint8_t msg_is_ixfr; /* 1:IXFR detected. 2:middle IXFR SOA seen. */ tsig_record_type tsig; /* tsig state for IXFR/AXFR */ uint64_t xfrfilenumber; /* identifier for file to store xfr into, valid if msg_seq_nr nonzero */ }; enum xfrd_packet_result { xfrd_packet_bad, /* drop the packet/connection */ xfrd_packet_drop, /* drop the connection, but not report bad */ xfrd_packet_more, /* more packets to follow on tcp */ xfrd_packet_notimpl, /* server responded with NOTIMPL or FORMATERR */ xfrd_packet_tcp, /* try tcp connection */ xfrd_packet_transfer, /* server responded with transfer*/ xfrd_packet_newlease /* no changes, soa OK */ }; /* Division of the (portably: 1024) max number of sockets that can be open. The sum of the below numbers should be below the user limit for sockets open, or you see errors in your logfile. And it should be below FD_SETSIZE, to be able to select() on replies. Note that also some sockets are used for writing the ixfr.db, xfrd.state files and for the pipes to the main parent process. For xfrd_tcp_max, 128 is the default number of TCP AXFR/IXFR concurrent connections. Each entry has 64Kb buffer preallocated. */ #define XFRD_MAX_UDP 128 /* max number of UDP sockets at a time for IXFR */ #define XFRD_MAX_UDP_NOTIFY 128 /* max concurrent UDP sockets for NOTIFY */ #define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 2*x seconds */ #define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */ #define XFRD_LOWERBOUND_REFRESH 1 /* seconds, smallest refresh timeout */ #define XFRD_LOWERBOUND_RETRY 1 /* seconds, smallest retry timeout */ /* * return refresh period * within configured and defined lower and upper bounds */ static inline time_t within_refresh_bounds(xfrd_zone_type* zone, time_t refresh) { return (time_t)zone->zone_options->pattern->max_refresh_time < refresh ? (time_t)zone->zone_options->pattern->max_refresh_time : (time_t)zone->zone_options->pattern->min_refresh_time > refresh ? (time_t)zone->zone_options->pattern->min_refresh_time : XFRD_LOWERBOUND_REFRESH > refresh ? XFRD_LOWERBOUND_REFRESH : refresh; } /* * return the zone's refresh period (from the on disk stored SOA) * within configured and defined lower and upper bounds */ static inline time_t bound_soa_disk_refresh(xfrd_zone_type* zone) { return within_refresh_bounds(zone, ntohl(zone->soa_disk.refresh)); } /* * return retry period * within configured and defined lower and upper bounds */ static inline time_t within_retry_bounds(xfrd_zone_type* zone, time_t retry) { return (time_t)zone->zone_options->pattern->max_retry_time < retry ? (time_t)zone->zone_options->pattern->max_retry_time : (time_t)zone->zone_options->pattern->min_retry_time > retry ? (time_t)zone->zone_options->pattern->min_retry_time : XFRD_LOWERBOUND_RETRY > retry ? XFRD_LOWERBOUND_RETRY : retry; } /* * return the zone's retry period (from the on disk stored SOA) * within configured and defined lower and upper bounds */ static inline time_t bound_soa_disk_retry(xfrd_zone_type* zone) { return within_retry_bounds(zone, ntohl(zone->soa_disk.retry)); } /* * return expire period * within configured and defined lower bounds */ static inline time_t within_expire_bounds(xfrd_zone_type* zone, time_t expire) { switch (zone->zone_options->pattern->min_expire_time_expr) { case EXPIRE_TIME_HAS_VALUE: return (time_t)zone->zone_options->pattern->min_expire_time > expire ? (time_t)zone->zone_options->pattern->min_expire_time : expire; case REFRESHPLUSRETRYPLUS1: return bound_soa_disk_refresh(zone) + bound_soa_disk_retry(zone) + 1 > expire ? bound_soa_disk_refresh(zone) + bound_soa_disk_retry(zone) + 1 : expire; default: return expire; } } /* return the zone's expire period (from the on disk stored SOA) */ static inline time_t bound_soa_disk_expire(xfrd_zone_type* zone) { return within_expire_bounds(zone, ntohl(zone->soa_disk.expire)); } /* return the zone's expire period (from the SOA in use by the running server) */ static inline time_t bound_soa_nsd_expire(xfrd_zone_type* zone) { return within_expire_bounds(zone, ntohl(zone->soa_nsd.expire)); } extern xfrd_state_type* xfrd; /* start xfrd, new start. Pass socket to server_main. */ void xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, pid_t nsd_pid); /* add new slave zone, dname(from zone_opt) and given options */ void xfrd_init_slave_zone(xfrd_state_type* xfrd, struct zone_options* zone_opt); /* delete slave zone */ void xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname); /* disable ixfr for a while for zone->master */ void xfrd_disable_ixfr(xfrd_zone_type* zone); /* get the current time epoch. Cached for speed. */ time_t xfrd_time(void); /* * Handle final received packet from network. * returns enum of packet discovery results */ enum xfrd_packet_result xfrd_handle_received_xfr_packet( xfrd_zone_type* zone, buffer_type* packet); /* set timer to specific value */ void xfrd_set_timer(xfrd_zone_type* zone, time_t t); /* set refresh timer of zone to refresh at time now */ void xfrd_set_refresh_now(xfrd_zone_type* zone); /* unset the timer - no more timeouts, for when zone is queued */ void xfrd_unset_timer(xfrd_zone_type* zone); /* remove the 'refresh now', remove it from the activated list */ void xfrd_deactivate_zone(xfrd_zone_type* z); /* * Make a new request to next master server. * uses next_master if set (and a fresh set of rounds). * otherwise, starts new round of requests if none started already. * starts next round of requests if at last master. * if too many rounds of requests, sets timer for next retry. */ void xfrd_make_request(xfrd_zone_type* zone); /* * send packet via udp (returns UDP fd source socket) to acl addr. * returns -1 on failure. */ int xfrd_send_udp(struct acl_options* acl, buffer_type* packet, struct acl_options* ifc); /* * read from udp port packet into buffer, returns 0 on failure */ int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src, socklen_t* srclen); /* * Release udp socket that a zone is using */ void xfrd_udp_release(xfrd_zone_type* zone); /* * Get a static buffer for temporary use (to build a packet). */ struct buffer* xfrd_get_temp_buffer(void); /* * TSIG sign outgoing request. Call if acl has a key. */ void xfrd_tsig_sign_request(buffer_type* packet, struct tsig_record* tsig, struct acl_options* acl); /* handle incoming soa information (NSD is running it, time acquired=guess). Pass soa=NULL,acquired=now if NSD has nothing loaded for the zone (i.e. zonefile was deleted). */ void xfrd_handle_incoming_soa(xfrd_zone_type* zone, xfrd_soa_type* soa, time_t acquired); /* handle a packet passed along ipc route. acl is the one that accepted the packet. The packet is the network blob received. acl_xfr is provide-xfr acl matching notify sender or -1 */ void xfrd_handle_passed_packet(buffer_type* packet, int acl_num, int acl_xfr); /* try to reopen the logfile. */ void xfrd_reopen_logfile(void); /* free namedb for xfrd usage */ void xfrd_free_namedb(struct nsd* nsd); /* copy SOA info from rr to soa struct. */ void xfrd_copy_soa(xfrd_soa_type* soa, rr_type* rr); /* check for failed updates - it is assumed that now the reload has finished, and all zone SOAs have been sent. */ void xfrd_check_failed_updates(void); void xfrd_prepare_updates_for_reload(void); /* * Prepare zones for a reload, this sets the times on the zones to be * before the current time, so the reload happens after. */ void xfrd_prepare_zones_for_reload(void); /* Bind a local interface to a socket descriptor, return 1 on success */ int xfrd_bind_local_interface(int sockd, struct acl_options* ifc, struct acl_options* acl, int tcp); /* process results and soa info from reload */ void xfrd_process_task_result(xfrd_state_type* xfrd, struct udb_base* taskudb); /* set to reload right away (for user controlled reload events) */ void xfrd_set_reload_now(xfrd_state_type* xfrd); /* send expiry notifications to nsd */ void xfrd_send_expire_notification(xfrd_zone_type* zone); /* handle incoming notify (soa or NULL) and start zone xfr if necessary */ void xfrd_handle_notify_and_start_xfr(xfrd_zone_type* zone, xfrd_soa_type* soa); /* handle zone timeout, event */ void xfrd_handle_zone(int fd, short event, void* arg); const char* xfrd_pretty_time(time_t v); xfrd_xfr_type *xfrd_prepare_zone_xfr(xfrd_zone_type *zone, uint16_t query_type); void xfrd_delete_zone_xfr(xfrd_zone_type *zone, xfrd_xfr_type *xfr); #endif /* XFRD_H */ nsd-4.12.0/xfrd.c0000644000175000017500000026462415002373054013122 0ustar mozziemozzie/* * xfrd.c - XFR (transfer) Daemon source file. Coordinates SOA updates. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "xfrd.h" #include "xfrd-tcp.h" #include "xfrd-disk.h" #include "xfrd-notify.h" #include "xfrd-catalog-zones.h" #include "options.h" #include "util.h" #include "netio.h" #include "region-allocator.h" #include "nsd.h" #include "packet.h" #include "rdata.h" #include "difffile.h" #include "ipc.h" #include "remote.h" #include "rrl.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif #ifdef USE_METRICS #include "metrics.h" #endif /* USE_METRICS */ #ifdef HAVE_SYSTEMD #include #endif #define XFRD_UDP_TIMEOUT 10 /* seconds, before a udp request times out */ #define XFRD_NO_IXFR_CACHE 172800 /* 48h before retrying ixfr's after notimpl */ #define XFRD_MAX_ROUNDS 1 /* max number of rounds along the masters */ #define XFRD_TSIG_MAX_UNSIGNED 103 /* max number of packets without tsig in a tcp stream. */ /* rfc recommends 100, +3 for offbyone errors/interoperability. */ #define XFRD_CHILD_REAP_TIMEOUT 60 /* seconds to wakeup and reap lost children */ /* these are reload processes that SIGCHILDed but the signal * was lost, and need waitpid to remove their process entry. */ /* the daemon state */ xfrd_state_type* xfrd = 0; /* main xfrd loop */ static void xfrd_main(void); /* shut down xfrd, close sockets. */ static void xfrd_shutdown(void); /* delete pending task xfr files in tmp */ static void xfrd_clean_pending_tasks(struct nsd* nsd, udb_base* u); /* create zone rbtree at start */ static void xfrd_init_zones(void); /* initial handshake with SOAINFO from main and send expire to main */ static void xfrd_receive_soa(int socket, int shortsoa); /* handle incoming notification message. soa can be NULL. true if transfer needed. */ static int xfrd_handle_incoming_notify(xfrd_zone_type* zone, xfrd_soa_type* soa); /* call with buffer just after the soa dname. returns 0 on error. */ static int xfrd_parse_soa_info(buffer_type* packet, xfrd_soa_type* soa); /* set the zone state to a new state (takes care of expiry messages) */ static void xfrd_set_zone_state(xfrd_zone_type* zone, enum xfrd_zone_state new_zone_state); /* set timer for retry amount (depends on zone_state) */ static void xfrd_set_timer_retry(xfrd_zone_type* zone); /* set timer for refresh timeout (depends on zone_state) */ static void xfrd_set_timer_refresh(xfrd_zone_type* zone); /* set reload timeout */ static void xfrd_set_reload_timeout(void); /* handle reload timeout */ static void xfrd_handle_reload(int fd, short event, void* arg); /* handle child timeout */ static void xfrd_handle_child_timer(int fd, short event, void* arg); /* send ixfr request, returns fd of connection to read on */ static int xfrd_send_ixfr_request_udp(xfrd_zone_type* zone); /* obtain udp socket slot */ static void xfrd_udp_obtain(xfrd_zone_type* zone); /* read data via udp */ static void xfrd_udp_read(xfrd_zone_type* zone); /* find master by notify number */ static int find_same_master_notify(xfrd_zone_type* zone, int acl_num_nfy); /* set the write timer to activate */ static void xfrd_write_timer_set(void); static void xfrd_free_zone_xfr(xfrd_zone_type* zone, xfrd_xfr_type* xfr); static void xfrd_signal_callback(int sig, short event, void* ATTR_UNUSED(arg)) { if(!(event & EV_SIGNAL)) return; sig_handler(sig); } static struct event* xfrd_sig_evs[10]; static int xfrd_sig_num = 0; static void xfrd_sigsetup(int sig) { struct event *ev = xalloc_zero(sizeof(*ev)); assert(xfrd_sig_num <= (int)(sizeof(xfrd_sig_evs)/sizeof(ev))); xfrd_sig_evs[xfrd_sig_num++] = ev; signal_set(ev, sig, xfrd_signal_callback, NULL); if(event_base_set(xfrd->event_base, ev) != 0) { log_msg(LOG_ERR, "xfrd sig handler: event_base_set failed"); } if(signal_add(ev, NULL) != 0) { log_msg(LOG_ERR, "xfrd sig handler: signal_add failed"); } } void xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, pid_t nsd_pid) { region_type* region; size_t i; assert(xfrd == 0); /* to setup signalhandling */ nsd->server_kind = NSD_SERVER_MAIN; region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); xfrd = (xfrd_state_type*)region_alloc(region, sizeof(xfrd_state_type)); memset(xfrd, 0, sizeof(xfrd_state_type)); xfrd->region = region; xfrd->xfrd_start_time = time(0); xfrd->event_base = nsd_child_event_base(); if(!xfrd->event_base) { log_msg(LOG_ERR, "xfrd: cannot create event base"); exit(1); } xfrd->nsd = nsd; xfrd->packet = buffer_create(xfrd->region, QIOBUFSZ); xfrd->udp_waiting_first = NULL; xfrd->udp_waiting_last = NULL; xfrd->udp_use_num = 0; xfrd->got_time = 0; xfrd->xfrfilenumber = 0; #ifdef USE_ZONE_STATS xfrd->zonestat_safe = nsd->zonestatdesired; #endif xfrd->activated_first = NULL; xfrd->last_task = region_alloc(xfrd->region, sizeof(*xfrd->last_task)); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); assert(shortsoa || udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0); xfrd->reload_handler.ev_fd = -1; xfrd->reload_added = 0; xfrd->reload_timeout.tv_sec = 0; xfrd->reload_cmd_last_sent = xfrd->xfrd_start_time; xfrd->reload_cmd_first_sent = 0; xfrd->reload_failed = 0; xfrd->can_send_reload = !reload_active; xfrd->reload_pid = nsd_pid; xfrd->child_timer_added = 0; xfrd->ipc_send_blocked = 0; memset(&xfrd->ipc_handler, 0, sizeof(xfrd->ipc_handler)); event_set(&xfrd->ipc_handler, socket, EV_PERSIST|EV_READ, xfrd_handle_ipc, xfrd); if(event_base_set(xfrd->event_base, &xfrd->ipc_handler) != 0) log_msg(LOG_ERR, "xfrd ipc handler: event_base_set failed"); if(event_add(&xfrd->ipc_handler, NULL) != 0) log_msg(LOG_ERR, "xfrd ipc handler: event_add failed"); xfrd->ipc_handler_flags = EV_PERSIST|EV_READ; xfrd->notify_events = (struct event *) region_alloc_array_zero( xfrd->region, nsd->child_count * 2, sizeof(struct event)); xfrd->notify_pipes = (struct xfrd_tcp *) region_alloc_array_zero( xfrd->region, nsd->child_count * 2, sizeof(struct xfrd_tcp)); for(i = 0; i < 2 * nsd->child_count; i++) { int fd = nsd->serve2xfrd_fd_recv[i]; xfrd->notify_pipes[i].fd = fd; xfrd->notify_pipes[i].packet = buffer_create(xfrd->region, QIOBUFSZ); event_set(&xfrd->notify_events[i], fd, EV_PERSIST|EV_READ, xfrd_handle_notify, &xfrd->notify_pipes[i]); if(event_base_set(xfrd->event_base, &xfrd->notify_events[i]) != 0) log_msg( LOG_ERR , "xfrd notify_event: event_base_set failed"); if(event_add(&xfrd->notify_events[i], NULL) != 0) log_msg(LOG_ERR, "xfrd notify_event: event_add failed"); } xfrd->need_to_send_reload = 0; xfrd->need_to_send_shutdown = 0; xfrd->need_to_send_stats = 0; xfrd->write_zonefile_needed = 0; if(nsd->options->zonefiles_write) xfrd_write_timer_set(); xfrd->notify_waiting_first = NULL; xfrd->notify_waiting_last = NULL; xfrd->notify_udp_num = 0; daemon_remote_attach(xfrd->nsd->rc, xfrd); #ifdef USE_METRICS daemon_metrics_attach(xfrd->nsd->metrics, xfrd); #endif /* USE_METRICS */ xfrd->tcp_set = xfrd_tcp_set_create(xfrd->region, nsd->options->tls_cert_bundle, nsd->options->xfrd_tcp_max, nsd->options->xfrd_tcp_pipeline); xfrd->tcp_set->tcp_timeout = nsd->tcp_timeout; #if !defined(HAVE_ARC4RANDOM) && !defined(HAVE_GETRANDOM) srandom((unsigned long) getpid() * (unsigned long) time(NULL)); #endif DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd pre-startup")); xfrd_init_zones(); xfrd_receive_soa(socket, shortsoa); if(nsd->options->xfrdfile != NULL && nsd->options->xfrdfile[0]!=0) xfrd_read_state(xfrd); /* did we get killed before startup was successful? */ if(nsd->signal_hint_shutdown) { kill(nsd_pid, SIGTERM); xfrd_shutdown(); return; } /* init libevent signals now, so that in the previous init scripts * the normal sighandler is called, and can set nsd->signal_hint.. * these are also looked at in sig_process before we run the main loop*/ xfrd_sigsetup(SIGHUP); xfrd_sigsetup(SIGTERM); xfrd_sigsetup(SIGQUIT); xfrd_sigsetup(SIGCHLD); xfrd_sigsetup(SIGALRM); xfrd_sigsetup(SIGILL); xfrd_sigsetup(SIGUSR1); xfrd_sigsetup(SIGINT); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd startup")); #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif xfrd_main(); } static void xfrd_process_activated(void) { xfrd_zone_type* zone; while((zone = xfrd->activated_first)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s activation", zone->apex_str)); /* pop zone from activated list */ xfrd->activated_first = zone->activated_next; if(zone->activated_next) zone->activated_next->activated_prev = NULL; zone->is_activated = 0; /* run it : no events, specifically not the TIMEOUT event, * so that running zone transfers are not interrupted */ xfrd_handle_zone(zone->zone_handler.ev_fd, 0, zone); } } static void xfrd_sig_process(void) { int status; pid_t child_pid; if(xfrd->nsd->signal_hint_quit || xfrd->nsd->signal_hint_shutdown) { xfrd->nsd->signal_hint_quit = 0; xfrd->nsd->signal_hint_shutdown = 0; xfrd->need_to_send_shutdown = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } else if(xfrd->nsd->signal_hint_reload_hup) { log_msg(LOG_WARNING, "SIGHUP received, reloading..."); xfrd->nsd->signal_hint_reload_hup = 0; if(xfrd->nsd->options->reload_config) { xfrd_reload_config(xfrd); } if(xfrd->nsd->options->zonefiles_check) { task_new_check_zonefiles(xfrd->nsd->task[ xfrd->nsd->mytask], xfrd->last_task, NULL); } xfrd_set_reload_now(xfrd); } else if(xfrd->nsd->signal_hint_statsusr) { xfrd->nsd->signal_hint_statsusr = 0; xfrd->need_to_send_stats = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } /* collect children that exited. */ xfrd->nsd->signal_hint_child = 0; while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { if(status != 0) { log_msg(LOG_ERR, "process %d exited with status %d", (int)child_pid, status); } } if(!xfrd->child_timer_added) { struct timeval tv; tv.tv_sec = XFRD_CHILD_REAP_TIMEOUT; tv.tv_usec = 0; memset(&xfrd->child_timer, 0, sizeof(xfrd->child_timer)); event_set(&xfrd->child_timer, -1, EV_TIMEOUT, xfrd_handle_child_timer, xfrd); if(event_base_set(xfrd->event_base, &xfrd->child_timer) != 0) log_msg(LOG_ERR, "xfrd child timer: event_base_set failed"); if(event_add(&xfrd->child_timer, &tv) != 0) log_msg(LOG_ERR, "xfrd child timer: event_add failed"); xfrd->child_timer_added = 1; } } static void xfrd_main(void) { /* we may have signals from the startup period, process them */ xfrd_sig_process(); xfrd->shutdown = 0; while(!xfrd->shutdown) { /* xfrd_sig_process takes care of reading zones on SIGHUP */ xfrd_process_catalog_producer_zones(); xfrd_process_catalog_consumer_zones(); /* process activated zones before blocking in select again */ xfrd_process_activated(); /* dispatch may block for a longer period, so current is gone */ xfrd->got_time = 0; if(event_base_loop(xfrd->event_base, EVLOOP_ONCE) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "xfrd dispatch failed: %s", strerror(errno)); } } xfrd_sig_process(); } xfrd_shutdown(); } static void xfrd_shutdown() { xfrd_zone_type* zone; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown")); #ifdef HAVE_SYSTEMD sd_notify(0, "STOPPING=1"); #endif event_del(&xfrd->ipc_handler); close(xfrd->ipc_handler.ev_fd); /* notifies parent we stop */ zone_list_close(nsd.options); if(xfrd->nsd->options->xfrdfile != NULL && xfrd->nsd->options->xfrdfile[0]!=0) xfrd_write_state(xfrd); if(xfrd->reload_added) { event_del(&xfrd->reload_handler); xfrd->reload_added = 0; } if(xfrd->child_timer_added) { event_del(&xfrd->child_timer); xfrd->child_timer_added = 0; } if(xfrd->nsd->options->zonefiles_write) { event_del(&xfrd->write_timer); } daemon_remote_close(xfrd->nsd->rc); /* close sockets of rc */ /* close sockets */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->event_added) { event_del(&zone->zone_handler); if(zone->zone_handler.ev_fd != -1) { close(zone->zone_handler.ev_fd); zone->zone_handler.ev_fd = -1; } zone->event_added = 0; } } close_notify_fds(xfrd->notify_zones); /* wait for server parent (if necessary) */ if(xfrd->reload_pid != -1) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd wait for servermain %d", (int)xfrd->reload_pid)); while(1) { if(waitpid(xfrd->reload_pid, NULL, 0) == -1) { if(errno == EINTR) continue; if(errno == ECHILD) break; log_msg(LOG_ERR, "xfrd: waitpid(%d): %s", (int)xfrd->reload_pid, strerror(errno)); } break; } } /* if we are killed past this point this is not a problem, * some files left in /tmp are cleaned by the OS, but it is neater * to clean them out */ /* unlink xfr files for running transfers */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { xfrd_xfr_type *xfr; for(xfr = zone->latest_xfr; xfr != NULL; xfr = xfr->prev) { if (xfr->acquired == 0) continue; xfrd_unlink_xfrfile(xfrd->nsd, xfr->xfrfilenumber); } } /* unlink xfr files in not-yet-done task file */ xfrd_clean_pending_tasks(xfrd->nsd, xfrd->nsd->task[xfrd->nsd->mytask]); xfrd_del_tempdir(xfrd->nsd); daemon_remote_delete(xfrd->nsd->rc); /* ssl-delete secret keys */ #ifdef HAVE_SSL if (xfrd->nsd->tls_ctx) SSL_CTX_free(xfrd->nsd->tls_ctx); # ifdef HAVE_TLS_1_3 if (xfrd->tcp_set->ssl_ctx) SSL_CTX_free(xfrd->tcp_set->ssl_ctx); # endif #endif #ifdef USE_DNSTAP dt_collector_close(nsd.dt_collector, &nsd); #endif /* process-exit cleans up memory used by xfrd process */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown complete")); #ifdef MEMCLEAN /* OS collects memory pages */ if(xfrd->nsd->db) { namedb_close(xfrd->nsd->db); } /* TODO: cleanup xfrd->catalog_consumer_zones and xfrd->catalog_producer_zones */ if(xfrd->zones) { xfrd_zone_type* z; RBTREE_FOR(z, xfrd_zone_type*, xfrd->zones) { while(z->latest_xfr != NULL) { xfrd_free_zone_xfr(z, z->latest_xfr); } } } if(xfrd->notify_zones) { struct notify_zone* n; RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones) { tsig_delete_record(&n->notify_tsig, NULL); } } if(xfrd_sig_num > 0) { int i; for(i=0; ievent_base); region_destroy(xfrd->region); nsd_options_destroy(nsd.options); region_destroy(nsd.region); log_finalize(); #endif exit(0); } static void xfrd_clean_pending_tasks(struct nsd* nsd, udb_base* u) { udb_ptr t; udb_ptr_new(&t, u, udb_base_get_userdata(u)); /* no dealloc of entries, we delete the entire file when done */ while(!udb_ptr_is_null(&t)) { if(TASKLIST(&t)->task_type == task_apply_xfr) { xfrd_unlink_xfrfile(nsd, TASKLIST(&t)->yesno); } udb_ptr_set_rptr(&t, u, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, u); } void xfrd_init_slave_zone(xfrd_state_type* xfrd, struct zone_options* zone_opt) { int num, num_xot; xfrd_zone_type *xzone; xzone = (xfrd_zone_type*)region_alloc(xfrd->region, sizeof(xfrd_zone_type)); memset(xzone, 0, sizeof(xfrd_zone_type)); xzone->apex = zone_opt->node.key; xzone->apex_str = zone_opt->name; xzone->state = xfrd_zone_refreshing; xzone->zone_options = zone_opt; /* first retry will use first master */ xzone->master = xzone->zone_options->pattern->request_xfr; xzone->master_num = 0; xzone->next_master = 0; xzone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; xzone->soa_nsd_acquired = 0; xzone->soa_disk_acquired = 0; xzone->latest_xfr = NULL; xzone->soa_notified_acquired = 0; /* [0]=1, [1]=0; "." domain name */ xzone->soa_nsd.prim_ns[0] = 1; xzone->soa_nsd.email[0] = 1; xzone->soa_disk.prim_ns[0]=1; xzone->soa_disk.email[0]=1; xzone->soa_notified.prim_ns[0]=1; xzone->soa_notified.email[0]=1; xzone->zone_handler.ev_fd = -1; xzone->zone_handler_flags = 0; xzone->event_added = 0; xzone->tcp_conn = -1; xzone->tcp_waiting = 0; xzone->udp_waiting = 0; xzone->is_activated = 0; xzone->multi_master_first_master = -1; xzone->multi_master_update_check = -1; /* set refreshing anyway, if we have data it may be old */ xfrd_set_refresh_now(xzone); /*Check all or none of acls use XoT*/ num = 0; num_xot = 0; for (; xzone->master != NULL; xzone->master = xzone->master->next, num++) { if (xzone->master->tls_auth_options != NULL) num_xot++; } if (num_xot != 0 && num != num_xot) log_msg(LOG_WARNING, "Some but not all request-xfrs for %s have XFR-over-TLS configured", xzone->apex_str); xzone->node.key = xzone->apex; rbtree_insert(xfrd->zones, (rbnode_type*)xzone); } static void xfrd_init_zones() { struct zone_options *zone_opt; assert(xfrd->zones == 0); xfrd->zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); xfrd->notify_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); xfrd->catalog_consumer_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); xfrd->catalog_producer_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); RBTREE_FOR(zone_opt, struct zone_options*, xfrd->nsd->options->zone_options) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: adding %s zone", zone_opt->name)); if(zone_is_catalog_consumer(zone_opt)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s " "is a catalog consumer zone", zone_opt->name)); xfrd_init_catalog_consumer_zone(xfrd, zone_opt); } if(zone_is_catalog_producer_member(zone_opt)) { xfrd_add_catalog_producer_member( as_catalog_member_zone(zone_opt)); } init_notify_send(xfrd->notify_zones, xfrd->region, zone_opt); if(!zone_is_slave(zone_opt)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, " "master zone has no outgoing xfr requests", zone_opt->name)); continue; } xfrd_init_slave_zone(xfrd, zone_opt); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: started server %d " "secondary zones, %d catalog zones", (int)xfrd->zones->count, (int)xfrd->catalog_consumer_zones->count)); } static void apply_xfrs_to_consumer_zone(struct xfrd_catalog_consumer_zone* consumer_zone, zone_type* dbzone, xfrd_xfr_type* xfr) { FILE* df; if(xfr->msg_is_ixfr) { uint32_t soa_serial; xfrd_xfr_type* prev; if(dbzone->soa_rrset == NULL || dbzone->soa_rrset->rrs == NULL || dbzone->soa_rrset->rrs[0].rdata_count <= 2 || rdata_atom_size(dbzone->soa_rrset->rrs[0].rdatas[2]) != sizeof(uint32_t)) { make_catalog_consumer_invalid(consumer_zone, "could not apply ixfr on catalog consumer zone " "\'%s\': invalid SOA resource record", consumer_zone->options->name); return; } soa_serial = read_uint32(rdata_atom_data( dbzone->soa_rrset->rrs[0].rdatas[2])); if(soa_serial == xfr->msg_old_serial) goto apply_xfr; for(prev = xfr->prev; prev; prev = prev->prev) { if(!prev->sent) continue; if(xfr->msg_old_serial != prev->msg_new_serial) continue; apply_xfrs_to_consumer_zone(consumer_zone, dbzone, prev); break; } if(!prev || xfr->msg_old_serial != read_uint32(rdata_atom_data( dbzone->soa_rrset->rrs[0].rdatas[2]))){ make_catalog_consumer_invalid(consumer_zone, "could not find and/or apply xfrs for catalog " "consumer zone \'%s\': to update to serial %u", consumer_zone->options->name, xfr->msg_new_serial); return; } } apply_xfr: DEBUG(DEBUG_IPC,1, (LOG_INFO, "apply %sXFR %u -> %u to consumer zone " "\'%s\'", (xfr->msg_is_ixfr ? "I" : "A"), xfr->msg_old_serial, xfr->msg_new_serial, consumer_zone->options->name)); if(!(df = xfrd_open_xfrfile(xfrd->nsd, xfr->xfrfilenumber, "r"))) { make_catalog_consumer_invalid(consumer_zone, "could not open transfer file %lld: %s", (long long)xfr->xfrfilenumber, strerror(errno)); } else if(0 >= apply_ixfr_for_zone(xfrd->nsd, dbzone, df, xfrd->nsd->options, NULL, xfr->xfrfilenumber)) { make_catalog_consumer_invalid(consumer_zone, "error processing transfer file %lld", (long long)xfr->xfrfilenumber); fclose(df); } else { /* Make valid for reprocessing */ make_catalog_consumer_valid(consumer_zone); fclose(df); DEBUG(DEBUG_IPC,1, (LOG_INFO, "%sXFR %u -> %u to consumer zone \'%s\' " "applied", (xfr->msg_is_ixfr ? "I" : "A"), xfr->msg_old_serial, xfr->msg_new_serial, consumer_zone->options->name)); } } static void xfrd_process_soa_info_task(struct task_list_d* task) { xfrd_soa_type soa; xfrd_soa_type* soa_ptr = &soa; xfrd_zone_type* zone; struct xfrd_catalog_producer_zone* producer_zone; struct xfrd_catalog_consumer_zone* consumer_zone = NULL; zone_type* dbzone = NULL; xfrd_xfr_type* xfr; xfrd_xfr_type* prev_xfr; enum soainfo_hint hint; #ifndef NDEBUG time_t before; #endif time_t acquired = 0; DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: process SOAINFO %s", dname_to_string(task->zname, 0))); zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, task->zname); hint = (enum soainfo_hint)task->yesno; if(task->size <= sizeof(struct task_list_d)+dname_total_size( task->zname)+sizeof(uint32_t)*6 + sizeof(uint8_t)*2) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s %s zone", dname_to_string(task->zname,0), hint == soainfo_bad ? "kept" : "lost")); soa_ptr = NULL; /* discard all updates */ #ifndef NDEBUG before = xfrd_time(); #endif } else { uint8_t* p = (uint8_t*)task->zname + dname_total_size( task->zname); /* read the soa info */ memset(&soa, 0, sizeof(soa)); /* left out type, klass, count for speed */ soa.type = htons(TYPE_SOA); soa.klass = htons(CLASS_IN); memmove(&soa.ttl, p, sizeof(uint32_t)); p += sizeof(uint32_t); soa.rdata_count = htons(7); memmove(soa.prim_ns, p, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(soa.prim_ns+1, p, soa.prim_ns[0]); p += soa.prim_ns[0]; memmove(soa.email, p, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(soa.email+1, p, soa.email[0]); p += soa.email[0]; memmove(&soa.serial, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.refresh, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.retry, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.expire, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.minimum, p, sizeof(uint32_t)); /* p += sizeof(uint32_t); if we wanted to read further */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s %u", dname_to_string(task->zname,0), (unsigned)ntohl(soa.serial))); /* discard all updates received before initial reload unless reload was successful */ #ifndef NDEBUG before = xfrd->reload_cmd_first_sent; #endif } if(zone) ; /* pass */ else if((producer_zone = (struct xfrd_catalog_producer_zone*) rbtree_search(xfrd->catalog_producer_zones, task->zname))) { struct xfrd_producer_xfr* pxfr, *next_pxfr; DEBUG(DEBUG_IPC,1, (LOG_INFO, "Zone %s is catalog producer", dname_to_string(task->zname,0))); if(hint != soainfo_ok) producer_zone->axfr = 1; for(pxfr = producer_zone->latest_pxfr; pxfr; pxfr = next_pxfr) { next_pxfr = pxfr->next; DEBUG(DEBUG_IPC,1, (LOG_INFO, "pxfr for zone %s for serial %u", dname_to_string(task->zname,0), pxfr->serial)); if(hint != soainfo_ok) ; /* pass */ else if(!soa_ptr || soa_ptr->serial != htonl(pxfr->serial)) continue; else if(xfrd->reload_failed) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s mark update " "to serial %u verified", producer_zone->options->name, pxfr->serial)); diff_update_commit( producer_zone->options->name, DIFF_VERIFIED, xfrd->nsd, pxfr->xfrfilenumber); return; } DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s delete update to " "serial %u", producer_zone->options->name, pxfr->serial)); xfrd_unlink_xfrfile(xfrd->nsd, pxfr->xfrfilenumber); if((*pxfr->prev_next_ptr = pxfr->next)) pxfr->next->prev_next_ptr = pxfr->prev_next_ptr; region_recycle(xfrd->region, pxfr, sizeof(*pxfr)); notify_handle_master_zone_soainfo(xfrd->notify_zones, task->zname, soa_ptr); } return; } else { DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: zone %s primary zone updated", dname_to_string(task->zname,0))); notify_handle_master_zone_soainfo(xfrd->notify_zones, task->zname, soa_ptr); return; } if(xfrd->nsd->db && xfrd->catalog_consumer_zones #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES && xfrd->catalog_consumer_zones->count == 1 #endif && (consumer_zone = (struct xfrd_catalog_consumer_zone*)rbtree_search( xfrd->catalog_consumer_zones, task->zname))) { dbzone = namedb_find_or_create_zone( xfrd->nsd->db, task->zname , consumer_zone->options); } /* soainfo_gone and soainfo_bad are straightforward, delete all updates that were transfered, i.e. acquired != 0. soainfo_ok is more complicated as it is possible that there are subsequent corrupt or inconsistent updates */ for(xfr = zone->latest_xfr; xfr; xfr = prev_xfr) { prev_xfr = xfr->prev; /* skip incomplete updates */ if(!xfr->acquired) { continue; } if(hint == soainfo_ok) { /* skip non-queued updates */ if(!xfr->sent) continue; assert(xfr->acquired <= before); } if(hint == soainfo_ok && soa_ptr) { /* soa_ptr should be true if soainfo_ok. If no * soa_ptr or soa_info_bad or gone delete all * the transfers. */ /* updates are applied in-order, acquired time of most-recent update is used as baseline */ if(!acquired) { acquired = xfr->acquired; } if(xfrd->reload_failed) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s mark update " "to serial %u verified", zone->apex_str, xfr->msg_new_serial)); diff_update_commit( zone->apex_str, DIFF_VERIFIED, xfrd->nsd, xfr->xfrfilenumber); return; } if(consumer_zone && dbzone && /* Call consumer apply for most recent update*/ (soa_ptr && soa_ptr->serial == htonl(xfr->msg_new_serial))) apply_xfrs_to_consumer_zone( consumer_zone, dbzone, xfr); } DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s delete update to serial %u", zone->apex_str, xfr->msg_new_serial)); xfrd_delete_zone_xfr(zone, xfr); } /* update zone state */ switch(hint) { case soainfo_bad: /* "rollback" on-disk soa information */ zone->soa_disk_acquired = zone->soa_nsd_acquired; zone->soa_disk = zone->soa_nsd; if(xfrd_time() - zone->soa_disk_acquired >= (time_t)ntohl(zone->soa_disk.expire)) { /* zone expired */ xfrd_set_zone_state(zone, xfrd_zone_expired); } /* do not refresh right away, like with corrupt or inconsistent updates, because the zone is likely not fixed on the primary yet. an immediate refresh can therefore potentially trigger an update loop */ xfrd_set_timer_retry(zone); if(zone->soa_notified_acquired != 0 && (zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { /* read was in response to this notification */ zone->soa_notified_acquired = 0; } if(zone->soa_notified_acquired && zone->state == xfrd_zone_ok) { /* refresh because of notification */ xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); } break; case soainfo_ok: if(xfrd->reload_failed) break; /* fall through */ case soainfo_gone: xfrd_handle_incoming_soa(zone, soa_ptr, acquired); break; } } static void xfrd_receive_soa(int socket, int shortsoa) { sig_atomic_t cmd; struct udb_base* xtask = xfrd->nsd->task[xfrd->nsd->mytask]; udb_ptr last_task, t; xfrd_zone_type* zone; if(!shortsoa) { /* put all expired zones into mytask */ udb_ptr_init(&last_task, xtask); RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->state == xfrd_zone_expired) { task_new_expire(xtask, &last_task, zone->apex, 1); } } udb_ptr_unlink(&last_task, xtask); /* send RELOAD to main to give it this tasklist */ task_process_sync(xtask); cmd = NSD_RELOAD; if(!write_socket(socket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending reload xfrdtomain: %s", strerror(errno)); } } /* receive RELOAD_DONE to get SOAINFO tasklist */ if(block_read(&nsd, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD_DONE) { if(nsd.signal_hint_shutdown) return; log_msg(LOG_ERR, "did not get start signal from main"); exit(1); } if(block_read(NULL, socket, &xfrd->reload_pid, sizeof(pid_t), -1) != sizeof(pid_t)) { log_msg(LOG_ERR, "xfrd cannot get reload_pid"); } /* process tasklist (SOAINFO data) */ udb_ptr_unlink(xfrd->last_task, xtask); /* if shortsoa: then use my own taskdb that nsdparent filled */ if(!shortsoa) xfrd->nsd->mytask = 1 - xfrd->nsd->mytask; xtask = xfrd->nsd->task[xfrd->nsd->mytask]; task_remap(xtask); udb_ptr_new(&t, xtask, udb_base_get_userdata(xtask)); while(!udb_ptr_is_null(&t)) { xfrd_process_soa_info_task(TASKLIST(&t)); udb_ptr_set_rptr(&t, xtask, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, xtask); task_clear(xtask); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); if(!shortsoa) { /* receive RELOAD_DONE that signals the other tasklist is * empty, and thus xfrd can operate (can call reload and swap * to the other, empty, tasklist) */ if(block_read(NULL, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD_DONE) { log_msg(LOG_ERR, "did not get start signal 2 from " "main"); exit(1); } } else { /* for shortsoa version, do expire later */ /* if expire notifications, put in my task and * schedule a reload to make sure they are processed */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->state == xfrd_zone_expired) { xfrd_send_expire_notification(zone); } } } } void xfrd_reopen_logfile(void) { if (xfrd->nsd->file_rotation_ok) log_reopen(xfrd->nsd->log_filename, 0); } void xfrd_deactivate_zone(xfrd_zone_type* z) { if(z->is_activated) { /* delete from activated list */ if(z->activated_prev) z->activated_prev->activated_next = z->activated_next; else xfrd->activated_first = z->activated_next; if(z->activated_next) z->activated_next->activated_prev = z->activated_prev; z->is_activated = 0; } } void xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname) { xfrd_zone_type* z = (xfrd_zone_type*)rbtree_delete(xfrd->zones, dname); if(!z) return; /* io */ if(z->tcp_waiting) { /* delete from tcp waiting list */ if(z->tcp_waiting_prev) z->tcp_waiting_prev->tcp_waiting_next = z->tcp_waiting_next; else xfrd->tcp_set->tcp_waiting_first = z->tcp_waiting_next; if(z->tcp_waiting_next) z->tcp_waiting_next->tcp_waiting_prev = z->tcp_waiting_prev; else xfrd->tcp_set->tcp_waiting_last = z->tcp_waiting_prev; z->tcp_waiting = 0; } if(z->udp_waiting) { /* delete from udp waiting list */ if(z->udp_waiting_prev) z->udp_waiting_prev->udp_waiting_next = z->udp_waiting_next; else xfrd->udp_waiting_first = z->udp_waiting_next; if(z->udp_waiting_next) z->udp_waiting_next->udp_waiting_prev = z->udp_waiting_prev; else xfrd->udp_waiting_last = z->udp_waiting_prev; z->udp_waiting = 0; } xfrd_deactivate_zone(z); if(z->tcp_conn != -1) { xfrd_tcp_release(xfrd->tcp_set, z); } else if(z->zone_handler.ev_fd != -1 && z->event_added) { xfrd_udp_release(z); } if(z->event_added) event_del(&z->zone_handler); while(z->latest_xfr) xfrd_delete_zone_xfr(z, z->latest_xfr); /* z->dname is recycled when the zone_options is removed */ region_recycle(xfrd->region, z, sizeof(*z)); } void xfrd_free_namedb(struct nsd* nsd) { namedb_close(nsd->db); nsd->db = 0; } static void xfrd_set_timer_refresh(xfrd_zone_type* zone) { time_t set_refresh; time_t set_expire; time_t set; if(zone->soa_disk_acquired == 0 || zone->state != xfrd_zone_ok) { xfrd_set_timer_retry(zone); return; } /* refresh or expire timeout, whichever is earlier */ set_refresh = bound_soa_disk_refresh(zone); set_expire = bound_soa_disk_expire(zone); set = zone->soa_disk_acquired + ( set_refresh < set_expire ? set_refresh : set_expire ); /* set point in time to period for xfrd_set_timer() */ xfrd_set_timer(zone, within_refresh_bounds(zone, set > xfrd_time() ? set - xfrd_time() : XFRD_LOWERBOUND_REFRESH)); } static void xfrd_set_timer_retry(xfrd_zone_type* zone) { time_t set_retry; time_t set_expire; int mult; /* perform exponential backoff in all the cases */ if(zone->fresh_xfr_timeout == 0) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; else { /* exponential backoff - some master data in zones is paid-for but non-working, and will not get fixed. */ zone->fresh_xfr_timeout *= 2; if(zone->fresh_xfr_timeout > XFRD_TRANSFER_TIMEOUT_MAX) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_MAX; } /* exponential backoff multiplier, starts at 1, backs off */ mult = zone->fresh_xfr_timeout / XFRD_TRANSFER_TIMEOUT_START; if(mult == 0) mult = 1; /* set timer for next retry or expire timeout if earlier. */ if(zone->soa_disk_acquired == 0) { /* if no information, use reasonable timeout * within configured and defined bounds */ xfrd_set_timer(zone, within_retry_bounds(zone, zone->fresh_xfr_timeout + random_generate(zone->fresh_xfr_timeout))); return; } /* exponential backoff within configured and defined bounds */ set_retry = within_retry_bounds(zone, ntohl(zone->soa_disk.retry) * mult); if(zone->state == xfrd_zone_expired) { xfrd_set_timer(zone, set_retry); return; } /* retry or expire timeout, whichever is earlier */ set_expire = zone->soa_disk_acquired + bound_soa_disk_expire(zone); if(xfrd_time() + set_retry < set_expire) { xfrd_set_timer(zone, set_retry); return; } /* Not expired, but next retry will be > than expire timeout. * Retry when the expire timeout runs out. * set_expire is below retry upper bounds (if statement above), * but not necessarily above lower bounds, * so use within_retry_bounds() again. */ xfrd_set_timer(zone, within_retry_bounds(zone, set_expire > xfrd_time() ? set_expire - xfrd_time() : XFRD_LOWERBOUND_RETRY)); } void xfrd_handle_zone(int ATTR_UNUSED(fd), short event, void* arg) { xfrd_zone_type* zone = (xfrd_zone_type*)arg; if(zone->tcp_conn != -1) { if(event == 0) /* activated, but already in TCP, nothing to do*/ return; /* busy in tcp transaction: an internal error */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s event tcp", zone->apex_str)); xfrd_tcp_release(xfrd->tcp_set, zone); /* continue to retry; as if a timeout happened */ event = EV_TIMEOUT; } if((event & EV_READ)) { /* busy in udp transaction */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s event udp read", zone->apex_str)); xfrd_udp_read(zone); return; } /* timeout */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s timeout", zone->apex_str)); if(zone->zone_handler.ev_fd != -1 && zone->event_added && (event & EV_TIMEOUT)) { assert(zone->tcp_conn == -1); xfrd_udp_release(zone); } if(zone->tcp_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s skips retry, TCP connections full", zone->apex_str)); xfrd_unset_timer(zone); return; } if(zone->udp_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s skips retry, UDP connections full", zone->apex_str)); xfrd_unset_timer(zone); return; } if(zone->soa_disk_acquired) { if (zone->state != xfrd_zone_expired && xfrd_time() >= zone->soa_disk_acquired + bound_soa_disk_expire(zone)) { /* zone expired */ log_msg(LOG_ERR, "xfrd: zone %s has expired", zone->apex_str); xfrd_set_zone_state(zone, xfrd_zone_expired); } else if(zone->state == xfrd_zone_ok && xfrd_time() >= zone->soa_disk_acquired + bound_soa_disk_refresh(zone)) { /* zone goes to refreshing state. */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is refreshing", zone->apex_str)); xfrd_set_zone_state(zone, xfrd_zone_refreshing); } } /* only make a new request if no request is running (UDPorTCP) */ if(zone->zone_handler.ev_fd == -1 && zone->tcp_conn == -1) { /* make a new request */ xfrd_make_request(zone); } } void xfrd_make_request(xfrd_zone_type* zone) { if(zone->next_master != -1) { /* we are told to use this next master */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s use primary %i", zone->apex_str, zone->next_master)); zone->master_num = zone->next_master; zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); /* if there is no next master, fallback to use the first one */ if(!zone->master) { zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; } /* fallback to cycle master */ zone->next_master = -1; zone->round_num = 0; /* fresh set of retries after notify */ } else { /* cycle master */ if(zone->round_num != -1 && zone->master && zone->master->next) { /* try the next master */ zone->master = zone->master->next; zone->master_num++; } else { /* start a new round */ zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; zone->round_num++; } if(zone->round_num >= XFRD_MAX_ROUNDS) { /* tried all servers that many times, wait */ zone->round_num = -1; xfrd_set_timer_retry(zone); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s makereq wait_retry, rd %d mr %d nx %d", zone->apex_str, zone->round_num, zone->master_num, zone->next_master)); zone->multi_master_first_master = -1; return; } } /* multi-master-check */ if(zone->zone_options->pattern->multi_primary_check) { if(zone->multi_master_first_master == zone->master_num && zone->round_num > 0 && zone->state != xfrd_zone_expired) { /* tried all servers and update zone */ if(zone->multi_master_update_check >= 0) { VERBOSITY(2, (LOG_INFO, "xfrd: multi primary " "check: zone %s completed transfers", zone->apex_str)); } zone->round_num = -1; /* next try start anew */ zone->multi_master_first_master = -1; xfrd_set_timer_refresh(zone); return; } if(zone->multi_master_first_master < 0) { zone->multi_master_first_master = zone->master_num; zone->multi_master_update_check = -1; } } /* cache ixfr_disabled only for XFRD_NO_IXFR_CACHE time */ if (zone->master->ixfr_disabled && (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= time(NULL)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "clear negative caching ixfr " "disabled for primary %s num " "%d ", zone->master->ip_address_spec, zone->master_num)); zone->master->ixfr_disabled = 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s make request round %d mr %d nx %d", zone->apex_str, zone->round_num, zone->master_num, zone->next_master)); /* perform xfr request */ if (!zone->master->use_axfr_only && zone->soa_disk_acquired > 0 && !zone->master->ixfr_disabled) { if (zone->master->allow_udp) { xfrd_set_timer(zone, XFRD_UDP_TIMEOUT); xfrd_udp_obtain(zone); } else { /* doing 3 rounds of IXFR/TCP might not be useful */ xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } } else if (zone->master->use_axfr_only || zone->soa_disk_acquired <= 0) { xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } else if (zone->master->ixfr_disabled) { if (zone->zone_options->pattern->allow_axfr_fallback) { xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s axfr " "fallback not allowed, skipping primary %s.", zone->apex_str, zone->master->ip_address_spec)); } } } static void xfrd_udp_obtain(xfrd_zone_type* zone) { assert(zone->udp_waiting == 0); if(zone->tcp_conn != -1) { /* no tcp and udp at the same time */ xfrd_tcp_release(xfrd->tcp_set, zone); } if(xfrd->udp_use_num < XFRD_MAX_UDP) { int fd; xfrd->udp_use_num++; fd = xfrd_send_ixfr_request_udp(zone); if(fd == -1) xfrd->udp_use_num--; else { if(zone->event_added) event_del(&zone->zone_handler); memset(&zone->zone_handler, 0, sizeof(zone->zone_handler)); event_set(&zone->zone_handler, fd, EV_PERSIST|EV_READ|EV_TIMEOUT, xfrd_handle_zone, zone); if(event_base_set(xfrd->event_base, &zone->zone_handler) != 0) log_msg(LOG_ERR, "xfrd udp: event_base_set failed"); if(event_add(&zone->zone_handler, &zone->timeout) != 0) log_msg(LOG_ERR, "xfrd udp: event_add failed"); zone->zone_handler_flags=EV_PERSIST|EV_READ|EV_TIMEOUT; zone->event_added = 1; } return; } /* queue the zone as last */ zone->udp_waiting = 1; zone->udp_waiting_next = NULL; zone->udp_waiting_prev = xfrd->udp_waiting_last; if(!xfrd->udp_waiting_first) xfrd->udp_waiting_first = zone; if(xfrd->udp_waiting_last) xfrd->udp_waiting_last->udp_waiting_next = zone; xfrd->udp_waiting_last = zone; xfrd_unset_timer(zone); } time_t xfrd_time() { if(!xfrd->got_time) { xfrd->current_time = time(0); xfrd->got_time = 1; } return xfrd->current_time; } void xfrd_copy_soa(xfrd_soa_type* soa, rr_type* rr) { const uint8_t* rr_ns_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[0]))); uint8_t rr_ns_len = domain_dname(rdata_atom_domain(rr->rdatas[0]))->name_size; const uint8_t* rr_em_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[1]))); uint8_t rr_em_len = domain_dname(rdata_atom_domain(rr->rdatas[1]))->name_size; if(rr->type != TYPE_SOA || rr->rdata_count != 7) { log_msg(LOG_ERR, "xfrd: copy_soa called with bad rr, type %d rrs %u.", rr->type, rr->rdata_count); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: copy_soa rr, type %d rrs %u, ttl %u.", (int)rr->type, (unsigned)rr->rdata_count, (unsigned)rr->ttl)); soa->type = htons(rr->type); soa->klass = htons(rr->klass); soa->ttl = htonl(rr->ttl); soa->rdata_count = htons(rr->rdata_count); /* copy dnames */ soa->prim_ns[0] = rr_ns_len; memcpy(soa->prim_ns+1, rr_ns_wire, rr_ns_len); soa->email[0] = rr_em_len; memcpy(soa->email+1, rr_em_wire, rr_em_len); /* already in network format */ memcpy(&soa->serial, rdata_atom_data(rr->rdatas[2]), sizeof(uint32_t)); memcpy(&soa->refresh, rdata_atom_data(rr->rdatas[3]), sizeof(uint32_t)); memcpy(&soa->retry, rdata_atom_data(rr->rdatas[4]), sizeof(uint32_t)); memcpy(&soa->expire, rdata_atom_data(rr->rdatas[5]), sizeof(uint32_t)); memcpy(&soa->minimum, rdata_atom_data(rr->rdatas[6]), sizeof(uint32_t)); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: copy_soa rr, serial %u refresh %u retry %u expire %u", (unsigned)ntohl(soa->serial), (unsigned)ntohl(soa->refresh), (unsigned)ntohl(soa->retry), (unsigned)ntohl(soa->expire))); } static void xfrd_set_zone_state(xfrd_zone_type* zone, enum xfrd_zone_state s) { if(s != zone->state) { enum xfrd_zone_state old = zone->state; zone->state = s; if((s == xfrd_zone_expired || old == xfrd_zone_expired) && s!=old) { xfrd_send_expire_notification(zone); } } } void xfrd_set_refresh_now(xfrd_zone_type* zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s is activated, state %d", zone->apex_str, zone->state)); if(!zone->is_activated) { /* push onto list */ zone->activated_prev = 0; zone->activated_next = xfrd->activated_first; if(xfrd->activated_first) xfrd->activated_first->activated_prev = zone; xfrd->activated_first = zone; zone->is_activated = 1; } } void xfrd_unset_timer(xfrd_zone_type* zone) { assert(zone->zone_handler.ev_fd == -1); if(zone->event_added) event_del(&zone->zone_handler); zone->zone_handler_flags = 0; zone->event_added = 0; } void xfrd_set_timer(xfrd_zone_type* zone, time_t t) { int fd = zone->zone_handler.ev_fd; int fl = ((fd == -1)?EV_TIMEOUT:zone->zone_handler_flags); if(t > XFRD_TRANSFER_TIMEOUT_MAX) t = XFRD_TRANSFER_TIMEOUT_MAX; /* randomize the time, within 90%-100% of original */ /* not later so zones cannot expire too late */ /* only for times far in the future */ if(t > 10) { time_t base = t*9/10; t = base + random_generate(t-base); } /* keep existing flags and fd, but re-add with timeout */ if(zone->event_added) event_del(&zone->zone_handler); else fd = -1; zone->timeout.tv_sec = t; zone->timeout.tv_usec = 0; memset(&zone->zone_handler, 0, sizeof(zone->zone_handler)); event_set(&zone->zone_handler, fd, fl, xfrd_handle_zone, zone); if(event_base_set(xfrd->event_base, &zone->zone_handler) != 0) log_msg(LOG_ERR, "xfrd timer: event_base_set failed"); if(event_add(&zone->zone_handler, &zone->timeout) != 0) log_msg(LOG_ERR, "xfrd timer: event_add failed"); zone->zone_handler_flags = fl; zone->event_added = 1; } void xfrd_handle_incoming_soa(xfrd_zone_type* zone, xfrd_soa_type* soa, time_t acquired) { time_t seconds_since_acquired; if(soa == NULL) { /* nsd no longer has a zone in memory */ zone->soa_nsd_acquired = 0; zone->soa_disk_acquired = 0; xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); return; } if(zone->soa_nsd_acquired && soa->serial == zone->soa_nsd.serial) return; if(zone->soa_disk_acquired) { int cmp = compare_serial(ntohl(soa->serial), ntohl(zone->soa_disk.serial)); /* soa is from an update if serial equals soa_disk.serial or serial is less than soa_disk.serial and the acquired time is before the reload was first requested */ if(!((cmp == 0) || (cmp < 0 && acquired != 0))) { goto zonefile; } /* acquired time of an update may not match time registered in in soa_disk_acquired as a refresh indicating the current serial may have occurred before the reload finished */ if(cmp == 0) { acquired = zone->soa_disk_acquired; } /* soa in disk has been loaded in memory */ { uint32_t soa_serial, soa_nsd_serial; soa_serial = ntohl(soa->serial); soa_nsd_serial = ntohl(zone->soa_nsd.serial); if (compare_serial(soa_serial, soa_nsd_serial) > 0) log_msg(LOG_INFO, "zone %s serial %"PRIu32" is updated to %"PRIu32, zone->apex_str, soa_nsd_serial, soa_serial); else log_msg(LOG_INFO, "zone %s serial is updated to %"PRIu32, zone->apex_str, soa_serial); } zone->soa_nsd = *soa; zone->soa_nsd_acquired = acquired; xfrd->write_zonefile_needed = 1; seconds_since_acquired = xfrd_time() > zone->soa_disk_acquired ? xfrd_time() - zone->soa_disk_acquired : 0; if(seconds_since_acquired < bound_soa_disk_refresh(zone)) { xfrd_set_zone_state(zone, xfrd_zone_ok); } /* update refresh timers based on disk soa, unless there are pending updates. i.e. serial != soa_disk.serial */ if (cmp == 0) { /* reset exponential backoff, we got a normal timer now */ zone->fresh_xfr_timeout = 0; if(seconds_since_acquired < bound_soa_disk_refresh(zone)) { /* zone ok, wait for refresh time */ zone->round_num = -1; xfrd_set_timer_refresh(zone); } else if(seconds_since_acquired < bound_soa_disk_expire(zone)) { /* zone refreshing */ xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); } if(seconds_since_acquired >= bound_soa_disk_expire(zone)) { /* zone expired */ xfrd_set_zone_state(zone, xfrd_zone_expired); xfrd_set_refresh_now(zone); } if(zone->soa_notified_acquired != 0 && (zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { /* read was in response to this notification */ zone->soa_notified_acquired = 0; } if(zone->soa_notified_acquired && zone->state == xfrd_zone_ok) { /* refresh because of notification */ xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); } } xfrd_send_notify(xfrd->notify_zones, zone->apex, &zone->soa_nsd); return; } zonefile: acquired = xfrd_time(); /* user must have manually provided zone data */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s serial %u from zonefile. refreshing", zone->apex_str, (unsigned)ntohl(soa->serial))); zone->soa_nsd = *soa; zone->soa_disk = *soa; zone->soa_nsd_acquired = acquired; zone->soa_disk_acquired = acquired; if(zone->soa_notified_acquired != 0 && (zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { /* user provided in response to this notification */ zone->soa_notified_acquired = 0; } xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); xfrd_send_notify(xfrd->notify_zones, zone->apex, &zone->soa_nsd); } void xfrd_send_expire_notification(xfrd_zone_type* zone) { task_new_expire(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->apex, zone->state == xfrd_zone_expired); xfrd_set_reload_timeout(); } int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src, socklen_t* srclen) { ssize_t received; /* read the data */ buffer_clear(packet); received = recvfrom(fd, buffer_begin(packet), buffer_remaining(packet), 0, src, srclen); if(received == -1) { log_msg(LOG_ERR, "xfrd: recvfrom failed: %s", strerror(errno)); return 0; } buffer_set_limit(packet, received); return 1; } void xfrd_udp_release(xfrd_zone_type* zone) { assert(zone->udp_waiting == 0); if(zone->event_added) event_del(&zone->zone_handler); if(zone->zone_handler.ev_fd != -1) { close(zone->zone_handler.ev_fd); } zone->zone_handler.ev_fd = -1; zone->zone_handler_flags = 0; zone->event_added = 0; /* see if there are waiting zones */ if(xfrd->udp_use_num == XFRD_MAX_UDP) { while(xfrd->udp_waiting_first) { /* snip off waiting list */ xfrd_zone_type* wz = xfrd->udp_waiting_first; assert(wz->udp_waiting); wz->udp_waiting = 0; xfrd->udp_waiting_first = wz->udp_waiting_next; if(wz->udp_waiting_next) wz->udp_waiting_next->udp_waiting_prev = NULL; if(xfrd->udp_waiting_last == wz) xfrd->udp_waiting_last = NULL; /* see if this zone needs udp connection */ if(wz->tcp_conn == -1) { int fd = xfrd_send_ixfr_request_udp(wz); if(fd != -1) { if(wz->event_added) event_del(&wz->zone_handler); memset(&wz->zone_handler, 0, sizeof(wz->zone_handler)); event_set(&wz->zone_handler, fd, EV_READ|EV_TIMEOUT|EV_PERSIST, xfrd_handle_zone, wz); if(event_base_set(xfrd->event_base, &wz->zone_handler) != 0) log_msg(LOG_ERR, "cannot set event_base for ixfr"); if(event_add(&wz->zone_handler, &wz->timeout) != 0) log_msg(LOG_ERR, "cannot add event for ixfr"); wz->zone_handler_flags = EV_READ|EV_TIMEOUT|EV_PERSIST; wz->event_added = 1; return; } else { /* make this zone do something with * this failure to act */ xfrd_set_refresh_now(wz); } } } } /* no waiting zones */ if(xfrd->udp_use_num > 0) xfrd->udp_use_num--; } /** disable ixfr for master */ void xfrd_disable_ixfr(xfrd_zone_type* zone) { if(!(zone->master->ixfr_disabled && (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= time(NULL))) { /* start new round, with IXFR disabled */ zone->round_num = 0; zone->next_master = zone->master_num; } zone->master->ixfr_disabled = time(NULL); } static void xfrd_udp_read(xfrd_zone_type* zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s read udp data", zone->apex_str)); if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd, NULL, NULL)) { zone->master->bad_xfr_count++; if (zone->master->bad_xfr_count > 2) { xfrd_disable_ixfr(zone); zone->master->bad_xfr_count = 0; } /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); return; } switch(xfrd_handle_received_xfr_packet(zone, xfrd->packet)) { case xfrd_packet_tcp: xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_udp_release(zone); xfrd_tcp_obtain(xfrd->tcp_set, zone); break; case xfrd_packet_transfer: if(zone->zone_options->pattern->multi_primary_check) { xfrd_udp_release(zone); xfrd_make_request(zone); break; } /* fallthrough */ case xfrd_packet_newlease: /* nothing more to do */ assert(zone->round_num == -1); xfrd_udp_release(zone); break; case xfrd_packet_notimpl: xfrd_disable_ixfr(zone); /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_more: case xfrd_packet_drop: /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_bad: default: zone->master->bad_xfr_count++; if (zone->master->bad_xfr_count > 2) { xfrd_disable_ixfr(zone); zone->master->bad_xfr_count = 0; } /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; } } int xfrd_send_udp(struct acl_options* acl, buffer_type* packet, struct acl_options* ifc) { #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif /* INET6 */ int fd, family; /* this will set the remote port to acl->port or TCP_PORT */ socklen_t to_len = xfrd_acl_sockaddr_to(acl, &to); /* get the address family of the remote host */ if(acl->is_ipv6) { #ifdef INET6 family = PF_INET6; #else return -1; #endif /* INET6 */ } else { family = PF_INET; } fd = socket(family, SOCK_DGRAM, IPPROTO_UDP); if(fd == -1) { log_msg(LOG_ERR, "xfrd: cannot create udp socket to %s: %s", acl->ip_address_spec, strerror(errno)); return -1; } /* bind it */ if (!xfrd_bind_local_interface(fd, ifc, acl, 0)) { log_msg(LOG_ERR, "xfrd: cannot bind outgoing interface '%s' to " "udp socket: No matching ip addresses found", ifc->ip_address_spec); close(fd); return -1; } /* send it (udp) */ if(sendto(fd, buffer_current(packet), buffer_remaining(packet), 0, (struct sockaddr*)&to, to_len) == -1) { log_msg(LOG_ERR, "xfrd: sendto %s failed %s", acl->ip_address_spec, strerror(errno)); close(fd); return -1; } return fd; } int xfrd_bind_local_interface(int sockd, struct acl_options* ifc, struct acl_options* acl, int tcp) { #ifdef SO_LINGER struct linger linger = {1, 0}; #endif socklen_t frm_len; #ifdef INET6 struct sockaddr_storage frm; #else struct sockaddr_in frm; #endif /* INET6 */ int ret = 1; if (!ifc) /* no outgoing interface set */ return 1; while (ifc) { if (ifc->is_ipv6 != acl->is_ipv6) { /* check if we have a matching address family */ ifc = ifc->next; continue; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: bind() %s to %s socket", ifc->ip_address_spec, tcp? "tcp":"udp")); ret = 0; frm_len = xfrd_acl_sockaddr_frm(ifc, &frm); if (tcp) { #ifdef SO_REUSEADDR if (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, &frm, frm_len) < 0) { VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt " "SO_REUSEADDR failed: %s", strerror(errno))); } #else VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt SO_REUSEADDR " "failed: SO_REUSEADDR not defined")); #endif /* SO_REUSEADDR */ if (ifc->port != 0) { #ifdef SO_LINGER if (setsockopt(sockd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) < 0) { VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt " "SO_LINGER failed: %s", strerror(errno))); } #else VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt SO_LINGER " "failed: SO_LINGER not defined")); #endif /* SO_LINGER */ } } /* found one */ if(bind(sockd, (struct sockaddr*)&frm, frm_len) >= 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: bind() %s to %s " "socket was successful", ifc->ip_address_spec, tcp? "tcp":"udp")); return 1; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: bind() %s to %s socket" "failed: %s", ifc->ip_address_spec, tcp? "tcp":"udp", strerror(errno))); log_msg(LOG_WARNING, "xfrd: could not bind source address:port to " "socket: %s", strerror(errno)); /* try another */ ifc = ifc->next; } return ret; } void xfrd_tsig_sign_request(buffer_type* packet, tsig_record_type* tsig, struct acl_options* acl) { tsig_algorithm_type* algo; assert(acl->key_options && acl->key_options->tsig_key); algo = tsig_get_algorithm_by_name(acl->key_options->algorithm); if(!algo) { log_msg(LOG_ERR, "tsig unknown algorithm %s", acl->key_options->algorithm); return; } assert(algo); tsig_init_record(tsig, algo, acl->key_options->tsig_key); tsig_init_query(tsig, ID(packet)); tsig_prepare(tsig); tsig_update(tsig, packet, buffer_position(packet)); tsig_sign(tsig); tsig_append_rr(tsig, packet); ARCOUNT_SET(packet, ARCOUNT(packet) + 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "appending tsig to packet")); /* prepare for validating tsigs */ tsig_prepare(tsig); } static int xfrd_send_ixfr_request_udp(xfrd_zone_type* zone) { int fd, apex_compress = 0; /* make sure we have a master to query the ixfr request to */ assert(zone->master); if(zone->tcp_conn != -1) { /* tcp is using the zone_handler.fd */ log_msg(LOG_ERR, "xfrd: %s tried to send udp whilst tcp engaged", zone->apex_str); return -1; } xfrd_setup_packet(xfrd->packet, TYPE_IXFR, CLASS_IN, zone->apex, qid_generate(), &apex_compress); zone->query_id = ID(xfrd->packet); xfrd_prepare_zone_xfr(zone, TYPE_IXFR); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "sent query with ID %d", zone->query_id)); NSCOUNT_SET(xfrd->packet, 1); xfrd_write_soa_buffer(xfrd->packet, zone->apex, &zone->soa_disk, apex_compress); /* if we have tsig keys, sign the ixfr query */ if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request( xfrd->packet, &zone->latest_xfr->tsig, zone->master); } buffer_flip(xfrd->packet); xfrd_set_timer(zone, XFRD_UDP_TIMEOUT); if((fd = xfrd_send_udp(zone->master, xfrd->packet, zone->zone_options->pattern->outgoing_interface)) == -1) return -1; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd sent udp request for ixfr=%u for zone %s to %s", (unsigned)ntohl(zone->soa_disk.serial), zone->apex_str, zone->master->ip_address_spec)); return fd; } static int xfrd_parse_soa_info(buffer_type* packet, xfrd_soa_type* soa) { if(!buffer_available(packet, 10)) return 0; soa->type = htons(buffer_read_u16(packet)); soa->klass = htons(buffer_read_u16(packet)); soa->ttl = htonl(buffer_read_u32(packet)); if(ntohs(soa->type) != TYPE_SOA || ntohs(soa->klass) != CLASS_IN) { return 0; } if(!buffer_available(packet, buffer_read_u16(packet)) /* rdata length */ || !(soa->prim_ns[0] = dname_make_wire_from_packet(soa->prim_ns+1, packet, 1)) || !(soa->email[0] = dname_make_wire_from_packet(soa->email+1, packet, 1))) { return 0; } soa->rdata_count = 7; /* rdata in SOA */ soa->serial = htonl(buffer_read_u32(packet)); soa->refresh = htonl(buffer_read_u32(packet)); soa->retry = htonl(buffer_read_u32(packet)); soa->expire = htonl(buffer_read_u32(packet)); soa->minimum = htonl(buffer_read_u32(packet)); return 1; } /* * Check the RRs in an IXFR/AXFR reply. * returns 0 on error, 1 on correct parseable packet. * done = 1 if the last SOA in an IXFR/AXFR has been seen. * soa then contains that soa info. * (soa contents is modified by the routine) */ static int xfrd_xfr_check_rrs(xfrd_zone_type* zone, buffer_type* packet, size_t count, int *done, xfrd_soa_type* soa, region_type* temp) { /* first RR has already been checked */ uint32_t tmp_serial = 0; uint16_t type, rrlen; size_t i, soapos, mempos; const dname_type* dname; domain_table_type* owners; rdata_atom_type* rdatas; for(i=0; ilatest_xfr->msg_rr_count) { if (*done) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr has " "trailing garbage", zone->apex_str)); return 0; } region_free_all(temp); owners = domain_table_create(temp); /* check the dname for errors */ dname = dname_make_from_packet(temp, packet, 1, 1); if(!dname) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr unable " "to parse owner name", zone->apex_str)); return 0; } if(!buffer_available(packet, 10)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr hdr " "too small", zone->apex_str)); return 0; } soapos = buffer_position(packet); type = buffer_read_u16(packet); (void)buffer_read_u16(packet); /* class */ (void)buffer_read_u32(packet); /* ttl */ rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr pkt " "too small", zone->apex_str)); return 0; } mempos = buffer_position(packet); if(rdata_wireformat_to_rdata_atoms(temp, owners, type, rrlen, packet, &rdatas) == -1) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr unable " "to parse rdata", zone->apex_str)); return 0; } if(type == TYPE_SOA) { /* check the SOAs */ buffer_set_position(packet, soapos); if(!xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "unable to parse soainfo", zone->apex_str)); return 0; } if(zone->latest_xfr->msg_rr_count == 1 && ntohl(soa->serial) != zone->latest_xfr->msg_new_serial) { /* 2nd RR is SOA with lower serial, this is an IXFR */ zone->latest_xfr->msg_is_ixfr = 1; if(!zone->soa_disk_acquired) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "got ixfr but need axfr", zone->apex_str)); return 0; /* got IXFR but need AXFR */ } if(ntohl(soa->serial) != ntohl(zone->soa_disk.serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "bad start serial", zone->apex_str)); return 0; /* bad start serial in IXFR */ } zone->latest_xfr->msg_old_serial = ntohl(soa->serial); tmp_serial = ntohl(soa->serial); } else if(ntohl(soa->serial) == zone->latest_xfr->msg_new_serial) { /* saw another SOA of new serial. */ if(zone->latest_xfr->msg_is_ixfr == 1) { zone->latest_xfr->msg_is_ixfr = 2; /* seen middle SOA in ixfr */ } else { /* 2nd SOA for AXFR or 3rd newSOA for IXFR */ *done = 1; } } else if (zone->latest_xfr->msg_is_ixfr) { /* some additional checks */ if(ntohl(soa->serial) > zone->latest_xfr->msg_new_serial) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "bad middle serial", zone->apex_str)); return 0; /* bad middle serial in IXFR */ } if(ntohl(soa->serial) < tmp_serial) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "serial decreasing not allowed", zone->apex_str)); return 0; /* middle serial decreases in IXFR */ } /* serial ok, update tmp serial */ tmp_serial = ntohl(soa->serial); } } buffer_set_position(packet, mempos); buffer_skip(packet, rrlen); } /* packet seems to have a valid DNS RR structure */ return 1; } static int xfrd_xfr_process_tsig(xfrd_zone_type* zone, buffer_type* packet) { int have_tsig = 0; assert(zone && zone->master && zone->master->key_options && zone->master->key_options->tsig_key && packet); if(!tsig_find_rr(&zone->latest_xfr->tsig, packet)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: malformed tsig RR", zone->apex_str, zone->master->ip_address_spec); return 0; } if(zone->latest_xfr->tsig.status == TSIG_OK) { have_tsig = 1; if (zone->latest_xfr->tsig.error_code != TSIG_ERROR_NOERROR) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: tsig error " "(%s)", zone->apex_str, zone->master->ip_address_spec, tsig_error(zone->latest_xfr->tsig.error_code)); } } if(have_tsig) { /* strip the TSIG resource record off... */ buffer_set_limit(packet, zone->latest_xfr->tsig.position); ARCOUNT_SET(packet, ARCOUNT(packet) - 1); } /* keep running the TSIG hash */ tsig_update(&zone->latest_xfr->tsig, packet, buffer_limit(packet)); if(have_tsig) { if (!tsig_verify(&zone->latest_xfr->tsig)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad tsig signature", zone->apex_str, zone->master->ip_address_spec); return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, from %s: good tsig signature", zone->apex_str, zone->master->ip_address_spec)); /* prepare for next tsigs */ tsig_prepare(&zone->latest_xfr->tsig); } else if(zone->latest_xfr->tsig.updates_since_last_prepare > XFRD_TSIG_MAX_UNSIGNED) { /* we allow a number of non-tsig signed packets */ log_msg(LOG_INFO, "xfrd: zone %s, from %s: too many consecutive " "packets without TSIG", zone->apex_str, zone->master->ip_address_spec); return 0; } if(!have_tsig && zone->latest_xfr->msg_seq_nr == 0) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: no tsig in first packet of reply", zone->apex_str, zone->master->ip_address_spec); return 0; } return 1; } /* parse the received packet. returns xfrd packet result code. */ static enum xfrd_packet_result xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, xfrd_soa_type* soa) { size_t rr_count; size_t qdcount = QDCOUNT(packet); size_t ancount = ANCOUNT(packet), ancount_todo; size_t nscount = NSCOUNT(packet); int done = 0; region_type* tempregion = NULL; assert(zone->master); /* has to be axfr / ixfr reply */ if(!buffer_available(packet, QHEADERSZ)) { log_msg(LOG_INFO, "packet too small"); return xfrd_packet_bad; } /* only check ID in first response message. Could also check that * AA bit and QR bit are set, but not needed. */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "got query with ID %d and %d needed", ID(packet), zone->query_id)); if(ID(packet) != zone->query_id) { log_msg(LOG_ERR, "xfrd: zone %s received bad query id from %s, " "dropped", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } /* check RCODE in all response messages */ if(RCODE(packet) != RCODE_OK) { /* for IXFR failures, do not log unless higher verbosity */ if(!(verbosity < 3 && (RCODE(packet) == RCODE_IMPL || RCODE(packet) == RCODE_FORMAT) && !zone->master->ixfr_disabled && !zone->master->use_axfr_only)) { log_msg(LOG_ERR, "xfrd: zone %s received error code %s from " "%s", zone->apex_str, rcode2str(RCODE(packet)), zone->master->ip_address_spec); } if (RCODE(packet) == RCODE_IMPL || RCODE(packet) == RCODE_FORMAT) { return xfrd_packet_notimpl; } if (RCODE(packet) != RCODE_NOTAUTH) { /* RFC 2845: If NOTAUTH, client should do TSIG checking */ return xfrd_packet_drop; } } /* check TSIG */ if(zone->master->key_options) { if(!xfrd_xfr_process_tsig(zone, packet)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "dropping xfr reply due " "to bad TSIG")); return xfrd_packet_bad; } } if (RCODE(packet) == RCODE_NOTAUTH) { return xfrd_packet_drop; } buffer_skip(packet, QHEADERSZ); if(qdcount > 64 || ancount > 65530 || nscount > 65530) { /* 0 or 1 question section rr, and 64k limits other counts */ DEBUG(DEBUG_XFRD,1, (LOG_ERR, "dropping xfr reply, impossibly " "high record count")); return xfrd_packet_bad; } /* skip question section */ for(rr_count = 0; rr_count < qdcount; ++rr_count) { if (!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad RR in " "question section", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } } if(zone->latest_xfr->msg_rr_count == 0 && ancount == 0) { if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: TC flagged")); return xfrd_packet_tcp; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: too short xfr packet: no " "answer")); /* if IXFR is unknown, fallback to AXFR (if allowed) */ if (nscount == 1) { if(!packet_skip_dname(packet) || !xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "no SOA begins authority section", zone->apex_str, zone->master->ip_address_spec)); return xfrd_packet_bad; } return xfrd_packet_notimpl; } return xfrd_packet_bad; } ancount_todo = ancount; tempregion = region_create(xalloc, free); if(zone->latest_xfr->msg_rr_count == 0) { const dname_type* soaname = dname_make_from_packet(tempregion, packet, 1, 1); if(!soaname) { /* parse failure */ DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "parse error in SOA record", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(dname_compare(soaname, zone->apex) != 0) { /* wrong name */ DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "wrong SOA record", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } /* parse the first RR, see if it is a SOA */ if(!xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "bad SOA rdata", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->state != xfrd_zone_expired /* if expired - accept anything */ && compare_serial(ntohl(soa->serial), ntohl(zone->soa_disk.serial)) < 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s ignoring old serial (%u/%u) from %s", zone->apex_str, ntohl(zone->soa_disk.serial), ntohl(soa->serial), zone->master->ip_address_spec)); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s ignoring old serial (%u/%u) from %s", zone->apex_str, ntohl(zone->soa_disk.serial), ntohl(soa->serial), zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->soa_disk.serial == soa->serial) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s got " "update indicating " "current serial", zone->apex_str)); /* (even if notified) the lease on the current soa is renewed */ zone->soa_disk_acquired = xfrd_time(); if(zone->soa_nsd.serial == soa->serial) zone->soa_nsd_acquired = xfrd_time(); xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", zone->apex_str)); if(zone->zone_options->pattern->multi_primary_check) { region_destroy(tempregion); return xfrd_packet_drop; } if(zone->soa_notified_acquired == 0) { /* not notified or anything, so stop asking around */ zone->round_num = -1; /* next try start a new round */ xfrd_set_timer_refresh(zone); region_destroy(tempregion); return xfrd_packet_newlease; } /* try next master */ region_destroy(tempregion); return xfrd_packet_drop; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "IXFR reply has ok serial (have \ %u, reply %u).", (unsigned)zone->soa_disk_acquired ? ntohl(zone->soa_disk.serial) : 0, (unsigned)ntohl(soa->serial))); /* serial is newer than soa_disk */ if(ancount == 1) { /* single record means it is like a notify */ (void)xfrd_handle_incoming_notify(zone, soa); } else if(zone->soa_notified_acquired && zone->soa_notified.serial && compare_serial(ntohl(zone->soa_notified.serial), ntohl(soa->serial)) < 0) { /* this AXFR/IXFR notifies me that an even newer serial exists */ zone->soa_notified.serial = soa->serial; } zone->latest_xfr->msg_new_serial = ntohl(soa->serial); zone->latest_xfr->msg_rr_count = 1; zone->latest_xfr->msg_is_ixfr = 0; if(zone->soa_disk_acquired) zone->latest_xfr->msg_old_serial = ntohl(zone->soa_disk.serial); else zone->latest_xfr->msg_old_serial = 0; ancount_todo = ancount - 1; } if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s received TC from %s. retry tcp.", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_tcp; } if(zone->tcp_conn == -1 && ancount < 2) { /* too short to be a real ixfr/axfr data transfer: need at */ /* least two RRs in the answer section. */ /* The serial is newer, so try tcp to this master. */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply is short. Try " "tcp anyway.")); region_destroy(tempregion); return xfrd_packet_tcp; } if(!xfrd_xfr_check_rrs(zone, packet, ancount_todo, &done, soa, tempregion)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s sent bad xfr " "reply.", zone->apex_str)); region_destroy(tempregion); return xfrd_packet_bad; } region_destroy(tempregion); if(zone->tcp_conn == -1 && done == 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply incomplete")); return xfrd_packet_bad; } if(done == 0) return xfrd_packet_more; if(zone->master->key_options) { if(zone->latest_xfr->tsig.updates_since_last_prepare != 0) { log_msg(LOG_INFO, "xfrd: last packet of reply has no " "TSIG"); return xfrd_packet_bad; } } return xfrd_packet_transfer; } const char* xfrd_pretty_time(time_t v) { struct tm* tm = localtime(&v); static char buf[64]; if(!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", tm)) snprintf(buf, sizeof(buf), "strftime-err-%u", (unsigned)v); return buf; } static void xfrd_free_zone_xfr(xfrd_zone_type *zone, xfrd_xfr_type *xfr) { if(xfr == zone->latest_xfr) { assert(xfr->next == NULL); if((zone->latest_xfr = xfr->prev) != NULL) zone->latest_xfr->next = NULL; } else { if(xfr->next != NULL) xfr->next->prev = xfr->prev; if(xfr->prev != NULL) xfr->prev->next = xfr->next; } tsig_delete_record(&xfr->tsig, xfrd->region); region_recycle(xfrd->region, xfr, sizeof(*xfr)); } void xfrd_delete_zone_xfr(xfrd_zone_type *zone, xfrd_xfr_type *xfr) { if(xfr->acquired != 0 || xfr->msg_seq_nr != 0) { xfrd_unlink_xfrfile(xfrd->nsd, xfr->xfrfilenumber); } xfrd_free_zone_xfr(zone, xfr); } xfrd_xfr_type * xfrd_prepare_zone_xfr(xfrd_zone_type *zone, uint16_t query_type) { xfrd_xfr_type *xfr; /* old transfer needs to be removed still? */ if(zone->latest_xfr != NULL && !zone->latest_xfr->acquired) { xfrd_delete_zone_xfr(zone, zone->latest_xfr); } xfr = region_alloc_zero(xfrd->region, sizeof(*xfr)); if((xfr->prev = zone->latest_xfr) != NULL) { xfr->prev->next = xfr; } tsig_create_record_custom(&xfr->tsig, NULL, 0, 0, 4); zone->latest_xfr = xfr; xfr->query_type = query_type; return xfr; } enum xfrd_packet_result xfrd_handle_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet) { xfrd_soa_type soa; enum xfrd_packet_result res; uint64_t xfrfile_size; assert(zone->latest_xfr); /* parse and check the packet - see if it ends the xfr */ switch((res=xfrd_parse_received_xfr_packet(zone, packet, &soa))) { case xfrd_packet_more: case xfrd_packet_transfer: /* continue with commit */ break; case xfrd_packet_newlease: return xfrd_packet_newlease; case xfrd_packet_tcp: return xfrd_packet_tcp; case xfrd_packet_notimpl: case xfrd_packet_bad: case xfrd_packet_drop: default: { /* rollback */ if(zone->latest_xfr->msg_seq_nr > 0) { /* do not process xfr - if only one part simply ignore it. */ /* delete file with previous parts of commit */ xfrd_unlink_xfrfile(xfrd->nsd, zone->latest_xfr->xfrfilenumber); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s " "reverted transfer %u from %s", zone->apex_str, zone->latest_xfr->msg_rr_count? (int)zone->latest_xfr->msg_new_serial:0, zone->master->ip_address_spec)); zone->latest_xfr->msg_seq_nr = 0; } else if (res == xfrd_packet_bad) { VERBOSITY(1, (LOG_INFO, "xfrd: zone %s " "bad transfer %u from %s", zone->apex_str, zone->latest_xfr->msg_rr_count? (int)zone->latest_xfr->msg_new_serial:0, zone->master->ip_address_spec)); } if (res == xfrd_packet_notimpl && zone->latest_xfr->query_type == TYPE_IXFR) return res; else return xfrd_packet_bad; } } /* dump reply on disk to diff file */ /* if first part, get new filenumber. Numbers can wrap around, 64bit * is enough so we do not collide with older-transfers-in-progress */ if(zone->latest_xfr->msg_seq_nr == 0) zone->latest_xfr->xfrfilenumber = xfrd->xfrfilenumber++; diff_write_packet(dname_to_string(zone->apex,0), zone->zone_options->pattern->pname, zone->latest_xfr->msg_old_serial, zone->latest_xfr->msg_new_serial, zone->latest_xfr->msg_seq_nr, buffer_begin(packet), buffer_limit(packet), xfrd->nsd, zone->latest_xfr->xfrfilenumber); if(verbosity < 4 || zone->latest_xfr->msg_seq_nr == 0) ; /* pass */ else if((verbosity >= 6) || (verbosity >= 5 && zone->latest_xfr->msg_seq_nr % 1000 == 0) || (verbosity >= 4 && zone->latest_xfr->msg_seq_nr % 10000 == 0)) { VERBOSITY(4, (LOG_INFO, "xfrd: zone %s written received XFR packet %u from %s " "with serial %u to disk", zone->apex_str, zone->latest_xfr->msg_seq_nr, zone->master->ip_address_spec, (int)zone->latest_xfr->msg_new_serial)); } zone->latest_xfr->msg_seq_nr++; xfrfile_size = xfrd_get_xfrfile_size( xfrd->nsd, zone->latest_xfr->xfrfilenumber); if( zone->zone_options->pattern->size_limit_xfr != 0 && xfrfile_size > zone->zone_options->pattern->size_limit_xfr ) { /* xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); xfrd_set_reload_timeout(); */ log_msg(LOG_INFO, "xfrd : transferred zone data was too large %llu", (long long unsigned)xfrfile_size); return xfrd_packet_bad; } if(res == xfrd_packet_more) { /* wait for more */ return xfrd_packet_more; } /* done. we are completely sure of this */ buffer_clear(packet); buffer_printf(packet, "received update to serial %u at %s from %s", (unsigned)zone->latest_xfr->msg_new_serial, xfrd_pretty_time(xfrd_time()), zone->master->ip_address_spec); if(zone->master->key_options) { buffer_printf(packet, " TSIG verified with key %s", zone->master->key_options->name); } buffer_flip(packet); diff_write_commit(zone->apex_str, zone->latest_xfr->msg_old_serial, zone->latest_xfr->msg_new_serial, zone->latest_xfr->msg_seq_nr, 1, (char*)buffer_begin(packet), xfrd->nsd, zone->latest_xfr->xfrfilenumber); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s committed \"%s\"", zone->apex_str, (char*)buffer_begin(packet))); /* now put apply_xfr task on the tasklist if no reload in progress */ if(xfrd->can_send_reload && task_new_apply_xfr( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->apex, zone->latest_xfr->msg_old_serial, zone->latest_xfr->msg_new_serial, zone->latest_xfr->xfrfilenumber)) { zone->latest_xfr->sent = xfrd->nsd->mytask + 1; } /* reset msg seq nr, so if that is nonnull we know xfr file exists */ zone->latest_xfr->msg_seq_nr = 0; /* update the disk serial no. */ zone->soa_disk_acquired = zone->latest_xfr->acquired = xfrd_time(); zone->soa_disk = soa; if(zone->soa_notified_acquired && ( zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { zone->soa_notified_acquired = 0; } if(!zone->soa_notified_acquired) { /* do not set expired zone to ok: * it would cause nsd to start answering * bad data, since the zone is not loaded yet. * if nsd does not reload < retry time, more * queries (for even newer versions) are made. * For expired zone after reload it is set ok (SOAINFO ipc). */ if(zone->state != xfrd_zone_expired) xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is waiting for reload", zone->apex_str)); if(zone->zone_options->pattern->multi_primary_check) { zone->multi_master_update_check = zone->master_num; xfrd_set_reload_timeout(); return xfrd_packet_transfer; } zone->round_num = -1; /* next try start anew */ xfrd_set_timer_refresh(zone); xfrd_set_reload_timeout(); return xfrd_packet_transfer; } else { /* try to get an even newer serial */ /* pretend it was bad to continue queries */ xfrd_set_reload_timeout(); return xfrd_packet_bad; } } static void xfrd_set_reload_timeout() { if(xfrd->nsd->options->xfrd_reload_timeout == -1) return; /* automatic reload disabled. */ if(xfrd->reload_timeout.tv_sec == 0 || xfrd_time() >= (time_t)xfrd->reload_timeout.tv_sec ) { /* no reload wait period (or it passed), do it right away */ xfrd_set_reload_now(xfrd); /* start reload wait period */ xfrd->reload_timeout.tv_sec = xfrd_time() + xfrd->nsd->options->xfrd_reload_timeout; xfrd->reload_timeout.tv_usec = 0; return; } /* cannot reload now, set that after the timeout a reload has to happen */ if(xfrd->reload_added == 0) { struct timeval tv; tv.tv_sec = xfrd->reload_timeout.tv_sec - xfrd_time(); tv.tv_usec = 0; if(tv.tv_sec > xfrd->nsd->options->xfrd_reload_timeout) tv.tv_sec = xfrd->nsd->options->xfrd_reload_timeout; memset(&xfrd->reload_handler, 0, sizeof(xfrd->reload_handler)); event_set(&xfrd->reload_handler, -1, EV_TIMEOUT, xfrd_handle_reload, xfrd); if(event_base_set(xfrd->event_base, &xfrd->reload_handler) != 0) log_msg(LOG_ERR, "cannot set reload event base"); if(event_add(&xfrd->reload_handler, &tv) != 0) log_msg(LOG_ERR, "cannot add reload event"); xfrd->reload_added = 1; } } static void xfrd_handle_reload(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { /* reload timeout */ assert(event & EV_TIMEOUT); (void)event; /* timeout wait period after this request is sent */ xfrd->reload_added = 0; xfrd->reload_timeout.tv_sec = xfrd_time() + xfrd->nsd->options->xfrd_reload_timeout; xfrd_set_reload_now(xfrd); } void xfrd_handle_notify_and_start_xfr(xfrd_zone_type* zone, xfrd_soa_type* soa) { if(xfrd_handle_incoming_notify(zone, soa)) { if(zone->zone_handler.ev_fd == -1 && zone->tcp_conn == -1 && !zone->tcp_waiting && !zone->udp_waiting) { xfrd_set_refresh_now(zone); } /* zones with no content start expbackoff again; this is also * for nsd-control started transfer commands, and also when * the master apparently sends notifies (is back up) */ if(zone->soa_disk_acquired == 0) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; } } void xfrd_handle_passed_packet(buffer_type* packet, int acl_num, int acl_num_xfr) { uint8_t qnamebuf[MAXDOMAINLEN]; uint16_t qtype, qclass; const dname_type* dname; region_type* tempregion = region_create(xalloc, free); xfrd_zone_type* zone; buffer_skip(packet, QHEADERSZ); if(!packet_read_query_section(packet, qnamebuf, &qtype, &qclass)) { region_destroy(tempregion); return; /* drop bad packet */ } dname = dname_make(tempregion, qnamebuf, 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: got passed packet for %s, acl " "%d", dname_to_string(dname,0), acl_num)); /* find the zone */ zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, dname); if(!zone) { /* this could be because the zone has been deleted meanwhile */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: incoming packet for " "unknown zone %s", dname_to_string(dname,0))); region_destroy(tempregion); return; /* drop packet for unknown zone */ } region_destroy(tempregion); /* handle */ if(OPCODE(packet) == OPCODE_NOTIFY) { xfrd_soa_type soa; int have_soa = 0; int next; /* get serial from a SOA */ if(ANCOUNT(packet) == 1 && packet_skip_dname(packet) && xfrd_parse_soa_info(packet, &soa)) { have_soa = 1; } xfrd_handle_notify_and_start_xfr(zone, have_soa?&soa:NULL); /* First, see if our notifier has a match in provide-xfr */ if (acl_find_num(zone->zone_options->pattern->request_xfr, acl_num_xfr)) next = acl_num_xfr; else /* If not, find master that matches notifiers ACL entry */ next = find_same_master_notify(zone, acl_num); if(next != -1) { zone->next_master = next; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: notify set next primary to query %d", next)); } } else { /* ignore other types of messages */ } } static int xfrd_handle_incoming_notify(xfrd_zone_type* zone, xfrd_soa_type* soa) { if(soa && zone->soa_disk_acquired && zone->state != xfrd_zone_expired && compare_serial(ntohl(soa->serial),ntohl(zone->soa_disk.serial)) <= 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: ignored notify %s %u old serial, zone valid " "(soa disk serial %u)", zone->apex_str, (unsigned)ntohl(soa->serial), (unsigned)ntohl(zone->soa_disk.serial))); return 0; /* ignore notify with old serial, we have a valid zone */ } if(soa == 0) { zone->soa_notified.serial = 0; } else if (zone->soa_notified_acquired == 0 || zone->soa_notified.serial == 0 || compare_serial(ntohl(soa->serial), ntohl(zone->soa_notified.serial)) > 0) { zone->soa_notified = *soa; } zone->soa_notified_acquired = xfrd_time(); if(zone->state == xfrd_zone_ok) { xfrd_set_zone_state(zone, xfrd_zone_refreshing); } /* transfer right away */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Handle incoming notify for zone %s", zone->apex_str)); return 1; } static int find_same_master_notify(xfrd_zone_type* zone, int acl_num_nfy) { struct acl_options* nfy_acl = acl_find_num(zone->zone_options->pattern-> allow_notify, acl_num_nfy); int num = 0; struct acl_options* master = zone->zone_options->pattern->request_xfr; if(!nfy_acl) return -1; while(master) { if(acl_addr_matches_host(nfy_acl, master)) return num; master = master->next; num++; } return -1; } void xfrd_check_failed_updates(void) { /* see if updates have not come through */ xfrd_zone_type* zone; xfrd_xfr_type* xfr; xfrd_xfr_type* prev_xfr; uint8_t sent = (xfrd->nsd->mytask == 0) + 1; RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { /* skip zones without updates */ if(!zone->latest_xfr) continue; xfr = zone->latest_xfr; while(!xfr->sent && xfr->prev) { xfr = xfr->prev; } /* zone has sent update and no (or different) nsd soa, the update must be corrupt */ if(xfr->sent == sent && (zone->soa_nsd_acquired == 0 || zone->soa_nsd.serial != htonl(xfr->msg_new_serial))) { xfrd_soa_type soa; soa.serial = htonl(xfr->msg_new_serial); log_msg(LOG_ERR, "xfrd: zone %s: soa serial %u update " "failed, restarting transfer " "(notified zone)", zone->apex_str, xfr->msg_new_serial); /* revert the soa; it has not been acquired properly */ if(xfr->acquired == zone->soa_nsd_acquired) { /* this was the same as served, * perform force_axfr , re-download * same serial from master */ zone->soa_disk_acquired = 0; zone->soa_nsd_acquired = 0; } else { /* revert soa to the one in server */ zone->soa_disk_acquired = zone->soa_nsd_acquired; zone->soa_disk = zone->soa_nsd; } /* fabricate soa and trigger notify to refetch and * reload update */ memset(&soa, 0, sizeof(soa)); soa.serial = htonl(xfr->msg_new_serial); xfrd_handle_incoming_notify(zone, &soa); xfrd_set_timer_refresh(zone); /* delete all pending updates */ for(xfr = zone->latest_xfr; xfr; xfr = prev_xfr) { prev_xfr = xfr->prev; /* skip incomplete updates */ if(!xfr->acquired) continue; DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s delete " "update to serial %u", zone->apex_str, xfr->msg_new_serial)); xfrd_delete_zone_xfr(zone, xfr); } } } } void xfrd_prepare_zones_for_reload(void) { xfrd_zone_type* zone; xfrd_xfr_type* xfr; int reload, send; send = 1; reload = 0; RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { xfr = zone->latest_xfr; while(xfr) { if(!xfr->prev) break; xfr = xfr->prev; assert(xfr->acquired); } while(xfr && xfr->acquired) { /* skip updates that arrived after failed reload */ if(xfrd->reload_cmd_first_sent && !xfr->sent) break; assert(!xfrd->reload_cmd_first_sent || xfrd->reload_cmd_first_sent >= xfr->acquired); if(send) { send = task_new_apply_xfr( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->apex, xfr->msg_old_serial, xfr->msg_new_serial, xfr->xfrfilenumber); if(send && !reload) { reload = 1; xfrd_set_reload_timeout(); } } xfr->sent = send ? 1 + xfrd->nsd->mytask : 0; xfr = xfr->next; } } } struct buffer* xfrd_get_temp_buffer() { return xfrd->packet; } #ifdef USE_ZONE_STATS /** process zonestat inc task */ static void xfrd_process_zonestat_inc_task(xfrd_state_type* xfrd, struct task_list_d* task) { xfrd->zonestat_safe = (unsigned)task->oldserial; zonestat_remap(xfrd->nsd, 0, xfrd->zonestat_safe*sizeof(struct nsdst)); xfrd->nsd->zonestatsize[0] = xfrd->zonestat_safe; zonestat_remap(xfrd->nsd, 1, xfrd->zonestat_safe*sizeof(struct nsdst)); xfrd->nsd->zonestatsize[1] = xfrd->zonestat_safe; } #endif /* USE_ZONE_STATS */ static void xfrd_handle_taskresult(xfrd_state_type* xfrd, struct task_list_d* task) { #ifndef USE_ZONE_STATS (void)xfrd; #endif switch(task->task_type) { case task_soa_info: xfrd_process_soa_info_task(task); break; #ifdef USE_ZONE_STATS case task_zonestat_inc: xfrd_process_zonestat_inc_task(xfrd, task); break; #endif default: log_msg(LOG_WARNING, "unhandled task result in xfrd from " "reload type %d", (int)task->task_type); } } void xfrd_process_task_result(xfrd_state_type* xfrd, struct udb_base* taskudb) { udb_ptr t; /* remap it for usage */ task_remap(taskudb); /* process the task-results in the taskudb */ udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); while(!udb_ptr_is_null(&t)) { xfrd_handle_taskresult(xfrd, TASKLIST(&t)); udb_ptr_set_rptr(&t, taskudb, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, taskudb); /* clear the udb so it can be used by xfrd to make new tasks for * reload, this happens when the reload signal is sent, and thus * the taskudbs are swapped */ task_clear(taskudb); #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif } void xfrd_set_reload_now(xfrd_state_type* xfrd) { #ifdef HAVE_SYSTEMD sd_notify(0, "RELOADING=1"); #endif xfrd->need_to_send_reload = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } static void xfrd_handle_write_timer(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { /* timeout for write events */ assert(event & EV_TIMEOUT); (void)event; if(xfrd->nsd->options->zonefiles_write == 0) return; /* call reload to write changed zonefiles */ if(!xfrd->write_zonefile_needed) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "zonefiles write timer (nothing)")); xfrd_write_timer_set(); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "zonefiles write timer")); task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, NULL); xfrd_set_reload_now(xfrd); xfrd->write_zonefile_needed = 0; xfrd_write_timer_set(); } static void xfrd_write_timer_set() { struct timeval tv; if(xfrd->nsd->options->zonefiles_write == 0) return; tv.tv_sec = xfrd->nsd->options->zonefiles_write; tv.tv_usec = 0; memset(&xfrd->write_timer, 0, sizeof(xfrd->write_timer)); event_set(&xfrd->write_timer, -1, EV_TIMEOUT, xfrd_handle_write_timer, xfrd); if(event_base_set(xfrd->event_base, &xfrd->write_timer) != 0) log_msg(LOG_ERR, "xfrd write timer: event_base_set failed"); if(event_add(&xfrd->write_timer, &tv) != 0) log_msg(LOG_ERR, "xfrd write timer: event_add failed"); } static void xfrd_handle_child_timer(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { assert(event & EV_TIMEOUT); (void)event; /* only used to wakeup the process to reap children, note the * event is no longer registered */ xfrd->child_timer_added = 0; } nsd-4.12.0/xfrd-tcp.h0000644000175000017500000002023515002373054013677 0ustar mozziemozzie/* * xfrd-tcp.h - XFR (transfer) Daemon TCP system header file. Manages tcp conn. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_TCP_H #define XFRD_TCP_H #include "xfrd.h" #ifdef HAVE_TLS_1_3 #include #endif struct buffer; struct xfrd_zone; struct xfrd_soa; struct xfrd_state; struct region; struct dname; struct acl_options; struct xfrd_tcp_pipeline; typedef struct xfrd_tcp xfrd_tcp_type; typedef struct xfrd_tcp_set xfrd_tcp_set_type; /* * A set of xfrd tcp connections. */ struct xfrd_tcp_set { /* tcp connections, array, each has packet and read/wr state */ struct xfrd_tcp_pipeline **tcp_state; /* max number of tcp connections, size of tcp_state array */ int tcp_max; /* max number of simultaneous connections on a tcp_pipeline */ int tcp_pipeline; /* number of TCP connections in use. */ int tcp_count; /* TCP timeout. */ int tcp_timeout; /* rbtree with pipelines sorted by master */ rbtree_type* pipetree; #ifdef HAVE_TLS_1_3 /* XoT: SSL context */ SSL_CTX* ssl_ctx; #endif /* double linked list of zones waiting for a TCP connection */ struct xfrd_zone *tcp_waiting_first, *tcp_waiting_last; }; /* * Structure to keep track of an open tcp connection * The xfrd tcp connection is used to first make a request * Then to receive the answer packet(s). */ struct xfrd_tcp { /* tcp connection state */ /* state: reading or writing */ uint8_t is_reading; /* how many bytes have been read/written - total, incl. tcp length bytes */ uint32_t total_bytes; /* msg len bytes */ uint16_t msglen; /* fd of connection. -1 means unconnected */ int fd; /* packet buffer of connection */ struct buffer* packet; }; /* use illegal pointer value to denote skipped ID number. * if this does not work, we can allocate with malloc */ #define TCP_NULL_SKIP ((struct xfrd_zone*)-1) /** * The per-id zone pointers, with TCP_NULL_SKIP or a zone pointer for the * ID value. */ struct xfrd_tcp_pipeline_id { /** rbtree node as first member, this is the key. */ rbnode_type node; /** the ID of this member */ uint16_t id; /** zone pointer or TCP_NULL_SKIP */ struct xfrd_zone* zone; /** next free in free list */ struct xfrd_tcp_pipeline_id* next_free; }; /** * The tcp pipeline key structure. By ip_len, ip, num_unused and unique by * pointer value. */ struct xfrd_tcp_pipeline_key { /* the rbtree node, sorted by IP and nr of unused queries */ rbnode_type node; /* destination IP address */ #ifdef INET6 struct sockaddr_storage ip; #else struct sockaddr_in ip; #endif /* INET6 */ socklen_t ip_len; /* number of unused IDs. used IDs are waiting to send their query, * or have been sent but not not all answer packets have been received. * Sorted by num_unused, so a lookup smaller-equal for 65536 finds the * connection to that master that has the most free IDs. */ int num_unused; /* number of skip-set IDs (these are 'in-use') */ int num_skip; }; /** * Structure to keep track of a pipelined set of queries on * an open tcp connection. The queries may be answered with * interleaved answer packets, the ID number disambiguates. * Sorted by the master IP address so you can use lookup with * smaller-or-equal to find the tcp connection most suitable. */ struct xfrd_tcp_pipeline { /* the key information for the tcp pipeline, in its own * struct so it can be referenced on its own for comparison funcs */ struct xfrd_tcp_pipeline_key key; int handler_added; /* the event handler for this pipe (it'll disambiguate by ID) */ struct event handler; /* the tcp connection to use for reading */ struct xfrd_tcp* tcp_r; /* the tcp connection to use for writing, if it is done successfully, * then the first zone from the sendlist can be removed. */ struct xfrd_tcp* tcp_w; /* once a byte has been written, handshake complete */ int connection_established; #ifdef HAVE_TLS_1_3 /* XoT: SSL object */ SSL *ssl; /* XoT: if SSL handshake is not done, handshake_want indicates the * last error. This may be SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE * when the handshake is still in progress. */ int handshake_want; /* XoT: 1 if the SSL handshake has succeeded, 0 otherwise */ int handshake_done; #endif /* list of queries that want to send, first to get write event, * if NULL, no write event interest */ struct xfrd_zone* tcp_send_first, *tcp_send_last; /* size of the id and unused arrays. */ int pipe_num; /* list of free xfrd_tcp_pipeline_id nodes, these are not in the * zone_per_id tree. preallocated at pipe_num amount. */ struct xfrd_tcp_pipeline_id* pipe_id_free_list; /* The xfrd_zone pointers, per id number. * The key is struct xfrd_tcp_pipeline_id. * per-ID number the queries that have this ID number, every * query owns one ID numbers (until it is done). NULL: unused * When a query is done but not all answer-packets have been * consumed for that ID number, the rest is skipped, this * is denoted with the pointer-value TCP_NULL_SKIP, the ids that * are skipped are not on the unused list. They may be * removed once the last answer packet is skipped. * pipe_num-num_unused values are in the tree (either * a zone pointer or SKIP) */ rbtree_type* zone_per_id; /* Array of uint16_t, with ID values. * unused ID numbers; the first part of the array contains the IDs */ uint16_t* unused; }; /* create set of tcp connections */ struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle, int tcp_max, int tcp_pipeline); /* init tcp state */ struct xfrd_tcp* xfrd_tcp_create(struct region* region, size_t bufsize); /* obtain tcp connection for a zone (or wait) */ void xfrd_tcp_obtain(struct xfrd_tcp_set* set, struct xfrd_zone* zone); /* release tcp connection for a zone (starts waiting) */ void xfrd_tcp_release(struct xfrd_tcp_set* set, struct xfrd_zone* zone); /* release tcp pipe entirely (does not stop the zones inside it) */ void xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, int conn); /* use tcp connection to start xfr */ void xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* initialize tcp_state for a zone. Opens the connection. true on success.*/ int xfrd_tcp_open(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* read data from tcp, maybe partial read */ void xfrd_tcp_read(struct xfrd_tcp_pipeline* tp); /* write data to tcp, maybe a partial write */ void xfrd_tcp_write(struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* handle tcp pipe events */ void xfrd_handle_tcp_pipe(int fd, short event, void* arg); /* * Read from a stream connection (size16)+packet into buffer. * returns value is * -1 on error. * 0 on short read, call back later. * 1 on completed read. * On first call, make sure total_bytes = 0, msglen=0, buffer_clear(). * and the packet and fd need to be set. */ int conn_read(struct xfrd_tcp* conn); /* * Write to a stream connection (size16)+packet. * return value is * -1 on error. 0 on short write, call back later. 1 completed write. * On first call, make sure total_bytes=0, msglen=buffer_limit(), * buffer_flipped(). packet and fd need to be set. */ int conn_write(struct xfrd_tcp* conn); /* setup DNS packet for a query of this type */ void xfrd_setup_packet(struct buffer* packet, uint16_t type, uint16_t klass, const struct dname* dname, uint16_t qid, int* apex_compress); /* write soa in network format to the packet buffer */ void xfrd_write_soa_buffer(struct buffer* packet, const struct dname* apex, struct xfrd_soa* soa, int apex_compress); /* use acl address to setup sockaddr struct, returns length of addr. */ socklen_t xfrd_acl_sockaddr_to(struct acl_options* acl, #ifdef INET6 struct sockaddr_storage *to); #else struct sockaddr_in *to); #endif /* INET6 */ socklen_t xfrd_acl_sockaddr_frm(struct acl_options* acl, #ifdef INET6 struct sockaddr_storage *frm); #else struct sockaddr_in *frm); #endif /* INET6 */ /* create pipeline tcp structure */ struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region, int tcp_pipeline); /* pick num uint16_t values, from 0..max-1, store in array */ void pick_id_values(uint16_t* array, int num, int max); #endif /* XFRD_TCP_H */ nsd-4.12.0/xfrd-tcp.c0000644000175000017500000013715515002373054013704 0ustar mozziemozzie/* * xfrd-tcp.c - XFR (transfer) Daemon TCP system source file. Manages tcp conn. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "nsd.h" #include "xfrd-tcp.h" #include "buffer.h" #include "packet.h" #include "dname.h" #include "options.h" #include "namedb.h" #include "xfrd.h" #include "xfrd-disk.h" #include "util.h" #ifdef HAVE_TLS_1_3 #include #include #endif #ifdef HAVE_TLS_1_3 void log_crypto_err(const char* str); /* in server.c */ static SSL_CTX* create_ssl_context() { SSL_CTX *ctx; unsigned char protos[] = { 3, 'd', 'o', 't' }; ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) { log_msg(LOG_ERR, "xfrd tls: Unable to create SSL ctxt"); } else if (SSL_CTX_set_default_verify_paths(ctx) != 1) { SSL_CTX_free(ctx); log_msg(LOG_ERR, "xfrd tls: Unable to set default SSL verify paths"); return NULL; } /* Only trust 1.3 as per the specification */ else if (!SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION)) { SSL_CTX_free(ctx); log_msg(LOG_ERR, "xfrd tls: Unable to set minimum TLS version 1.3"); return NULL; } if (SSL_CTX_set_alpn_protos(ctx, protos, sizeof(protos)) != 0) { SSL_CTX_free(ctx); log_msg(LOG_ERR, "xfrd tls: Unable to set ALPN protocols"); return NULL; } return ctx; } static int tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); int depth = X509_STORE_CTX_get_error_depth(ctx); // report the specific cert error here - will need custom verify code if // SPKI pins are supported if (!preverify_ok) log_msg(LOG_ERR, "xfrd tls: TLS verify failed - (%d) depth: %d error: %s", err, depth, X509_verify_cert_error_string(err)); return preverify_ok; } static int setup_ssl(struct xfrd_tcp_pipeline* tp, struct xfrd_tcp_set* tcp_set, const char* auth_domain_name) { if (!tcp_set->ssl_ctx) { log_msg(LOG_ERR, "xfrd tls: No TLS CTX, cannot set up XFR-over-TLS"); return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: setting up TLS for tls_auth domain name %s", auth_domain_name)); tp->ssl = SSL_new((SSL_CTX*)tcp_set->ssl_ctx); if(!tp->ssl) { log_msg(LOG_ERR, "xfrd tls: Unable to create TLS object"); return 0; } SSL_set_connect_state(tp->ssl); (void)SSL_set_mode(tp->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(tp->ssl, tp->tcp_w->fd)) { log_msg(LOG_ERR, "xfrd tls: Unable to set TLS fd"); SSL_free(tp->ssl); tp->ssl = NULL; return 0; } SSL_set_verify(tp->ssl, SSL_VERIFY_PEER, tls_verify_callback); if(!SSL_set1_host(tp->ssl, auth_domain_name)) { log_msg(LOG_ERR, "xfrd tls: TLS setting of hostname %s failed", auth_domain_name); SSL_free(tp->ssl); tp->ssl = NULL; return 0; } return 1; } static int ssl_handshake(struct xfrd_tcp_pipeline* tp) { int ret; ERR_clear_error(); ret = SSL_do_handshake(tp->ssl); if(ret == 1) { DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: TLS handshake successful")); tp->handshake_done = 1; return 1; } tp->handshake_want = SSL_get_error(tp->ssl, ret); if(tp->handshake_want == SSL_ERROR_WANT_READ || tp->handshake_want == SSL_ERROR_WANT_WRITE) return 1; return 0; } int password_cb(char *buf, int size, int ATTR_UNUSED(rwflag), void *u) { strlcpy(buf, (char*)u, size); return strlen(buf); } #endif /* sort tcppipe, first on IP address, for an IPaddresss, sort on num_unused */ static int xfrd_pipe_cmp(const void* a, const void* b) { const struct xfrd_tcp_pipeline* x = (struct xfrd_tcp_pipeline*)a; const struct xfrd_tcp_pipeline* y = (struct xfrd_tcp_pipeline*)b; int r; if(x == y) return 0; if(y->key.ip_len != x->key.ip_len) /* subtraction works because nonnegative and small numbers */ return (int)y->key.ip_len - (int)x->key.ip_len; r = memcmp(&x->key.ip, &y->key.ip, x->key.ip_len); if(r != 0) return r; /* sort that num_unused is sorted ascending, */ if(x->key.num_unused != y->key.num_unused) { return (x->key.num_unused < y->key.num_unused) ? -1 : 1; } /* different pipelines are different still, even with same numunused*/ return (uintptr_t)x < (uintptr_t)y ? -1 : 1; } struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle, int tcp_max, int tcp_pipeline) { int i; struct xfrd_tcp_set* tcp_set = region_alloc(region, sizeof(struct xfrd_tcp_set)); memset(tcp_set, 0, sizeof(struct xfrd_tcp_set)); tcp_set->tcp_state = NULL; tcp_set->tcp_max = tcp_max; tcp_set->tcp_pipeline = tcp_pipeline; tcp_set->tcp_count = 0; tcp_set->tcp_waiting_first = 0; tcp_set->tcp_waiting_last = 0; #ifdef HAVE_TLS_1_3 /* Set up SSL context */ tcp_set->ssl_ctx = create_ssl_context(); if (tcp_set->ssl_ctx == NULL) log_msg(LOG_ERR, "xfrd: XFR-over-TLS not available"); else if (tls_cert_bundle && tls_cert_bundle[0] && SSL_CTX_load_verify_locations( tcp_set->ssl_ctx, tls_cert_bundle, NULL) != 1) { log_msg(LOG_ERR, "xfrd tls: Unable to set the certificate bundle file %s", tls_cert_bundle); } #else (void)tls_cert_bundle; log_msg(LOG_INFO, "xfrd: No TLS 1.3 support - XFR-over-TLS not available"); #endif tcp_set->tcp_state = region_alloc(region, sizeof(*tcp_set->tcp_state)*tcp_set->tcp_max); for(i=0; itcp_max; i++) tcp_set->tcp_state[i] = xfrd_tcp_pipeline_create(region, tcp_pipeline); tcp_set->pipetree = rbtree_create(region, &xfrd_pipe_cmp); return tcp_set; } static int pipeline_id_compare(const void* x, const void* y) { struct xfrd_tcp_pipeline_id* a = (struct xfrd_tcp_pipeline_id*)x; struct xfrd_tcp_pipeline_id* b = (struct xfrd_tcp_pipeline_id*)y; if(a->id < b->id) return -1; if(a->id > b->id) return 1; return 0; } void pick_id_values(uint16_t* array, int num, int max) { uint8_t inserted[65536]; int j, done; if(num == 65536) { /* all of them, loop and insert */ int i; for(i=0; ileft); node->left = NULL; clear_pipeline_entry(tp, node->right); node->right = NULL; /* move the node into the free list */ n = (struct xfrd_tcp_pipeline_id*)node; n->next_free = tp->pipe_id_free_list; tp->pipe_id_free_list = n; } static void xfrd_tcp_pipeline_cleanup(struct xfrd_tcp_pipeline* tp) { /* move entries into free list */ clear_pipeline_entry(tp, tp->zone_per_id->root); /* clear the tree */ tp->zone_per_id->count = 0; tp->zone_per_id->root = RBTREE_NULL; } static void xfrd_tcp_pipeline_init(struct xfrd_tcp_pipeline* tp) { tp->key.node.key = tp; tp->key.num_unused = tp->pipe_num; tp->key.num_skip = 0; tp->tcp_send_first = NULL; tp->tcp_send_last = NULL; xfrd_tcp_pipeline_cleanup(tp); pick_id_values(tp->unused, tp->pipe_num, 65536); } struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region, int tcp_pipeline) { int i; struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*) region_alloc_zero(region, sizeof(*tp)); if(tcp_pipeline < 0) tcp_pipeline = 0; if(tcp_pipeline > 65536) tcp_pipeline = 65536; /* max 16 bit ID numbers */ tp->pipe_num = tcp_pipeline; tp->key.num_unused = tp->pipe_num; tp->zone_per_id = rbtree_create(region, &pipeline_id_compare); tp->pipe_id_free_list = NULL; for(i=0; ipipe_num; i++) { struct xfrd_tcp_pipeline_id* n = (struct xfrd_tcp_pipeline_id*) region_alloc_zero(region, sizeof(*n)); n->next_free = tp->pipe_id_free_list; tp->pipe_id_free_list = n; } tp->unused = (uint16_t*)region_alloc_zero(region, sizeof(tp->unused[0])*tp->pipe_num); tp->tcp_r = xfrd_tcp_create(region, QIOBUFSZ); tp->tcp_w = xfrd_tcp_create(region, QIOBUFSZ); xfrd_tcp_pipeline_init(tp); return tp; } static struct xfrd_zone* xfrd_tcp_pipeline_lookup_id(struct xfrd_tcp_pipeline* tp, uint16_t id) { struct xfrd_tcp_pipeline_id key; rbnode_type* n; memset(&key, 0, sizeof(key)); key.node.key = &key; key.id = id; n = rbtree_search(tp->zone_per_id, &key); if(n && n != RBTREE_NULL) { return ((struct xfrd_tcp_pipeline_id*)n)->zone; } return NULL; } static void xfrd_tcp_pipeline_insert_id(struct xfrd_tcp_pipeline* tp, uint16_t id, struct xfrd_zone* zone) { struct xfrd_tcp_pipeline_id* n; /* because there are tp->pipe_num preallocated entries, and we have * only tp->pipe_num id values, the list cannot be empty now. */ assert(tp->pipe_id_free_list != NULL); /* pick up next free xfrd_tcp_pipeline_id node */ n = tp->pipe_id_free_list; tp->pipe_id_free_list = n->next_free; n->next_free = NULL; memset(&n->node, 0, sizeof(n->node)); n->node.key = n; n->id = id; n->zone = zone; rbtree_insert(tp->zone_per_id, &n->node); } static void xfrd_tcp_pipeline_remove_id(struct xfrd_tcp_pipeline* tp, uint16_t id) { struct xfrd_tcp_pipeline_id key; rbnode_type* node; memset(&key, 0, sizeof(key)); key.node.key = &key; key.id = id; node = rbtree_delete(tp->zone_per_id, &key); if(node && node != RBTREE_NULL) { struct xfrd_tcp_pipeline_id* n = (struct xfrd_tcp_pipeline_id*)node; n->next_free = tp->pipe_id_free_list; tp->pipe_id_free_list = n; } } static void xfrd_tcp_pipeline_skip_id(struct xfrd_tcp_pipeline* tp, uint16_t id) { struct xfrd_tcp_pipeline_id key; rbnode_type* n; memset(&key, 0, sizeof(key)); key.node.key = &key; key.id = id; n = rbtree_search(tp->zone_per_id, &key); if(n && n != RBTREE_NULL) { struct xfrd_tcp_pipeline_id* zid = (struct xfrd_tcp_pipeline_id*)n; zid->zone = TCP_NULL_SKIP; } } void xfrd_setup_packet(buffer_type* packet, uint16_t type, uint16_t klass, const dname_type* dname, uint16_t qid, int* apex_compress) { /* Set up the header */ buffer_clear(packet); ID_SET(packet, qid); FLAGS_SET(packet, 0); OPCODE_SET(packet, OPCODE_QUERY); QDCOUNT_SET(packet, 1); ANCOUNT_SET(packet, 0); NSCOUNT_SET(packet, 0); ARCOUNT_SET(packet, 0); buffer_skip(packet, QHEADERSZ); /* The question record. */ if(apex_compress) *apex_compress = buffer_position(packet); buffer_write(packet, dname_name(dname), dname->name_size); buffer_write_u16(packet, type); buffer_write_u16(packet, klass); } static socklen_t #ifdef INET6 xfrd_acl_sockaddr(acl_options_type* acl, unsigned int port, struct sockaddr_storage *sck) #else xfrd_acl_sockaddr(acl_options_type* acl, unsigned int port, struct sockaddr_in *sck, const char* fromto) #endif /* INET6 */ { /* setup address structure */ #ifdef INET6 memset(sck, 0, sizeof(struct sockaddr_storage)); #else memset(sck, 0, sizeof(struct sockaddr_in)); #endif if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_in6* sa = (struct sockaddr_in6*)sck; sa->sin6_family = AF_INET6; sa->sin6_port = htons(port); sa->sin6_addr = acl->addr.addr6; return sizeof(struct sockaddr_in6); #else log_msg(LOG_ERR, "xfrd: IPv6 connection %s %s attempted but no \ INET6.", fromto, acl->ip_address_spec); return 0; #endif } else { struct sockaddr_in* sa = (struct sockaddr_in*)sck; sa->sin_family = AF_INET; sa->sin_port = htons(port); sa->sin_addr = acl->addr.addr; return sizeof(struct sockaddr_in); } } socklen_t #ifdef INET6 xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_storage *to) #else xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_in *to) #endif /* INET6 */ { #ifdef HAVE_TLS_1_3 unsigned int port = acl->port?acl->port:(acl->tls_auth_options? (unsigned)atoi(TLS_PORT):(unsigned)atoi(TCP_PORT)); #else unsigned int port = acl->port?acl->port:(unsigned)atoi(TCP_PORT); #endif #ifdef INET6 return xfrd_acl_sockaddr(acl, port, to); #else return xfrd_acl_sockaddr(acl, port, to, "to"); #endif /* INET6 */ } socklen_t #ifdef INET6 xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_storage *frm) #else xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_in *frm) #endif /* INET6 */ { unsigned int port = acl->port?acl->port:0; #ifdef INET6 return xfrd_acl_sockaddr(acl, port, frm); #else return xfrd_acl_sockaddr(acl, port, frm, "from"); #endif /* INET6 */ } void xfrd_write_soa_buffer(struct buffer* packet, const dname_type* apex, struct xfrd_soa* soa, int apex_compress) { size_t rdlength_pos; uint16_t rdlength; if(apex_compress > 0 && apex_compress < (int)buffer_limit(packet) && apex->name_size > 1) buffer_write_u16(packet, 0xc000 | apex_compress); else buffer_write(packet, dname_name(apex), apex->name_size); /* already in network order */ buffer_write(packet, &soa->type, sizeof(soa->type)); buffer_write(packet, &soa->klass, sizeof(soa->klass)); buffer_write(packet, &soa->ttl, sizeof(soa->ttl)); rdlength_pos = buffer_position(packet); buffer_skip(packet, sizeof(rdlength)); /* compress dnames to apex if possible */ if(apex_compress > 0 && apex_compress < (int)buffer_limit(packet) && apex->name_size > 1 && is_dname_subdomain_of_case( soa->prim_ns+1, soa->prim_ns[0], dname_name(apex), apex->name_size)) { if(soa->prim_ns[0] > apex->name_size) buffer_write(packet, soa->prim_ns+1, soa->prim_ns[0]- apex->name_size); buffer_write_u16(packet, 0xc000 | apex_compress); } else { buffer_write(packet, soa->prim_ns+1, soa->prim_ns[0]); } if(apex_compress > 0 && apex_compress < (int)buffer_limit(packet) && apex->name_size > 1 && is_dname_subdomain_of_case(soa->email+1, soa->email[0], dname_name(apex), apex->name_size)) { if(soa->email[0] > apex->name_size) buffer_write(packet, soa->email+1, soa->email[0]- apex->name_size); buffer_write_u16(packet, 0xc000 | apex_compress); } else { buffer_write(packet, soa->email+1, soa->email[0]); } buffer_write(packet, &soa->serial, sizeof(uint32_t)); buffer_write(packet, &soa->refresh, sizeof(uint32_t)); buffer_write(packet, &soa->retry, sizeof(uint32_t)); buffer_write(packet, &soa->expire, sizeof(uint32_t)); buffer_write(packet, &soa->minimum, sizeof(uint32_t)); /* write length of RR */ rdlength = buffer_position(packet) - rdlength_pos - sizeof(rdlength); buffer_write_u16_at(packet, rdlength_pos, rdlength); } struct xfrd_tcp* xfrd_tcp_create(region_type* region, size_t bufsize) { struct xfrd_tcp* tcp_state = (struct xfrd_tcp*)region_alloc( region, sizeof(struct xfrd_tcp)); memset(tcp_state, 0, sizeof(struct xfrd_tcp)); tcp_state->packet = buffer_create(region, bufsize); tcp_state->fd = -1; return tcp_state; } static struct xfrd_tcp_pipeline* pipeline_find(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { rbnode_type* sme = NULL; struct xfrd_tcp_pipeline* r; /* smaller buf than a full pipeline with 64kb ID array, only need * the front part with the key info, this front part contains the * members that the compare function uses. */ struct xfrd_tcp_pipeline_key k, *key=&k; key->node.key = key; key->ip_len = xfrd_acl_sockaddr_to(zone->master, &key->ip); key->num_unused = set->tcp_pipeline; /* lookup existing tcp transfer to the master with highest unused */ if(rbtree_find_less_equal(set->pipetree, key, &sme)) { /* exact match, strange, fully unused tcp cannot be open */ assert(0); } if(!sme) return NULL; r = (struct xfrd_tcp_pipeline*)sme->key; /* <= key pointed at, is the master correct ? */ if(r->key.ip_len != key->ip_len) return NULL; if(memcmp(&r->key.ip, &key->ip, key->ip_len) != 0) return NULL; /* correct master, is there a slot free for this transfer? */ if(r->key.num_unused == 0) return NULL; return r; } /* remove zone from tcp waiting list */ static void tcp_zone_waiting_list_popfirst(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { assert(zone->tcp_waiting); set->tcp_waiting_first = zone->tcp_waiting_next; if(zone->tcp_waiting_next) zone->tcp_waiting_next->tcp_waiting_prev = NULL; else set->tcp_waiting_last = 0; zone->tcp_waiting_next = 0; zone->tcp_waiting = 0; } /* remove zone from tcp pipe write-wait list */ static void tcp_pipe_sendlist_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { if(zone->in_tcp_send) { if(zone->tcp_send_prev) zone->tcp_send_prev->tcp_send_next=zone->tcp_send_next; else tp->tcp_send_first=zone->tcp_send_next; if(zone->tcp_send_next) zone->tcp_send_next->tcp_send_prev=zone->tcp_send_prev; else tp->tcp_send_last=zone->tcp_send_prev; zone->in_tcp_send = 0; } } /* remove first from write-wait list */ static void tcp_pipe_sendlist_popfirst(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { tp->tcp_send_first = zone->tcp_send_next; if(tp->tcp_send_first) tp->tcp_send_first->tcp_send_prev = NULL; else tp->tcp_send_last = NULL; zone->in_tcp_send = 0; } /* remove zone from tcp pipe ID map */ static void tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone, int alsotree) { assert(tp->key.num_unused < tp->pipe_num && tp->key.num_unused >= 0); if(alsotree) xfrd_tcp_pipeline_remove_id(tp, zone->query_id); tp->unused[tp->key.num_unused] = zone->query_id; /* must remove and re-add for sort order in tree */ (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->key.node); tp->key.num_unused++; (void)rbtree_insert(xfrd->tcp_set->pipetree, &tp->key.node); } /* stop the tcp pipe (and all its zones need to retry) */ static void xfrd_tcp_pipe_stop(struct xfrd_tcp_pipeline* tp) { struct xfrd_tcp_pipeline_id* zid; int conn = -1; assert(tp->key.num_unused < tp->pipe_num); /* at least one 'in-use' */ assert(tp->pipe_num - tp->key.num_unused > tp->key.num_skip); /* at least one 'nonskip' */ /* need to retry for all the zones connected to it */ /* these could use different lists and go to a different nextmaster*/ RBTREE_FOR(zid, struct xfrd_tcp_pipeline_id*, tp->zone_per_id) { xfrd_zone_type* zone = zid->zone; if(zone && zone != TCP_NULL_SKIP) { assert(zone->query_id == zid->id); conn = zone->tcp_conn; zone->tcp_conn = -1; zone->tcp_waiting = 0; tcp_pipe_sendlist_remove(tp, zone); tcp_pipe_id_remove(tp, zone, 0); xfrd_set_refresh_now(zone); } } xfrd_tcp_pipeline_cleanup(tp); assert(conn != -1); /* now release the entire tcp pipe */ xfrd_tcp_pipe_release(xfrd->tcp_set, tp, conn); } static void tcp_pipe_reset_timeout(struct xfrd_tcp_pipeline* tp) { int fd = tp->handler.ev_fd; struct timeval tv; tv.tv_sec = xfrd->tcp_set->tcp_timeout; tv.tv_usec = 0; if(tp->handler_added) event_del(&tp->handler); memset(&tp->handler, 0, sizeof(tp->handler)); event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ| #ifdef HAVE_TLS_1_3 ( tp->ssl ? ( tp->handshake_done ? ( tp->tcp_send_first ? EV_WRITE : 0 ) : tp->handshake_want == SSL_ERROR_WANT_WRITE ? EV_WRITE : 0 ) : tp->tcp_send_first ? EV_WRITE : 0 ), #else ( tp->tcp_send_first ? EV_WRITE : 0 ), #endif xfrd_handle_tcp_pipe, tp); if(event_base_set(xfrd->event_base, &tp->handler) != 0) log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); if(event_add(&tp->handler, &tv) != 0) log_msg(LOG_ERR, "xfrd tcp: event_add failed"); tp->handler_added = 1; } /* handle event from fd of tcp pipe */ void xfrd_handle_tcp_pipe(int ATTR_UNUSED(fd), short event, void* arg) { struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*)arg; if((event & EV_WRITE)) { tcp_pipe_reset_timeout(tp); if(tp->tcp_send_first) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp write, zone %s", tp->tcp_send_first->apex_str)); xfrd_tcp_write(tp, tp->tcp_send_first); } } if((event & EV_READ) && tp->handler_added) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp read")); tcp_pipe_reset_timeout(tp); xfrd_tcp_read(tp); } if((event & EV_TIMEOUT) && tp->handler_added) { /* tcp connection timed out */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp timeout")); xfrd_tcp_pipe_stop(tp); } } /* add a zone to the pipeline, it starts to want to write its query */ static void pipeline_setup_new_zone(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { /* assign the ID */ int idx; assert(tp->key.num_unused > 0); /* we pick a random ID, even though it is TCP anyway */ idx = random_generate(tp->key.num_unused); zone->query_id = tp->unused[idx]; tp->unused[idx] = tp->unused[tp->key.num_unused-1]; xfrd_tcp_pipeline_insert_id(tp, zone->query_id, zone); /* decrement unused counter, and fixup tree */ (void)rbtree_delete(set->pipetree, &tp->key.node); tp->key.num_unused--; (void)rbtree_insert(set->pipetree, &tp->key.node); /* add to sendlist, at end */ zone->tcp_send_next = NULL; zone->tcp_send_prev = tp->tcp_send_last; zone->in_tcp_send = 1; if(tp->tcp_send_last) tp->tcp_send_last->tcp_send_next = zone; else tp->tcp_send_first = zone; tp->tcp_send_last = zone; /* is it first in line? */ if(tp->tcp_send_first == zone) { xfrd_tcp_setup_write_packet(tp, zone); /* add write to event handler */ tcp_pipe_reset_timeout(tp); } } void xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { struct xfrd_tcp_pipeline* tp; assert(zone->tcp_conn == -1); assert(zone->tcp_waiting == 0); if(set->tcp_count < set->tcp_max) { int i; assert(!set->tcp_waiting_first); set->tcp_count ++; /* find a free tcp_buffer */ for(i=0; itcp_max; i++) { if(set->tcp_state[i]->tcp_r->fd == -1) { zone->tcp_conn = i; break; } } /** What if there is no free tcp_buffer? return; */ if (zone->tcp_conn < 0) { return; } tp = set->tcp_state[zone->tcp_conn]; zone->tcp_waiting = 0; /* stop udp use (if any) */ if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); if(!xfrd_tcp_open(set, tp, zone)) { zone->tcp_conn = -1; set->tcp_count --; xfrd_set_refresh_now(zone); return; } /* ip and ip_len set by tcp_open */ xfrd_tcp_pipeline_init(tp); /* insert into tree */ (void)rbtree_insert(set->pipetree, &tp->key.node); xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* check for a pipeline to the same master with unused ID */ if((tp = pipeline_find(set, zone))!= NULL) { int i; if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); for(i=0; itcp_max; i++) { if(set->tcp_state[i] == tp) zone->tcp_conn = i; } xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* wait, at end of line */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: max number of tcp " "connections (%d) reached.", set->tcp_max)); zone->tcp_waiting_next = 0; zone->tcp_waiting_prev = set->tcp_waiting_last; zone->tcp_waiting = 1; if(!set->tcp_waiting_last) { set->tcp_waiting_first = zone; set->tcp_waiting_last = zone; } else { set->tcp_waiting_last->tcp_waiting_next = zone; set->tcp_waiting_last = zone; } xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); } int xfrd_tcp_open(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { int fd, family, conn; struct timeval tv; assert(zone->tcp_conn != -1); /* if there is no next master, fallback to use the first one */ /* but there really should be a master set */ if(!zone->master) { zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s open tcp conn to %s", zone->apex_str, zone->master->ip_address_spec)); tp->tcp_r->is_reading = 1; tp->tcp_r->total_bytes = 0; tp->tcp_r->msglen = 0; buffer_clear(tp->tcp_r->packet); tp->tcp_w->is_reading = 0; tp->tcp_w->total_bytes = 0; tp->tcp_w->msglen = 0; tp->connection_established = 0; if(zone->master->is_ipv6) { #ifdef INET6 family = PF_INET6; #else xfrd_set_refresh_now(zone); return 0; #endif } else { family = PF_INET; } fd = socket(family, SOCK_STREAM, IPPROTO_TCP); if(fd == -1) { /* squelch 'Address family not supported by protocol' at low * verbosity levels */ if(errno != EAFNOSUPPORT || verbosity > 2) log_msg(LOG_ERR, "xfrd: %s cannot create tcp socket: %s", zone->master->ip_address_spec, strerror(errno)); xfrd_set_refresh_now(zone); return 0; } if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "xfrd: fcntl failed: %s", strerror(errno)); close(fd); xfrd_set_refresh_now(zone); return 0; } if(xfrd->nsd->outgoing_tcp_mss > 0) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void*)&xfrd->nsd->outgoing_tcp_mss, sizeof(xfrd->nsd->outgoing_tcp_mss)) < 0) { log_msg(LOG_ERR, "xfrd: setsockopt(TCP_MAXSEG)" "failed: %s", strerror(errno)); } #else log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported"); #endif } tp->key.ip_len = xfrd_acl_sockaddr_to(zone->master, &tp->key.ip); /* bind it */ if (!xfrd_bind_local_interface(fd, zone->zone_options->pattern-> outgoing_interface, zone->master, 1)) { close(fd); xfrd_set_refresh_now(zone); return 0; } conn = connect(fd, (struct sockaddr*)&tp->key.ip, tp->key.ip_len); if (conn == -1 && errno != EINPROGRESS) { log_msg(LOG_ERR, "xfrd: connect %s failed: %s", zone->master->ip_address_spec, strerror(errno)); close(fd); xfrd_set_refresh_now(zone); return 0; } tp->tcp_r->fd = fd; tp->tcp_w->fd = fd; /* Check if an tls_auth name is configured which means we should try to establish an SSL connection */ if (zone->master->tls_auth_options && zone->master->tls_auth_options->auth_domain_name) { #ifdef HAVE_TLS_1_3 /* Load client certificate (if provided) */ if (zone->master->tls_auth_options->client_cert && zone->master->tls_auth_options->client_key) { if (SSL_CTX_use_certificate_chain_file(set->ssl_ctx, zone->master->tls_auth_options->client_cert) != 1) { log_msg(LOG_ERR, "xfrd tls: Unable to load client certificate from file %s", zone->master->tls_auth_options->client_cert); } if (zone->master->tls_auth_options->client_key_pw) { SSL_CTX_set_default_passwd_cb(set->ssl_ctx, password_cb); SSL_CTX_set_default_passwd_cb_userdata(set->ssl_ctx, zone->master->tls_auth_options->client_key_pw); } if (SSL_CTX_use_PrivateKey_file(set->ssl_ctx, zone->master->tls_auth_options->client_key, SSL_FILETYPE_PEM) != 1) { log_msg(LOG_ERR, "xfrd tls: Unable to load private key from file %s", zone->master->tls_auth_options->client_key); } if (!SSL_CTX_check_private_key(set->ssl_ctx)) { log_msg(LOG_ERR, "xfrd tls: Client private key from file %s does not match the certificate from file %s", zone->master->tls_auth_options->client_key, zone->master->tls_auth_options->client_cert); } /* If client certificate/private key loading has failed, client will not try to authenticate to the server but the connection will procceed and will be up to the server to allow or deny the unauthenticated connection. A server that does not enforce authentication (or a badly configured server?) might allow the transfer. XXX: Maybe we should close the connection now to make it obvious that there is something wrong from our side. Alternatively make it obvious to the operator that we're not being authenticated to the server. */ } if (!setup_ssl(tp, set, zone->master->tls_auth_options->auth_domain_name)) { log_msg(LOG_ERR, "xfrd: Cannot setup TLS on pipeline for %s to %s", zone->apex_str, zone->master->ip_address_spec); close(fd); xfrd_set_refresh_now(zone); return 0; } tp->handshake_done = 0; if(!ssl_handshake(tp)) { if(tp->handshake_want == SSL_ERROR_SYSCALL) { log_msg(LOG_ERR, "xfrd: TLS handshake failed " "for %s to %s: %s", zone->apex_str, zone->master->ip_address_spec, strerror(errno)); } else if(tp->handshake_want == SSL_ERROR_SSL) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "xfrd: " "TLS handshake failed for %s to %s", zone->apex_str, zone->master->ip_address_spec); log_crypto_err(errmsg); } else { log_msg(LOG_ERR, "xfrd: TLS handshake failed " "for %s to %s with %d", zone->apex_str, zone->master->ip_address_spec, tp->handshake_want); } close(fd); xfrd_set_refresh_now(zone); return 0; } #else log_msg(LOG_ERR, "xfrd: TLS 1.3 is not available, XFR-over-TLS is " "not supported for %s to %s", zone->apex_str, zone->master->ip_address_spec); close(fd); xfrd_set_refresh_now(zone); return 0; #endif } /* set the tcp pipe event */ if(tp->handler_added) event_del(&tp->handler); memset(&tp->handler, 0, sizeof(tp->handler)); event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ| #ifdef HAVE_TLS_1_3 ( !tp->ssl || tp->handshake_done || tp->handshake_want == SSL_ERROR_WANT_WRITE ? EV_WRITE : 0), #else EV_WRITE, #endif xfrd_handle_tcp_pipe, tp); if(event_base_set(xfrd->event_base, &tp->handler) != 0) log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); tv.tv_sec = set->tcp_timeout; tv.tv_usec = 0; if(event_add(&tp->handler, &tv) != 0) log_msg(LOG_ERR, "xfrd tcp: event_add failed"); tp->handler_added = 1; return 1; } void xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { struct xfrd_tcp* tcp = tp->tcp_w; assert(zone->tcp_conn != -1); 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 || /* 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)); VERBOSITY(3, (LOG_INFO, "request full zone transfer " "(AXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); xfrd_setup_packet(tcp->packet, TYPE_AXFR, CLASS_IN, zone->apex, zone->query_id, NULL); xfrd_prepare_zone_xfr(zone, TYPE_AXFR); } else { int apex_compress = 0; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request incremental zone " "transfer (IXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); VERBOSITY(3, (LOG_INFO, "request incremental zone " "transfer (IXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); xfrd_setup_packet(tcp->packet, TYPE_IXFR, CLASS_IN, zone->apex, zone->query_id, &apex_compress); xfrd_prepare_zone_xfr(zone, TYPE_IXFR); NSCOUNT_SET(tcp->packet, 1); xfrd_write_soa_buffer(tcp->packet, zone->apex, &zone->soa_disk, apex_compress); } if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request( tcp->packet, &zone->latest_xfr->tsig, zone->master); } buffer_flip(tcp->packet); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "sent tcp query with ID %d", zone->query_id)); tcp->msglen = buffer_limit(tcp->packet); tcp->total_bytes = 0; } static void tcp_conn_ready_for_reading(struct xfrd_tcp* tcp) { tcp->total_bytes = 0; tcp->msglen = 0; buffer_clear(tcp->packet); } #ifdef HAVE_TLS_1_3 static int conn_write_ssl(struct xfrd_tcp* tcp, SSL* ssl) { int request_length; ssize_t sent; if(tcp->total_bytes < sizeof(tcp->msglen)) { uint16_t sendlen = htons(tcp->msglen); // send request_length = sizeof(tcp->msglen) - tcp->total_bytes; ERR_clear_error(); sent = SSL_write(ssl, (const char*)&sendlen + tcp->total_bytes, request_length); switch(SSL_get_error(ssl,sent)) { case SSL_ERROR_NONE: break; default: log_msg(LOG_ERR, "xfrd: generic write problem with tls"); } if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } tcp->total_bytes += sent; if(sent > (ssize_t)sizeof(tcp->msglen)) buffer_skip(tcp->packet, sent-sizeof(tcp->msglen)); if(tcp->total_bytes < sizeof(tcp->msglen)) { /* incomplete write, resume later */ return 0; } assert(tcp->total_bytes >= sizeof(tcp->msglen)); } assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)); request_length = buffer_remaining(tcp->packet); ERR_clear_error(); sent = SSL_write(ssl, buffer_current(tcp->packet), request_length); switch(SSL_get_error(ssl,sent)) { case SSL_ERROR_NONE: break; default: log_msg(LOG_ERR, "xfrd: generic write problem with tls"); } if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } buffer_skip(tcp->packet, sent); tcp->total_bytes += sent; if(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) { /* more to write when socket becomes writable again */ return 0; } assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen)); return 1; } #endif int conn_write(struct xfrd_tcp* tcp) { ssize_t sent; if(tcp->total_bytes < sizeof(tcp->msglen)) { uint16_t sendlen = htons(tcp->msglen); #ifdef HAVE_WRITEV struct iovec iov[2]; iov[0].iov_base = (uint8_t*)&sendlen + tcp->total_bytes; iov[0].iov_len = sizeof(sendlen) - tcp->total_bytes; iov[1].iov_base = buffer_begin(tcp->packet); iov[1].iov_len = buffer_limit(tcp->packet); sent = writev(tcp->fd, iov, 2); #else /* HAVE_WRITEV */ sent = write(tcp->fd, (const char*)&sendlen + tcp->total_bytes, sizeof(tcp->msglen) - tcp->total_bytes); #endif /* HAVE_WRITEV */ if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } tcp->total_bytes += sent; if(sent > (ssize_t)sizeof(tcp->msglen)) buffer_skip(tcp->packet, sent-sizeof(tcp->msglen)); if(tcp->total_bytes < sizeof(tcp->msglen)) { /* incomplete write, resume later */ return 0; } #ifdef HAVE_WRITEV if(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen)) { /* packet done */ return 1; } #endif assert(tcp->total_bytes >= sizeof(tcp->msglen)); } assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)); sent = write(tcp->fd, buffer_current(tcp->packet), buffer_remaining(tcp->packet)); if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } buffer_skip(tcp->packet, sent); tcp->total_bytes += sent; if(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) { /* more to write when socket becomes writable again */ return 0; } assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen)); return 1; } void xfrd_tcp_write(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { int ret; struct xfrd_tcp* tcp = tp->tcp_w; assert(zone->tcp_conn != -1); assert(zone == tp->tcp_send_first); /* see if for non-established connection, there is a connect error */ if(!tp->connection_established) { /* check for pending error from nonblocking connect */ /* from Stevens, unix network programming, vol1, 3rd ed, p450 */ int error = 0; socklen_t len = sizeof(error); if(getsockopt(tcp->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){ error = errno; /* on solaris errno is error */ } if(error == EINPROGRESS || error == EWOULDBLOCK) return; /* try again later */ if(error != 0) { log_msg(LOG_ERR, "%s: Could not tcp connect to %s: %s", zone->apex_str, zone->master->ip_address_spec, strerror(error)); xfrd_tcp_pipe_stop(tp); return; } } #ifdef HAVE_TLS_1_3 if (tp->ssl) { if(tp->handshake_done) { ret = conn_write_ssl(tcp, tp->ssl); } else if(ssl_handshake(tp)) { tcp_pipe_reset_timeout(tp); /* reschedule */ return; } else { if(tp->handshake_want == SSL_ERROR_SYSCALL) { log_msg(LOG_ERR, "xfrd: TLS handshake failed: %s", strerror(errno)); } else if(tp->handshake_want == SSL_ERROR_SSL) { log_crypto_err("xfrd: TLS handshake failed"); } else { log_msg(LOG_ERR, "xfrd: TLS handshake failed " "with value: %d", tp->handshake_want); } xfrd_tcp_pipe_stop(tp); return; } } else #endif ret = conn_write(tcp); if(ret == -1) { log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno)); xfrd_tcp_pipe_stop(tp); return; } if(tcp->total_bytes != 0 && !tp->connection_established) tp->connection_established = 1; if(ret == 0) { return; /* write again later */ } /* done writing this message */ /* remove first zone from sendlist */ tcp_pipe_sendlist_popfirst(tp, zone); /* see if other zone wants to write; init; let it write (now) */ /* and use a loop, because 64k stack calls is a too much */ while(tp->tcp_send_first) { /* setup to write for this zone */ xfrd_tcp_setup_write_packet(tp, tp->tcp_send_first); /* attempt to write for this zone (if success, continue loop)*/ #ifdef HAVE_TLS_1_3 if (tp->ssl) ret = conn_write_ssl(tcp, tp->ssl); else #endif ret = conn_write(tcp); if(ret == -1) { log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno)); xfrd_tcp_pipe_stop(tp); return; } if(ret == 0) return; /* write again later */ tcp_pipe_sendlist_popfirst(tp, tp->tcp_send_first); } /* if sendlist empty, remove WRITE from event */ /* listen to READ, and not WRITE events */ assert(tp->tcp_send_first == NULL); tcp_pipe_reset_timeout(tp); } #ifdef HAVE_TLS_1_3 static int conn_read_ssl(struct xfrd_tcp* tcp, SSL* ssl) { ssize_t received; /* receive leading packet length bytes */ if(tcp->total_bytes < sizeof(tcp->msglen)) { ERR_clear_error(); received = SSL_read(ssl, (char*) &tcp->msglen + tcp->total_bytes, sizeof(tcp->msglen) - tcp->total_bytes); if (received <= 0) { int err = SSL_get_error(ssl, received); if(err == SSL_ERROR_WANT_READ && errno == EAGAIN) { return 0; } if(err == SSL_ERROR_ZERO_RETURN) { /* EOF */ return -1; } if(err == SSL_ERROR_SYSCALL) log_msg(LOG_ERR, "ssl_read returned error SSL_ERROR_SYSCALL with received %zd: %s", received, strerror(errno)); else log_msg(LOG_ERR, "ssl_read returned error %d with received %zd", err, received); } if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tls read sz: %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; if(tcp->total_bytes < sizeof(tcp->msglen)) { /* not complete yet, try later */ return 0; } assert(tcp->total_bytes == sizeof(tcp->msglen)); tcp->msglen = ntohs(tcp->msglen); if(tcp->msglen == 0) { buffer_set_limit(tcp->packet, tcp->msglen); return 1; } if(tcp->msglen > buffer_capacity(tcp->packet)) { log_msg(LOG_ERR, "buffer too small, dropping connection"); return 0; } buffer_set_limit(tcp->packet, tcp->msglen); } assert(buffer_remaining(tcp->packet) > 0); ERR_clear_error(); received = SSL_read(ssl, buffer_current(tcp->packet), buffer_remaining(tcp->packet)); if (received <= 0) { int err = SSL_get_error(ssl, received); if(err == SSL_ERROR_ZERO_RETURN) { /* EOF */ return -1; } if(err == SSL_ERROR_SYSCALL) log_msg(LOG_ERR, "ssl_read returned error SSL_ERROR_SYSCALL with received %zd: %s", received, strerror(errno)); else log_msg(LOG_ERR, "ssl_read returned error %d with received %zd", err, received); } if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tcp read %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; buffer_skip(tcp->packet, received); if(buffer_remaining(tcp->packet) > 0) { /* not complete yet, wait for more */ return 0; } /* completed */ assert(buffer_position(tcp->packet) == tcp->msglen); return 1; } #endif int conn_read(struct xfrd_tcp* tcp) { ssize_t received; /* receive leading packet length bytes */ if(tcp->total_bytes < sizeof(tcp->msglen)) { received = read(tcp->fd, (char*) &tcp->msglen + tcp->total_bytes, sizeof(tcp->msglen) - tcp->total_bytes); if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tcp read sz: %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; if(tcp->total_bytes < sizeof(tcp->msglen)) { /* not complete yet, try later */ return 0; } assert(tcp->total_bytes == sizeof(tcp->msglen)); tcp->msglen = ntohs(tcp->msglen); if(tcp->msglen == 0) { buffer_set_limit(tcp->packet, tcp->msglen); return 1; } if(tcp->msglen > buffer_capacity(tcp->packet)) { log_msg(LOG_ERR, "buffer too small, dropping connection"); return 0; } buffer_set_limit(tcp->packet, tcp->msglen); } assert(buffer_remaining(tcp->packet) > 0); received = read(tcp->fd, buffer_current(tcp->packet), buffer_remaining(tcp->packet)); if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tcp read %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; buffer_skip(tcp->packet, received); if(buffer_remaining(tcp->packet) > 0) { /* not complete yet, wait for more */ return 0; } /* completed */ assert(buffer_position(tcp->packet) == tcp->msglen); return 1; } void xfrd_tcp_read(struct xfrd_tcp_pipeline* tp) { xfrd_zone_type* zone; struct xfrd_tcp* tcp = tp->tcp_r; int ret; enum xfrd_packet_result pkt_result; #ifdef HAVE_TLS_1_3 if(tp->ssl) { if(tp->handshake_done) { ret = conn_read_ssl(tcp, tp->ssl); } else if(ssl_handshake(tp)) { tcp_pipe_reset_timeout(tp); /* reschedule */ return; } else { if(tp->handshake_want == SSL_ERROR_SYSCALL) { log_msg(LOG_ERR, "xfrd: TLS handshake failed: %s", strerror(errno)); } else if(tp->handshake_want == SSL_ERROR_SSL) { log_crypto_err("xfrd: TLS handshake failed"); } else { log_msg(LOG_ERR, "xfrd: TLS handshake failed " "with value: %d", tp->handshake_want); } xfrd_tcp_pipe_stop(tp); return; } } else #endif ret = conn_read(tcp); if(ret == -1) { if(errno != 0) log_msg(LOG_ERR, "xfrd: failed reading tcp %s", strerror(errno)); else log_msg(LOG_ERR, "xfrd: failed reading tcp: closed"); xfrd_tcp_pipe_stop(tp); return; } if(ret == 0) return; /* completed msg */ buffer_flip(tcp->packet); /* see which ID number it is, if skip, handle skip, NULL: warn */ if(tcp->msglen < QHEADERSZ) { /* too short for DNS header, skip it */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp skip response that is too short")); tcp_conn_ready_for_reading(tcp); return; } zone = xfrd_tcp_pipeline_lookup_id(tp, ID(tcp->packet)); if(!zone || zone == TCP_NULL_SKIP) { /* no zone for this id? skip it */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp skip response with %s ID", zone?"set-to-skip":"unknown")); tcp_conn_ready_for_reading(tcp); return; } assert(zone->tcp_conn != -1); /* handle message for zone */ pkt_result = xfrd_handle_received_xfr_packet(zone, tcp->packet); /* setup for reading the next packet on this connection */ tcp_conn_ready_for_reading(tcp); switch(pkt_result) { case xfrd_packet_more: /* wait for next packet */ break; case xfrd_packet_newlease: /* set to skip if more packets with this ID */ xfrd_tcp_pipeline_skip_id(tp, zone->query_id); tp->key.num_skip++; /* fall through to remove zone from tp */ /* fallthrough */ case xfrd_packet_transfer: if(zone->zone_options->pattern->multi_primary_check) { xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_make_request(zone); break; } xfrd_tcp_release(xfrd->tcp_set, zone); assert(zone->round_num == -1); break; case xfrd_packet_notimpl: xfrd_disable_ixfr(zone); xfrd_tcp_release(xfrd->tcp_set, zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_bad: case xfrd_packet_tcp: default: /* set to skip if more packets with this ID */ xfrd_tcp_pipeline_skip_id(tp, zone->query_id); tp->key.num_skip++; xfrd_tcp_release(xfrd->tcp_set, zone); /* query next server */ xfrd_make_request(zone); break; } } void xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { int conn = zone->tcp_conn; struct xfrd_tcp_pipeline* tp = set->tcp_state[conn]; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s released tcp conn to %s", zone->apex_str, zone->master->ip_address_spec)); assert(zone->tcp_conn != -1); assert(zone->tcp_waiting == 0); zone->tcp_conn = -1; zone->tcp_waiting = 0; /* remove from tcp_send list */ tcp_pipe_sendlist_remove(tp, zone); /* remove it from the ID list */ if(xfrd_tcp_pipeline_lookup_id(tp, zone->query_id) != TCP_NULL_SKIP) tcp_pipe_id_remove(tp, zone, 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: released tcp pipe now %d unused", tp->key.num_unused)); /* if pipe was full, but no more, then see if waiting element is * for the same master, and can fill the unused ID */ if(tp->key.num_unused == 1 && set->tcp_waiting_first) { #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif socklen_t to_len = xfrd_acl_sockaddr_to( set->tcp_waiting_first->master, &to); if(to_len == tp->key.ip_len && memcmp(&to, &tp->key.ip, to_len) == 0) { /* use this connection for the waiting zone */ zone = set->tcp_waiting_first; assert(zone->tcp_conn == -1); zone->tcp_conn = conn; tcp_zone_waiting_list_popfirst(set, zone); if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* waiting zone did not go to same server */ } /* if all unused, or only skipped leftover, close the pipeline */ if(tp->key.num_unused >= tp->pipe_num || tp->key.num_skip >= tp->pipe_num - tp->key.num_unused) xfrd_tcp_pipe_release(set, tp, conn); } void xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, int conn) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp pipe released")); /* one handler per tcp pipe */ if(tp->handler_added) event_del(&tp->handler); tp->handler_added = 0; #ifdef HAVE_TLS_1_3 /* close SSL */ if (tp->ssl) { DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: Shutting down TLS")); SSL_shutdown(tp->ssl); SSL_free(tp->ssl); tp->ssl = NULL; } #endif /* fd in tcp_r and tcp_w is the same, close once */ if(tp->tcp_r->fd != -1) close(tp->tcp_r->fd); tp->tcp_r->fd = -1; tp->tcp_w->fd = -1; /* remove from pipetree */ (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->key.node); /* a waiting zone can use the free tcp slot (to another server) */ /* if that zone fails to set-up or connect, we try to start the next * waiting zone in the list */ while(set->tcp_count == set->tcp_max && set->tcp_waiting_first) { /* pop first waiting process */ xfrd_zone_type* zone = set->tcp_waiting_first; /* start it */ assert(zone->tcp_conn == -1); zone->tcp_conn = conn; tcp_zone_waiting_list_popfirst(set, zone); /* stop udp (if any) */ if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); if(!xfrd_tcp_open(set, tp, zone)) { zone->tcp_conn = -1; xfrd_set_refresh_now(zone); /* try to start the next zone (if any) */ continue; } /* re-init this tcppipe */ /* ip and ip_len set by tcp_open */ xfrd_tcp_pipeline_init(tp); /* insert into tree */ (void)rbtree_insert(set->pipetree, &tp->key.node); /* setup write */ xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); /* started a task, no need for cleanups, so return */ return; } /* no task to start, cleanup */ assert(!set->tcp_waiting_first); set->tcp_count --; assert(set->tcp_count >= 0); } nsd-4.12.0/xfrd-notify.h0000644000175000017500000000552415002373054014425 0ustar mozziemozzie/* * xfrd-notify.h - notify sending routines. * * Copyright (c) 2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_NOTIFY_H #define XFRD_NOTIFY_H #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "tsig.h" #include "rbtree.h" struct nsd; struct region; struct xfrd_zone; struct zone_options; struct zone; struct xfrd_soa; struct acl_options; struct xfrd_state; /** number of concurrent notify packets in flight */ #define NOTIFY_CONCURRENT_MAX 16 /** notify packet info */ struct notify_pkt { struct acl_options* dest; /* target, NULL if entry not in use */ uint8_t notify_retry; /* how manieth retry in sending to current */ uint16_t notify_query_id; time_t send_time; }; /** * This struct keeps track of outbound notifies for a zone. */ struct notify_zone { rbnode_type node; /* name of the zone */ const dname_type* apex; const char* apex_str; tsig_record_type notify_tsig; /* tsig state for notify */ struct zone_options* options; struct xfrd_soa *current_soa; /* current SOA in NSD */ /* notify sending handler */ /* Not saved on disk (i.e. kill of daemon stops notifies) */ int notify_send_enable; struct event notify_send_handler; int notify_send6_enable; struct event notify_send6_handler; struct timeval notify_timeout; struct acl_options* notify_current; /* current slave to notify */ uint8_t notify_restart; /* restart notify after repattern */ struct notify_pkt pkts[NOTIFY_CONCURRENT_MAX]; int notify_pkt_count; /* number of entries nonNULL in pkts */ /* is this notify waiting for a socket? */ uint8_t is_waiting; /* the double linked waiting list for the udp sockets */ struct notify_zone* waiting_next; struct notify_zone* waiting_prev; } ATTR_PACKED; /* initialise outgoing notifies */ void init_notify_send(rbtree_type* tree, region_type* region, struct zone_options* options); /* delete notify zone */ void xfrd_del_notify(struct xfrd_state* xfrd, const dname_type* dname); /* send notifications to all in the notify list */ void xfrd_send_notify(rbtree_type* 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* 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. */ void notify_handle_master_zone_soainfo(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa); /* close fds in use for notification sending */ void close_notify_fds(rbtree_type* tree); /* stop send of notify */ void notify_disable(struct notify_zone* zone); #endif /* XFRD_NOTIFY_H */ nsd-4.12.0/xfrd-notify.c0000644000175000017500000004075515002373054014425 0ustar mozziemozzie/* * xfrd-notify.c - notify sending routines * * Copyright (c) 2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "xfrd-notify.h" #include "xfrd.h" #include "xfrd-tcp.h" #include "packet.h" #define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */ /* start sending notifies */ static void notify_enable(struct notify_zone* zone, struct xfrd_soa* new_soa); /* setup the notify active state */ static void setup_notify_active(struct notify_zone* zone); /* handle zone notify send */ static void xfrd_handle_notify_send(int fd, short event, void* arg); static int xfrd_notify_send_udp(struct notify_zone* zone, int index); static void notify_send_disable(struct notify_zone* zone) { zone->notify_send_enable = 0; event_del(&zone->notify_send_handler); if(zone->notify_send_handler.ev_fd != -1) { close(zone->notify_send_handler.ev_fd); zone->notify_send_handler.ev_fd = -1; } } static void notify_send6_disable(struct notify_zone* zone) { zone->notify_send6_enable = 0; event_del(&zone->notify_send6_handler); if(zone->notify_send6_handler.ev_fd != -1) { close(zone->notify_send6_handler.ev_fd); zone->notify_send6_handler.ev_fd = -1; } } void notify_disable(struct notify_zone* zone) { zone->notify_current = 0; /* if added, then remove */ if(zone->notify_send_enable) { notify_send_disable(zone); } if(zone->notify_send6_enable) { notify_send6_disable(zone); } if(xfrd->notify_udp_num == XFRD_MAX_UDP_NOTIFY) { /* find next waiting and needy zone */ while(xfrd->notify_waiting_first) { /* snip off */ struct notify_zone* wz = xfrd->notify_waiting_first; assert(wz->is_waiting); wz->is_waiting = 0; xfrd->notify_waiting_first = wz->waiting_next; if(wz->waiting_next) wz->waiting_next->waiting_prev = NULL; if(xfrd->notify_waiting_last == wz) xfrd->notify_waiting_last = NULL; /* see if this zone needs notify sending */ if(wz->notify_current) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify off waiting list.", zone->apex_str) ); setup_notify_active(wz); return; } } } xfrd->notify_udp_num--; } void init_notify_send(rbtree_type* tree, region_type* region, struct zone_options* options) { struct notify_zone* not = (struct notify_zone*) region_alloc(region, sizeof(struct notify_zone)); memset(not, 0, sizeof(struct notify_zone)); not->apex = options->node.key; not->apex_str = options->name; not->node.key = not->apex; not->options = options; /* if master zone and have a SOA */ not->current_soa = (struct xfrd_soa*)region_alloc(region, sizeof(struct xfrd_soa)); memset(not->current_soa, 0, sizeof(struct xfrd_soa)); not->notify_send_handler.ev_fd = -1; not->notify_send6_handler.ev_fd = -1; not->is_waiting = 0; not->notify_send_enable = 0; not->notify_send6_enable = 0; tsig_create_record_custom(¬->notify_tsig, NULL, 0, 0, 4); not->notify_current = 0; rbtree_insert(tree, (rbnode_type*)not); } void xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname) { /* find it */ struct notify_zone* not = (struct notify_zone*)rbtree_delete( xfrd->notify_zones, dname); if(!not) return; /* waiting list */ if(not->is_waiting) { if(not->waiting_prev) not->waiting_prev->waiting_next = not->waiting_next; else xfrd->notify_waiting_first = not->waiting_next; if(not->waiting_next) not->waiting_next->waiting_prev = not->waiting_prev; else xfrd->notify_waiting_last = not->waiting_prev; not->is_waiting = 0; } /* event */ if(not->notify_send_enable || not->notify_send6_enable) { notify_disable(not); } /* del tsig */ tsig_delete_record(¬->notify_tsig, NULL); /* free it */ region_recycle(xfrd->region, not->current_soa, sizeof(xfrd_soa_type)); /* the apex is recycled when the zone_options.node.key is removed */ region_recycle(xfrd->region, not, sizeof(*not)); } static int reply_pkt_is_ack(struct notify_zone* zone, buffer_type* packet, int index) { if((OPCODE(packet) != OPCODE_NOTIFY) || (QR(packet) == 0)) { log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags from %s", zone->apex_str, zone->pkts[index].dest->ip_address_spec); return 0; } /* we know it is OPCODE NOTIFY, QUERY_REPLY and for this zone */ if(ID(packet) != zone->pkts[index].notify_query_id) { log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID from %s", zone->apex_str, zone->pkts[index].dest->ip_address_spec); return 0; } /* could check tsig, but why. The reply does not cause processing. */ if(RCODE(packet) != RCODE_OK) { log_msg(LOG_ERR, "xfrd: zone %s: received notify response error %s from %s", zone->apex_str, rcode2str(RCODE(packet)), zone->pkts[index].dest->ip_address_spec); if(RCODE(packet) == RCODE_IMPL) return 1; /* rfc1996: notimpl notify reply: consider retries done */ return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: host %s acknowledges notify", zone->apex_str, zone->pkts[index].dest->ip_address_spec)); return 1; } /* compare sockaddr and acl_option addr and port numbers */ static int cmp_addr_equal(struct sockaddr* a, socklen_t a_len, struct acl_options* dest) { if(dest) { unsigned int destport = ((dest->port == 0)? (unsigned)atoi(TCP_PORT):dest->port); #ifdef INET6 struct sockaddr_storage* a1 = (struct sockaddr_storage*)a; if(a1->ss_family == AF_INET6 && dest->is_ipv6) { struct sockaddr_in6* a2 = (struct sockaddr_in6*)a; if(a_len < sizeof(struct sockaddr_in6)) return 0; /* too small */ if(ntohs(a2->sin6_port) != destport) return 0; /* different port number */ if(memcmp(&a2->sin6_addr, &dest->addr.addr6, sizeof(struct in6_addr)) != 0) return 0; /* different address */ return 1; } if(a1->ss_family == AF_INET6 || dest->is_ipv6) return 0; /* different address family */ else { #endif /* INET6 */ struct sockaddr_in* a3 = (struct sockaddr_in*)a; if(a_len < sizeof(struct sockaddr_in)) return 0; /* too small */ if(ntohs(a3->sin_port) != destport) return 0; /* different port number */ if(memcmp(&a3->sin_addr, &dest->addr.addr, sizeof(struct in_addr)) != 0) return 0; /* different address */ return 1; #ifdef INET6 } #endif } return 0; } static void notify_pkt_done(struct notify_zone* zone, int index) { zone->pkts[index].dest = NULL; zone->pkts[index].notify_retry = 0; zone->pkts[index].send_time = 0; zone->pkts[index].notify_query_id = 0; zone->notify_pkt_count--; } static void notify_pkt_retry(struct notify_zone* zone, int index) { if(++zone->pkts[index].notify_retry >= zone->options->pattern->notify_retry) { log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable", zone->apex_str, zone->pkts[index].dest->ip_address_spec); notify_pkt_done(zone, index); return; } if(!xfrd_notify_send_udp(zone, index)) { notify_pkt_retry(zone, index); } } static void xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet, struct sockaddr* src, socklen_t srclen) { int i; for(i=0; ipkts[i].dest) continue; /* based on destination */ if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest)) continue; if(reply_pkt_is_ack(zone, packet, i)) { /* is done */ notify_pkt_done(zone, i); return; } else { /* retry */ notify_pkt_retry(zone, i); return; } } } static int xfrd_notify_send_udp(struct notify_zone* zone, int index) { int apex_compress = 0; buffer_type* packet = xfrd_get_temp_buffer(); if(!zone->pkts[index].dest) return 0; /* send NOTIFY to secondary. */ xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex, qid_generate(), &apex_compress); zone->pkts[index].notify_query_id = ID(packet); OPCODE_SET(packet, OPCODE_NOTIFY); AA_SET(packet); if(zone->current_soa->serial != 0) { /* add current SOA to answer section */ ANCOUNT_SET(packet, 1); xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa, apex_compress); } if(zone->pkts[index].dest->key_options) { xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest); } buffer_flip(packet); if((zone->pkts[index].dest->is_ipv6 && zone->notify_send6_handler.ev_fd == -1) || (!zone->pkts[index].dest->is_ipv6 && zone->notify_send_handler.ev_fd == -1)) { /* open fd */ int fd = xfrd_send_udp(zone->pkts[index].dest, packet, zone->options->pattern->outgoing_interface); if(fd == -1) { log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s", zone->apex_str, zone->pkts[index].notify_retry, zone->pkts[index].dest->ip_address_spec); return 0; } if(zone->pkts[index].dest->is_ipv6) zone->notify_send6_handler.ev_fd = fd; else zone->notify_send_handler.ev_fd = fd; } else { /* send on existing fd */ #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif /* INET6 */ int fd; socklen_t to_len = xfrd_acl_sockaddr_to( zone->pkts[index].dest, &to); if(zone->pkts[index].dest->is_ipv6 && zone->notify_send6_handler.ev_fd != -1) fd = zone->notify_send6_handler.ev_fd; else if (zone->notify_send_handler.ev_fd != -1) fd = zone->notify_send_handler.ev_fd; else { log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s", zone->pkts[index].dest->ip_address_spec, "invalid file descriptor"); return 0; } if(sendto(fd, buffer_current(packet), buffer_remaining(packet), 0, (struct sockaddr*)&to, to_len) == -1) { log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s", zone->pkts[index].dest->ip_address_spec, strerror(errno)); return 0; } } zone->pkts[index].send_time = time(NULL); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s", zone->apex_str, zone->pkts[index].notify_retry, zone->pkts[index].dest->ip_address_spec)); return 1; } static void notify_timeout_check(struct notify_zone* zone) { time_t now = time(NULL); int i; for(i=0; ipkts[i].dest) continue; if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) { notify_pkt_retry(zone, i); } } } static void notify_start_pkts(struct notify_zone* zone) { int i; if(!zone->notify_current) return; /* no more acl to send to */ for(i=0; ipkts[i].dest==NULL && zone->notify_current) { zone->pkts[i].dest = zone->notify_current; zone->notify_current = zone->notify_current->next; zone->pkts[i].notify_retry = 0; zone->pkts[i].notify_query_id = 0; zone->pkts[i].send_time = 0; zone->notify_pkt_count++; if(!xfrd_notify_send_udp(zone, i)) { notify_pkt_retry(zone, i); } } } } static void notify_setup_event(struct notify_zone* zone) { if(zone->notify_send_handler.ev_fd != -1) { int fd = zone->notify_send_handler.ev_fd; if(zone->notify_send_enable) { event_del(&zone->notify_send_handler); } zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; memset(&zone->notify_send_handler, 0, sizeof(zone->notify_send_handler)); event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notify_send: event_add failed"); zone->notify_send_enable = 1; } if(zone->notify_send6_handler.ev_fd != -1) { int fd = zone->notify_send6_handler.ev_fd; if(zone->notify_send6_enable) { event_del(&zone->notify_send6_handler); } zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; memset(&zone->notify_send6_handler, 0, sizeof(zone->notify_send6_handler)); event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); if(event_add(&zone->notify_send6_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notify_send: event_add failed"); zone->notify_send6_enable = 1; } } static void xfrd_handle_notify_send(int fd, short event, void* arg) { struct notify_zone* zone = (struct notify_zone*)arg; buffer_type* packet = xfrd_get_temp_buffer(); if(zone->is_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: notify waiting, skipped, %s", zone->apex_str)); return; } if((event & EV_READ)) { struct sockaddr_storage src; socklen_t srclen = (socklen_t)sizeof(src); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: read notify ACK", zone->apex_str)); assert(fd != -1); if(xfrd_udp_read_packet(packet, fd, (struct sockaddr*)&src, &srclen)) { /* find entry, send retry or make entry NULL */ xfrd_handle_notify_reply(zone, packet, (struct sockaddr*)&src, srclen); } } if((event & EV_TIMEOUT)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout", zone->apex_str)); /* timeout, try again */ } /* see which pkts have timeouted, retry or NULL them */ notify_timeout_check(zone); /* start new packets if we have empty space */ notify_start_pkts(zone); /* see if we are done */ if(!zone->notify_current && !zone->notify_pkt_count) { /* we are done */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: no more notify-send acls. stop notify.", zone->apex_str)); notify_disable(zone); return; } notify_setup_event(zone); } static void setup_notify_active(struct notify_zone* zone) { zone->notify_pkt_count = 0; memset(zone->pkts, 0, sizeof(zone->pkts)); zone->notify_current = zone->options->pattern->notify; zone->notify_timeout.tv_sec = 0; zone->notify_timeout.tv_usec = 0; if(zone->notify_send_enable) notify_send_disable(zone); memset(&zone->notify_send_handler, 0, sizeof(zone->notify_send_handler)); event_set(&zone->notify_send_handler, -1, EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notifysend: event_base_set failed"); if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notifysend: evtimer_add failed"); zone->notify_send_enable = 1; } static void notify_enable(struct notify_zone* zone, struct xfrd_soa* new_soa) { if(!zone->options->pattern->notify) { return; /* no notify acl, nothing to do */ } if(new_soa == NULL) memset(zone->current_soa, 0, sizeof(xfrd_soa_type)); else memcpy(zone->current_soa, new_soa, sizeof(xfrd_soa_type)); if(zone->is_waiting) return; if(xfrd->notify_udp_num < XFRD_MAX_UDP_NOTIFY) { setup_notify_active(zone); xfrd->notify_udp_num++; return; } /* put it in waiting list */ zone->notify_current = zone->options->pattern->notify; zone->is_waiting = 1; zone->waiting_next = NULL; zone->waiting_prev = xfrd->notify_waiting_last; if(xfrd->notify_waiting_last) { xfrd->notify_waiting_last->waiting_next = zone; } else { xfrd->notify_waiting_first = zone; } xfrd->notify_waiting_last = zone; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify on waiting list.", zone->apex_str)); } void xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd) { xfrd_zone_type* xz; if(zone->is_waiting || zone->notify_send_enable || zone->notify_send6_enable) return; xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, zone->apex); if(xz && xz->soa_nsd_acquired) notify_enable(zone, &xz->soa_nsd); else notify_enable(zone, NULL); } void xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa) { /* lookup the zone */ struct notify_zone* zone = (struct notify_zone*) rbtree_search(tree, apex); assert(zone); if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); } void notify_handle_master_zone_soainfo(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa) { /* lookup the zone */ struct notify_zone* zone = (struct notify_zone*) rbtree_search(tree, apex); if(!zone) return; /* got SOAINFO but zone was deleted meanwhile */ /* check if SOA changed */ if( (new_soa == NULL && zone->current_soa->serial == 0) || (new_soa && new_soa->serial == zone->current_soa->serial)) return; if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); } void close_notify_fds(rbtree_type* tree) { struct notify_zone* zone; RBTREE_FOR(zone, struct notify_zone*, tree) { if(zone->notify_send_enable || zone->notify_send6_enable) notify_send_disable(zone); } } nsd-4.12.0/xfrd-disk.h0000644000175000017500000000177115002373054014047 0ustar mozziemozzie/* * xfrd-disk.h - XFR (transfer) Daemon TCP system header file. Save/Load state to disk. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_DISK_H #define XFRD_DISK_H struct xfrd_state; struct nsd; /* magic string to identify xfrd state file */ #define XFRD_FILE_MAGIC "NSDXFRD2" /* read from state file as many zones as possible (until error/eof).*/ void xfrd_read_state(struct xfrd_state* xfrd); /* write xfrd zone state if possible */ void xfrd_write_state(struct xfrd_state* xfrd); /* create temp directory */ void xfrd_make_tempdir(struct nsd* nsd); /* rmdir temp directory */ void xfrd_del_tempdir(struct nsd* nsd); /* open temp file, makes directory if needed */ FILE* xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode); /* unlink temp file */ void xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number); /* get temp file size */ uint64_t xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ); #endif /* XFRD_DISK_H */ nsd-4.12.0/xfrd-disk.c0000644000175000017500000004150415002373054014040 0ustar mozziemozzie/* * xfrd-disk.c - XFR (transfer) Daemon TCP system source file. Read/Write state to disk. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "xfrd-disk.h" #include "xfrd.h" #include "buffer.h" #include "nsd.h" #include "options.h" /* quick tokenizer, reads words separated by whitespace. No quoted strings. Comments are skipped (#... eol). */ static char* xfrd_read_token(FILE* in) { static char buf[4000]; buf[sizeof(buf)-1]=0; while(1) { if(fscanf(in, " %3990s", buf) != 1) return 0; if(buf[0] != '#') return buf; if(!fgets(buf, sizeof(buf), in)) return 0; } } static int xfrd_read_i16(FILE *in, uint16_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atoi(p); return 1; } static int xfrd_read_i32(FILE *in, uint32_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atoi(p); return 1; } static int xfrd_read_time_t(FILE *in, time_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atol(p); return 1; } static int xfrd_read_check_str(FILE* in, const char* str) { char *p = xfrd_read_token(in); if(!p) return 0; if(strcmp(p, str) != 0) return 0; return 1; } static int xfrd_read_state_soa(FILE* in, const char* id_acquired, const char* id, xfrd_soa_type* soa, time_t* soatime) { char *p; if(!xfrd_read_check_str(in, id_acquired) || !xfrd_read_time_t(in, soatime)) { return 0; } if(*soatime == 0) return 1; if(!xfrd_read_check_str(in, id) || !xfrd_read_i16(in, &soa->type) || !xfrd_read_i16(in, &soa->klass) || !xfrd_read_i32(in, &soa->ttl) || !xfrd_read_i16(in, &soa->rdata_count)) { return 0; } soa->type = htons(soa->type); soa->klass = htons(soa->klass); soa->ttl = htonl(soa->ttl); soa->rdata_count = htons(soa->rdata_count); if(!(p=xfrd_read_token(in)) || !(soa->prim_ns[0] = dname_parse_wire(soa->prim_ns+1, p))) return 0; if(!(p=xfrd_read_token(in)) || !(soa->email[0] = dname_parse_wire(soa->email+1, p))) return 0; if(!xfrd_read_i32(in, &soa->serial) || !xfrd_read_i32(in, &soa->refresh) || !xfrd_read_i32(in, &soa->retry) || !xfrd_read_i32(in, &soa->expire) || !xfrd_read_i32(in, &soa->minimum)) { return 0; } soa->serial = htonl(soa->serial); soa->refresh = htonl(soa->refresh); soa->retry = htonl(soa->retry); soa->expire = htonl(soa->expire); soa->minimum = htonl(soa->minimum); return 1; } void xfrd_read_state(struct xfrd_state* xfrd) { const char* statefile = xfrd->nsd->options->xfrdfile; FILE *in; uint32_t filetime = 0; uint32_t numzones, i; region_type *tempregion; time_t soa_refresh; tempregion = region_create(xalloc, free); if(!tempregion) return; in = fopen(statefile, "r"); if(!in) { if(errno != ENOENT) { log_msg(LOG_ERR, "xfrd: Could not open file %s for reading: %s", statefile, strerror(errno)); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: no file %s. refreshing all zones.", statefile)); } region_destroy(tempregion); return; } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) { /* older file version; reset everything */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: file %s is old version. refreshing all zones.", statefile)); fclose(in); region_destroy(tempregion); return; } if(!xfrd_read_check_str(in, "filetime:") || !xfrd_read_i32(in, &filetime) || (time_t)filetime > xfrd_time()+15 || !xfrd_read_check_str(in, "numzones:") || !xfrd_read_i32(in, &numzones)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } for(i=0; i2) || !xfrd_read_check_str(in, "master:") || !xfrd_read_i32(in, &masnum) || !xfrd_read_check_str(in, "next_master:") || !xfrd_read_i32(in, &nextmas) || !xfrd_read_check_str(in, "round_num:") || !xfrd_read_i32(in, &round_num) || !xfrd_read_check_str(in, "next_timeout:") || !xfrd_read_i32(in, &timeout) || !xfrd_read_check_str(in, "backoff:") || !xfrd_read_i32(in, &backoff) || !xfrd_read_state_soa(in, "soa_nsd_acquired:", "soa_nsd:", &soa_nsd_read, &soa_nsd_acquired_read) || !xfrd_read_state_soa(in, "soa_disk_acquired:", "soa_disk:", &soa_disk_read, &soa_disk_acquired_read) || !xfrd_read_state_soa(in, "soa_notify_acquired:", "soa_notify:", &soa_notified_read, &soa_notified_acquired_read)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, dname); if(!zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: state file has info for not configured zone %s", p)); continue; } if(soa_nsd_acquired_read>xfrd_time()+15 || soa_disk_acquired_read>xfrd_time()+15 || soa_notified_acquired_read>xfrd_time()+15) { log_msg(LOG_ERR, "xfrd: statefile %s contains" " times in the future for zone %s. Ignoring.", statefile, zone->apex_str); continue; } zone->state = state; zone->master_num = masnum; zone->next_master = nextmas; zone->round_num = round_num; zone->timeout.tv_sec = timeout; zone->timeout.tv_usec = 0; zone->fresh_xfr_timeout = backoff*XFRD_TRANSFER_TIMEOUT_START; /* read the zone OK, now set the master properly */ zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); if(!zone->master) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: primaries changed for zone %s", zone->apex_str)); zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; zone->round_num = 0; } /* * There is no timeout, * or there is a notification, * or there is a soa && current time is past refresh point */ soa_refresh = ntohl(soa_disk_read.refresh); if (soa_refresh > (time_t)zone->zone_options->pattern->max_refresh_time) soa_refresh = zone->zone_options->pattern->max_refresh_time; else if (soa_refresh < (time_t)zone->zone_options->pattern->min_refresh_time) soa_refresh = zone->zone_options->pattern->min_refresh_time; if(timeout == 0 || soa_notified_acquired_read != 0 || (soa_disk_acquired_read != 0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > (uint32_t)soa_refresh)) { zone->state = xfrd_zone_refreshing; xfrd_set_refresh_now(zone); } if(timeout != 0 && filetime + timeout < (uint32_t)xfrd_time()) { /* timeout is in the past, refresh the zone */ timeout = 0; if(zone->state == xfrd_zone_ok) zone->state = xfrd_zone_refreshing; xfrd_set_refresh_now(zone); } /* There is a soa && current time is past expiry point */ if(soa_disk_acquired_read!=0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > ntohl(soa_disk_read.expire)) { zone->state = xfrd_zone_expired; xfrd_set_refresh_now(zone); } /* there is a zone read and it matches what we had before */ if(zone->soa_nsd_acquired && zone->state != xfrd_zone_expired && zone->soa_nsd.serial == soa_nsd_read.serial) { xfrd_deactivate_zone(zone); zone->state = state; xfrd_set_timer(zone, within_refresh_bounds(zone, timeout)); } if((zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 && soa_disk_acquired_read == 0) || (zone->state != xfrd_zone_ok && timeout != 0)) { /* but don't check now, because that would mean a * storm of attempts on some master servers */ xfrd_deactivate_zone(zone); zone->state = state; xfrd_set_timer(zone, within_retry_bounds(zone, timeout)); } /* handle as an incoming SOA. */ incoming_soa = zone->soa_nsd; incoming_acquired = zone->soa_nsd_acquired; zone->soa_nsd = soa_nsd_read; zone->soa_nsd_acquired = soa_nsd_acquired_read; /* use soa and soa_acquired from starting NSD, not what is stored in * the state file, because the actual zone contents trumps the contents * of this cache */ zone->soa_disk = incoming_soa; zone->soa_disk_acquired = incoming_acquired; zone->soa_notified = soa_notified_read; zone->soa_notified_acquired = soa_notified_acquired_read; if (zone->state == xfrd_zone_expired) { xfrd_send_expire_notification(zone); } if(incoming_acquired != 0) xfrd_handle_incoming_soa(zone, &incoming_soa, incoming_acquired); } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); region_destroy(tempregion); fclose(in); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: read %d zones from state file", (int)numzones)); fclose(in); region_destroy(tempregion); } /* prints neato days hours and minutes. */ static void neato_timeout(FILE* out, const char* str, time_t secs) { fprintf(out, "%s", str); if(secs <= 0) { fprintf(out, " %llds", (long long)secs); return; } if(secs >= 3600*24) { fprintf(out, " %lldd", (long long)(secs/(3600*24))); secs = secs % (3600*24); } if(secs >= 3600) { fprintf(out, " %lldh", (long long)(secs/3600)); secs = secs%3600; } if(secs >= 60) { fprintf(out, " %lldm", (long long)(secs/60)); secs = secs%60; } if(secs > 0) { fprintf(out, " %llds", (long long)secs); } } static void xfrd_write_dname(FILE* out, uint8_t* dname) { uint8_t* d= dname+1; uint8_t len = *d++; uint8_t i; if(dname[0]<=1) { fprintf(out, "."); return; } while(len) { assert(d - (dname+1) <= dname[0]); for(i=0; itype), (unsigned)ntohs(soa->klass), (unsigned)ntohl(soa->ttl), (unsigned)ntohs(soa->rdata_count)); fprintf(out, " "); xfrd_write_dname(out, soa->prim_ns); fprintf(out, " "); xfrd_write_dname(out, soa->email); fprintf(out, " %u", (unsigned)ntohl(soa->serial)); fprintf(out, " %u", (unsigned)ntohl(soa->refresh)); fprintf(out, " %u", (unsigned)ntohl(soa->retry)); fprintf(out, " %u", (unsigned)ntohl(soa->expire)); fprintf(out, " %u\n", (unsigned)ntohl(soa->minimum)); fprintf(out, "\t#"); neato_timeout(out, " refresh =", ntohl(soa->refresh)); neato_timeout(out, " retry =", ntohl(soa->retry)); neato_timeout(out, " expire =", ntohl(soa->expire)); neato_timeout(out, " minimum =", ntohl(soa->minimum)); fprintf(out, "\n"); } void xfrd_write_state(struct xfrd_state* xfrd) { rbnode_type* p; const char* statefile = xfrd->nsd->options->xfrdfile; FILE *out; time_t now = xfrd_time(); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: write file %s", statefile)); out = fopen(statefile, "w"); if(!out) { log_msg(LOG_ERR, "xfrd: Could not open file %s for writing: %s", statefile, strerror(errno)); return; } fprintf(out, "%s\n", XFRD_FILE_MAGIC); fprintf(out, "# This file is written on exit by nsd xfr daemon.\n"); fprintf(out, "# This file contains secondary zone information:\n"); fprintf(out, "# * timeouts (when was zone data acquired)\n"); fprintf(out, "# * state (OK, refreshing, expired)\n"); fprintf(out, "# * which primary transfer to attempt next\n"); fprintf(out, "# The file is read on start (but not on reload) by nsd xfr daemon.\n"); fprintf(out, "# You can edit; but do not change statement order\n"); fprintf(out, "# and no fancy stuff (like quoted \"strings\").\n"); fprintf(out, "#\n"); fprintf(out, "# If you remove a zone entry, it will be refreshed.\n"); fprintf(out, "# This can be useful for an expired zone; it revives\n"); fprintf(out, "# the zone temporarily, from refresh-expiry time.\n"); fprintf(out, "# If you delete the file all secondary zones are updated.\n"); fprintf(out, "#\n"); fprintf(out, "# Note: if you edit this file while nsd is running,\n"); fprintf(out, "# it will be overwritten on exit by nsd.\n"); fprintf(out, "\n"); fprintf(out, "filetime: %lld\t# %s\n", (long long)now, ctime(&now)); fprintf(out, "# The number of zone entries in this file\n"); fprintf(out, "numzones: %d\n", (int)xfrd->zones->count); fprintf(out, "\n"); for(p = rbtree_first(xfrd->zones); p && p!=RBTREE_NULL; p=rbtree_next(p)) { xfrd_zone_type* zone = (xfrd_zone_type*)p; fprintf(out, "zone: \tname: %s\n", zone->apex_str); fprintf(out, "\tstate: %d", (int)zone->state); fprintf(out, " # %s", zone->state==xfrd_zone_ok?"OK":( zone->state==xfrd_zone_refreshing?"refreshing":"expired")); fprintf(out, "\n"); fprintf(out, "\tmaster: %d\n", zone->master_num); fprintf(out, "\tnext_master: %d\n", zone->next_master); fprintf(out, "\tround_num: %d\n", zone->round_num); fprintf(out, "\tnext_timeout: %d", (zone->zone_handler_flags&EV_TIMEOUT)?(int)zone->timeout.tv_sec:0); if((zone->zone_handler_flags&EV_TIMEOUT)) { neato_timeout(out, "\t# =", zone->timeout.tv_sec); } fprintf(out, "\n"); fprintf(out, "\tbackoff: %d\n", zone->fresh_xfr_timeout/XFRD_TRANSFER_TIMEOUT_START); xfrd_write_state_soa(out, "soa_nsd", &zone->soa_nsd, zone->soa_nsd_acquired, zone->apex); xfrd_write_state_soa(out, "soa_disk", &zone->soa_disk, zone->soa_disk_acquired, zone->apex); xfrd_write_state_soa(out, "soa_notify", &zone->soa_notified, zone->soa_notified_acquired, zone->apex); fprintf(out, "\n"); } fprintf(out, "%s\n", XFRD_FILE_MAGIC); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: written %d zones to state file", (int)xfrd->zones->count)); fclose(out); } /* return tempdirname */ static void tempdirname(char* buf, size_t sz, struct nsd* nsd) { snprintf(buf, sz, "%snsd-xfr-%d", nsd->options->xfrdir, (int)nsd->pid); } void xfrd_make_tempdir(struct nsd* nsd) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); /* create parent directories if needed (0750 permissions) */ if(!create_dirs(tnm)) { log_msg(LOG_ERR, "parentdirs of %s failed", tnm); } /* restrictive permissions here, because this may be in /tmp */ if(mkdir(tnm, 0700)==-1) { if(errno != EEXIST) { log_msg(LOG_ERR, "mkdir %s failed: %s", tnm, strerror(errno)); } } } void xfrd_del_tempdir(struct nsd* nsd) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); /* ignore parent directories, they are likely /var/tmp, /tmp or * /var/cache/nsd and do not have to be deleted */ if(rmdir(tnm)==-1 && errno != ENOENT) { log_msg(LOG_WARNING, "rmdir %s failed: %s", tnm, strerror(errno)); } } /* return name of xfrfile in tempdir */ static void tempxfrname(char* buf, size_t sz, struct nsd* nsd, uint64_t number) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); snprintf(buf, sz, "%s/xfr.%lld", tnm, (long long)number); } FILE* xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode) { char fname[1200]; FILE* xfr; tempxfrname(fname, sizeof(fname), nsd, number); xfr = fopen(fname, mode); if(!xfr && errno == ENOENT) { /* directory may not exist */ xfrd_make_tempdir(nsd); xfr = fopen(fname, mode); } if(!xfr) { log_msg(LOG_ERR, "open %s for %s failed: %s", fname, mode, strerror(errno)); return NULL; } return xfr; } void xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number) { char fname[1200]; tempxfrname(fname, sizeof(fname), nsd, number); if(unlink(fname) == -1) { log_msg(LOG_WARNING, "could not unlink %s: %s", fname, strerror(errno)); } } uint64_t xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ) { char fname[1200]; struct stat tempxfr_stat; tempxfrname(fname, sizeof(fname), nsd, number); if( stat( fname, &tempxfr_stat ) < 0 ) { log_msg(LOG_WARNING, "could not get file size %s: %s", fname, strerror(errno)); return 0; } return (uint64_t)tempxfr_stat.st_size; } nsd-4.12.0/xfrd-catalog-zones.h0000644000175000017500000000760115002373054015661 0ustar mozziemozzie/* * xfrd-catalog-zones.h -- catalog zone implementation for NSD * * Copyright (c) 2024, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #ifndef XFRD_CATALOG_ZONES_H #define XFRD_CATALOG_ZONES_H #include "xfrd.h" struct xfrd_producer_member; struct xfrd_producer_xfr; /** * Catalog zones withing the xfrd context */ struct xfrd_catalog_consumer_zone { /* For indexing in struc xfrd_state { rbtree_type* catalog_consumer_zones; } */ rbnode_type node; /* Associated zone options with this catalog consumer zone */ struct zone_options* options; /* Member zones indexed by member_id */ rbtree_type member_ids; /* Last time processed, compare with zone->mtime to see if we need to process */ struct timespec mtime; /* The reason for this zone to be invalid, or NULL if it is valid */ char *invalid; } ATTR_PACKED; /** * Catalog producer zones withing the xfrd context */ struct xfrd_catalog_producer_zone { /* For indexing in struc xfrd_state { rbtree_type* catalog_producer_zones; } */ rbnode_type node; /* Associated zone options with this catalog consumer zone */ struct zone_options* options; /* Member zones indexed by member_id */ rbtree_type member_ids; /* SOA serial for this zone */ uint32_t serial; /* Stack of members to delete from this catalog producer zone */ struct xfrd_producer_member* to_delete; /* Stack of member zones to add to this catalog producer zone */ struct xfrd_producer_member* to_add; /* To cleanup on disk xfr files */ struct xfrd_producer_xfr* latest_pxfr; /* Set if next generated xfr for the producer zone should be axfr */ unsigned axfr: 1; } ATTR_PACKED; /** * Data to add or remove from a catalog producer zone */ struct xfrd_producer_member { const dname_type* member_id; const dname_type* member_zone_name; const char* group_name; struct xfrd_producer_member* next; } ATTR_PACKED; /** * To track applied generated transfers from catalog producer zones */ struct xfrd_producer_xfr { uint32_t serial; uint64_t xfrfilenumber; struct xfrd_producer_xfr** prev_next_ptr; struct xfrd_producer_xfr* next; } ATTR_PACKED; /* Initialize as a catalog consumer zone */ void xfrd_init_catalog_consumer_zone(xfrd_state_type* xfrd, struct zone_options* zone); /* To be called if and a zone is no longer a catalog zone (changed pattern) */ void xfrd_deinit_catalog_consumer_zone(xfrd_state_type* xfrd, const dname_type* dname); /* make the catalog consumer zone invalid for given reason */ void make_catalog_consumer_invalid( struct xfrd_catalog_consumer_zone *consumer_zone, const char *format, ...) ATTR_FORMAT(printf, 2, 3); /* Return the reason a zone is invalid, or NULL on a valid catalog */ const char *invalid_catalog_consumer_zone(struct zone_options* zone); /* make the catalog consumer zone valid again */ void make_catalog_consumer_valid( struct xfrd_catalog_consumer_zone *consumer_zone); /* Check the catalog consumer zone files (or file if zone is given) */ void xfrd_check_catalog_consumer_zonefiles(const dname_type* name); /* process the catalog consumer zones, load if needed */ void xfrd_process_catalog_consumer_zones(); /* Add (or change) PTR , and * group. TXT pname> to the associated producer zone by * constructed xfr. make cmz->member_id if needed. */ void xfrd_add_catalog_producer_member(struct catalog_member_zone* cmz); /* Delete PTR , and * group. TXT pname> from the associated producer zone by * constructed xfr. Return 1 if zone is deleted. In this case, member_zone_name * is taken over by xfrd and cannot be recycled by the caller. member_zone_name * must have been allocated int the xfrd->nsd->options->region */ int xfrd_del_catalog_producer_member(xfrd_state_type* xfrd, const dname_type* dname); /* process the catalog producer zones */ void xfrd_process_catalog_producer_zones(); #endif nsd-4.12.0/xfrd-catalog-zones.c0000644000175000017500000012502315002373054015653 0ustar mozziemozzie/* * xfrd-catalog-zones.c -- catalog zone implementation for NSD * * Copyright (c) 2024, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #include "config.h" #include "difffile.h" #include "nsd.h" #include "packet.h" #include "xfrd-catalog-zones.h" #include "xfrd-notify.h" /****************** ****************** ****************** catalog consumer zone processing ****************** ****************** ******************/ /** process a catalog consumer zone, load if needed */ static void xfrd_process_catalog_consumer_zone( struct xfrd_catalog_consumer_zone* consumer_zone); /** make the catalog consumer zone invalid for given reason */ static void vmake_catalog_consumer_invalid( struct xfrd_catalog_consumer_zone *consumer_zone, const char *format, va_list args); /** return (static) dname with label prepended to dname */ static dname_type* label_plus_dname(const char* label,const dname_type* dname); /** delete the catalog member zone */ static void catalog_del_consumer_member_zone( struct xfrd_catalog_consumer_zone* consumer_zone, struct catalog_member_zone* consumer_member_zone); #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES /* return a single catalog consumer zone from xfrd struct */ static inline struct xfrd_catalog_consumer_zone* xfrd_one_catalog_consumer_zone() { return xfrd && xfrd->catalog_consumer_zones && xfrd->catalog_consumer_zones->count == 1 ? (struct xfrd_catalog_consumer_zone*) rbtree_first(xfrd->catalog_consumer_zones) : NULL; } #endif /** return the catalog-member-pattern or NULL on error if not present */ static inline struct pattern_options* catalog_member_pattern(struct xfrd_catalog_consumer_zone* consumer_zone) { if (!consumer_zone->options->pattern || !consumer_zone->options->pattern->catalog_member_pattern) return NULL; return pattern_options_find(xfrd->nsd->options, consumer_zone->options->pattern->catalog_member_pattern); } /** see if we have more zonestatistics entries and it has to be incremented */ static inline void zonestat_inc_ifneeded() { #ifdef USE_ZONE_STATS if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe) task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, xfrd->nsd->options->zonestatnames->count); #endif /* USE_ZONE_STATS */ } /****************** ****************** ****************** catalog producer zone processing ****************** ****************** ******************/ /** process catalog producer zone producer_zone */ static void xfrd_process_catalog_producer_zone( struct xfrd_catalog_producer_zone* producer_zone); /** rbnode must be struct catalog_member_zone*; compares (key->member_id) */ static int member_id_compare(const void *left, const void *right); /** return xfrd_catalog_producer_zone* pointed to by cmz' catalog-producer-zone * pattern option. struct is created if necessary. returns NULL on failure. */ static struct xfrd_catalog_producer_zone* xfrd_get_catalog_producer_zone( struct catalog_member_zone* cmz); /** helper struct for generating XFR files, for conveying the catalog producer * zone content to the server process. */ struct xfrd_xfr_writer { struct xfrd_catalog_producer_zone* producer_zone; char packet_space[16384]; buffer_type packet; uint32_t seq_nr; /* number of messages already handled */ uint32_t old_serial, new_serial; /* host byte order */ uint64_t xfrfilenumber; /* identifier for file to store xfr into */ }; /** initialize xfrd_xfr_writer struct xw */ static void xfr_writer_init(struct xfrd_xfr_writer* xw, struct xfrd_catalog_producer_zone* producer_zone); /** write packet from xfrd_xfr_writer struct xw to xfr file */ static void xfr_writer_write_packet(struct xfrd_xfr_writer* xw); /** commit xfr file (send to server process), with provided log message */ static void xfr_writer_commit(struct xfrd_xfr_writer* xw, const char *fmt, ...); /** try writing SOA RR with serial to packet buffer. returns 0 on failure */ static int try_buffer_write_SOA(buffer_type* packet, const dname_type* owner, uint32_t serial); /** try writing RR to packet buffer. returns 0 on failure */ static int try_buffer_write_RR(buffer_type* packet, const dname_type* owner, uint16_t rr_type, uint16_t rdata_len, const void* rdata); /** try writing PTR RR to packet buffer. returns 0 on failure */ static inline int try_buffer_write_PTR(buffer_type* packet, const dname_type* owner, const dname_type* name); /** try writing TXT RR to packet buffer. returns 0 on failure */ static int try_buffer_write_TXT(buffer_type* packet, const dname_type* name, const char *txt); /** add SOA RR with serial serial to xfrd_xfr_writer xw */ static inline void xfr_writer_add_SOA(struct xfrd_xfr_writer* xw, const dname_type* owner, uint32_t serial) { if(try_buffer_write_SOA(&xw->packet, owner, serial)) return; xfr_writer_write_packet(xw); assert(buffer_position(&xw->packet) == 12); try_buffer_write_SOA(&xw->packet, owner, serial); } /** add RR to xfrd_xfr_writer xw */ static inline void xfr_writer_add_RR(struct xfrd_xfr_writer* xw, const dname_type* owner, uint16_t rr_type, uint16_t rdata_len, const void* rdata) { if(try_buffer_write_RR(&xw->packet, owner, rr_type, rdata_len, rdata)) return; xfr_writer_write_packet(xw); assert(buffer_position(&xw->packet) == 12); try_buffer_write_RR(&xw->packet, owner, rr_type, rdata_len, rdata); } /** add PTR RR to xfrd_xfr_writer xw */ static inline void xfr_writer_add_PTR(struct xfrd_xfr_writer* xw, const dname_type* owner, const dname_type* name) { if(try_buffer_write_PTR(&xw->packet, owner, name)) return; xfr_writer_write_packet(xw); assert(buffer_position(&xw->packet) == 12); try_buffer_write_PTR(&xw->packet, owner, name); } /** add TXT RR to xfrd_xfr_writer xw */ static inline void xfr_writer_add_TXT(struct xfrd_xfr_writer* xw, const dname_type* owner, const char* txt) { if(try_buffer_write_TXT(&xw->packet, owner, txt)) return; xfr_writer_write_packet(xw); assert(buffer_position(&xw->packet) == 12); try_buffer_write_TXT(&xw->packet, owner, txt); } /****************** ****************** ****************** catalog consumer zone processing ****************** ****************** ******************/ void xfrd_init_catalog_consumer_zone(xfrd_state_type* xfrd, struct zone_options* zone) { struct xfrd_catalog_consumer_zone* consumer_zone; if ((consumer_zone = (struct xfrd_catalog_consumer_zone*)rbtree_search( xfrd->catalog_consumer_zones, zone->node.key))) { log_msg(LOG_ERR, "cannot initialize new catalog consumer zone:" " '%s: it already exists in xfrd's catalog " " consumer zones index", zone->name); /* Maybe we need to reprocess it? */ make_catalog_consumer_valid(consumer_zone); return; } consumer_zone = (struct xfrd_catalog_consumer_zone*) region_alloc(xfrd->region, sizeof(struct xfrd_catalog_consumer_zone)); memset(consumer_zone, 0, sizeof(struct xfrd_catalog_consumer_zone)); consumer_zone->node.key = zone->node.key; consumer_zone->options = zone; consumer_zone->member_ids.region = xfrd->region; consumer_zone->member_ids.root = RBTREE_NULL; consumer_zone->member_ids.count = 0; consumer_zone->member_ids.cmp = member_id_compare; consumer_zone->mtime.tv_sec = 0; consumer_zone->mtime.tv_nsec = 0; consumer_zone->invalid = NULL; rbtree_insert(xfrd->catalog_consumer_zones, (rbnode_type*)consumer_zone); #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES if ((int)xfrd->catalog_consumer_zones->count > 1) { log_msg(LOG_ERR, "catalog consumer processing disabled: " "only one single catalog consumer zone allowed"); } #endif if(zone->pattern && zone->pattern->store_ixfr) { /* Don't process ixfrs from xfrd */ zone->pattern->store_ixfr = 0; } } void xfrd_deinit_catalog_consumer_zone(xfrd_state_type* xfrd, const dname_type* dname) { struct xfrd_catalog_consumer_zone* consumer_zone; zone_type* zone; if (!(consumer_zone =(struct xfrd_catalog_consumer_zone*)rbtree_delete( xfrd->catalog_consumer_zones, dname))) { log_msg(LOG_ERR, "cannot de-initialize catalog consumer zone:" " '%s: it did not exist in xfrd's catalog " " consumer zones index", dname_to_string(dname, NULL)); return; } if (consumer_zone->member_ids.count) log_msg(LOG_WARNING, "de-initialize catalog consumer zone:" " '%s: will cause all member zones to be " " deleted", consumer_zone->options->name); while (consumer_zone->member_ids.count) { struct catalog_member_zone* cmz = (struct catalog_member_zone*) rbtree_first(&consumer_zone->member_ids)->key; log_msg(LOG_INFO, "deleting member zone '%s' on " "de-initializing catalog consumer zone '%s'", cmz->options.name, consumer_zone->options->name); catalog_del_consumer_member_zone(consumer_zone, cmz); } if ((zone = namedb_find_zone(xfrd->nsd->db, dname))) { namedb_zone_delete(xfrd->nsd->db, zone); } region_recycle(xfrd->region, consumer_zone, sizeof(*consumer_zone)); #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES if((consumer_zone = xfrd_one_catalog_consumer_zone()) && consumer_zone->options && consumer_zone->options->node.key) { xfrd_zone_type* zone = (xfrd_zone_type*)rbtree_search( xfrd->zones, (const dname_type*)consumer_zone->options->node.key); if(zone) { zone->soa_disk_acquired = 0; zone->soa_nsd_acquired = 0; xfrd_handle_notify_and_start_xfr(zone, NULL); } } #endif } /** make the catalog consumer zone invalid for given reason */ static void vmake_catalog_consumer_invalid( struct xfrd_catalog_consumer_zone *consumer_zone, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; if (!consumer_zone || consumer_zone->invalid) return; vsnprintf(message, sizeof(message), format, args); log_msg(LOG_ERR, "invalid catalog consumer zone '%s': %s", consumer_zone->options->name, message); consumer_zone->invalid = region_strdup(xfrd->region, message); } void make_catalog_consumer_invalid(struct xfrd_catalog_consumer_zone *consumer_zone, const char *format, ...) { va_list args; if (!consumer_zone || consumer_zone->invalid) return; va_start(args, format); vmake_catalog_consumer_invalid(consumer_zone, format, args); va_end(args); } void make_catalog_consumer_valid(struct xfrd_catalog_consumer_zone *consumer_zone) { if (consumer_zone->invalid) { region_recycle(xfrd->region, consumer_zone->invalid, strlen(consumer_zone->invalid) + 1); consumer_zone->invalid = NULL; } } static dname_type* label_plus_dname(const char* label, const dname_type* dname) { static struct { dname_type dname; uint8_t bytes[MAXDOMAINLEN + 128 /* max number of labels */]; } ATTR_PACKED name; size_t i, ll; if (!label || !dname || dname->label_count > 127) return NULL; ll = strlen(label); if ((int)dname->name_size + ll + 1 > MAXDOMAINLEN) return NULL; /* In reversed order and first copy with memmove, so we can nest. * i.e. label_plus_dname(label1, label_plus_dname(label2, dname)) */ memmove(name.bytes + dname->label_count + 1 /* label_count increases by one */ + 1 /* label type/length byte for label */ + ll, ((char*)dname) + sizeof(dname_type) + dname->label_count, dname->name_size); memcpy(name.bytes + dname->label_count + 1 /* label_count increases by one */ + 1 /* label type/length byte for label */, label, ll); name.bytes[dname->label_count + 1] = ll; /* label type/length byte */ name.bytes[dname->label_count] = 0; /* first label follows last * label_offsets element */ for (i = 0; i < dname->label_count; i++) name.bytes[i] = ((uint8_t*)(void*)dname)[sizeof(dname_type)+i] + 1 /* label type/length byte for label */ + ll; name.dname.label_count = dname->label_count + 1 /* label_count incr. */; name.dname.name_size = dname->name_size + ll + 1 /* label length */; return &name.dname; } static void catalog_del_consumer_member_zone( struct xfrd_catalog_consumer_zone* consumer_zone, struct catalog_member_zone* consumer_member_zone) { const dname_type* dname = consumer_member_zone->options.node.key; /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(&consumer_member_zone->options)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); #ifdef MULTIPLE_CATALOG_CONSUMER_ZONES /* delete it in xfrd's catalog consumers list */ if(zone_is_catalog_consumer(&consumer_member_zone->options)) { xfrd_deinit_catalog_consumer_zone(xfrd, dname); } #endif if(consumer_member_zone->member_id) { rbtree_delete(&consumer_zone->member_ids,consumer_member_zone); consumer_member_zone->node = *RBTREE_NULL; region_recycle( xfrd->nsd->options->region, (void*)consumer_member_zone->member_id, dname_total_size(consumer_member_zone->member_id)); consumer_member_zone->member_id = NULL; } zone_options_delete(xfrd->nsd->options,&consumer_member_zone->options); } void xfrd_check_catalog_consumer_zonefiles(const dname_type* name) { struct xfrd_catalog_consumer_zone* consumer_zone; #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES consumer_zone = xfrd_one_catalog_consumer_zone(); if (!consumer_zone) return; if (name && dname_compare(name, consumer_zone->node.key) != 0) return; name = consumer_zone->node.key; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Mark %s " "for checking", consumer_zone->options->name)); make_catalog_consumer_valid(consumer_zone); namedb_read_zonefile(xfrd->nsd, namedb_find_or_create_zone( xfrd->nsd->db, name, consumer_zone->options), NULL, NULL); #else if (!name) { RBTREE_FOR(consumer_zone, struct xfrd_catalog_consumer_zone*, xfrd->catalog_consumer_zones) { make_catalog_consumer_valid(consumer_zone); namedb_read_zonefile(xfrd->nsd, namedb_find_or_create_zone(xfrd->nsd->db, consumer_zone->options->node.key, consumer_zone->options), NULL, NULL); } } else if ((consumer_zone = (struct xfrd_catalog_consumer_zone*) rbtree_search(xfrd->catalog_consumer_zones, name))) { make_catalog_consumer_valid(consumer_zone); namedb_read_zonefile(xfrd->nsd, namedb_find_or_create_zone( xfrd->nsd->db, name, consumer_zone->options), NULL, NULL); } #endif } const char *invalid_catalog_consumer_zone(struct zone_options* zone) { struct xfrd_catalog_consumer_zone* consumer_zone; const char *msg; if (!zone || !zone_is_catalog_consumer(zone)) msg = NULL; else if (!xfrd) msg = "asked for catalog information outside of xfrd process"; else if (!xfrd->catalog_consumer_zones) msg = "zone not found: " "xfrd's catalog consumer zones index is empty"; #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES else if (xfrd->catalog_consumer_zones->count > 1) return "not processing: more than one catalog consumer zone " "configured and only a single one allowed"; #endif else if (!(consumer_zone = (struct xfrd_catalog_consumer_zone*) rbtree_search(xfrd->catalog_consumer_zones, zone->node.key))) msg = "zone not found in xfrd's catalog consumer zones index"; else return consumer_zone->invalid; if (msg) log_msg(LOG_ERR, "catalog consumer zone '%s': %s", zone->name, msg); return msg; } void xfrd_process_catalog_consumer_zones() { struct xfrd_catalog_consumer_zone* consumer_zone; #ifndef MULTIPLE_CATALOG_CONSUMER_ZONES if((consumer_zone = xfrd_one_catalog_consumer_zone())) xfrd_process_catalog_consumer_zone(consumer_zone); #else RBTREE_FOR(consumer_zone, struct xfrd_catalog_consumer_zone*, xfrd->catalog_consumer_zones) { xfrd_process_catalog_consumer_zone(consumer_zone); } #endif } static inline struct catalog_member_zone* cursor_cmz(rbnode_type* node) { return node != RBTREE_NULL ? (struct catalog_member_zone*)node->key : NULL; } static inline const dname_type* cursor_member_id(rbnode_type* node) { return cursor_cmz(node) ? cursor_cmz(node)->member_id : NULL; } #if !defined(NDEBUG) && 1 /* Only disable for seriously slow debugging */ static void debug_log_consumer_members( struct xfrd_catalog_consumer_zone* consumer_zone) { rbnode_type* cursor; size_t i; for ( cursor = rbtree_first(&consumer_zone->member_ids), i = 0 ; cursor != RBTREE_NULL; i++, cursor = rbtree_next(cursor)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Catalog member %.2zu: %s = %s", i, dname_to_string(cursor_member_id(cursor), NULL), cursor_cmz(cursor)->options.name)); } } #else # define debug_log_consumer_members(x) /* nothing */ #endif static void xfrd_process_catalog_consumer_zone( struct xfrd_catalog_consumer_zone* consumer_zone) { zone_type* zone; const dname_type* dname; domain_type *match, *closest_encloser, *member_id, *group; rrset_type *rrset; size_t i; uint8_t version_2_found; /* Currect catalog member zone */ rbnode_type* cursor; struct pattern_options *default_pattern = NULL; /* A transfer of a catalog zone can contain deletion and adding of * the same member zone. In such cases it can occur that the member * is tried to be added before it is deleted. For these exceptional * cases, we will rewalk the zone after the first pass, to retry * adding those zones. * * Initial pass is mode "try_to_add". * If a zone cannot be added, mode is set to "retry_to_add" * If after the first pass the mode is "retry_to_add", * mode will be set to "just_add", and a second pass is done. */ enum { try_to_add, retry_to_add, just_add } mode; assert(consumer_zone); if (!xfrd->nsd->db) { xfrd->nsd->db = namedb_open(xfrd->nsd->options); } dname = (const dname_type*)consumer_zone->node.key; if (dname->name_size > 247) { make_catalog_consumer_invalid(consumer_zone, "name too long"); return; } if (dname->label_count > 126) { make_catalog_consumer_invalid(consumer_zone,"too many labels"); return; } zone = namedb_find_zone(xfrd->nsd->db, dname); if (!zone) { zone = namedb_zone_create(xfrd->nsd->db, dname, consumer_zone->options); namedb_read_zonefile(xfrd->nsd, zone, NULL, NULL); } if (timespec_compare(&consumer_zone->mtime, &zone->mtime) == 0) { /* Not processing unchanged catalog consumer zone */ return; } consumer_zone->mtime = zone->mtime; /* start processing */ /* Lookup version. TXT and check that it is version 2 */ if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("version", dname), &match, &closest_encloser) || !(rrset = domain_find_rrset(match, zone, TYPE_TXT))) { make_catalog_consumer_invalid(consumer_zone, "'version.%s TXT RRset not found", consumer_zone->options->name); return; } version_2_found = 0; for (i = 0; i < rrset->rr_count; i++) { if (rrset->rrs[i].rdata_count != 1) continue; if (rrset->rrs[i].rdatas[0].data[0] == 2 && ((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[0] == 1 && ((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[1] == '2') { version_2_found = 1; break; } } if (!version_2_found) { make_catalog_consumer_invalid(consumer_zone, "'version.%s' TXT RR with value \"2\" not found", consumer_zone->options->name); return; } /* Walk over all names under zones. */ if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("zones", dname), &match, &closest_encloser)) { /* zones. does not exist, so the catalog has no * members. This is just fine. But there may be members that need * to be deleted. */ cursor = rbtree_first(&consumer_zone->member_ids); mode = just_add; goto delete_members; } mode = consumer_zone->member_ids.count ? try_to_add : just_add; retry_adding: cursor = rbtree_first(&consumer_zone->member_ids); for ( member_id = domain_next(match) ; member_id && domain_is_subdomain(member_id, match) ; member_id = domain_next(member_id)) { domain_type *member_domain; char member_domain_str[5 * MAXDOMAINLEN]; struct zone_options* zopt; int valid_group_values; struct pattern_options *pattern = NULL; struct catalog_member_zone* to_add; if (domain_dname(member_id)->label_count > dname->label_count+2 || !(rrset = domain_find_rrset(member_id, zone, TYPE_PTR))) continue; /* RFC9432 Section 4.1. Member Zones: * * `` This PTR record MUST be the only record in the PTR RRset * with the same name. The presence of more than one record * in the RRset indicates a broken catalog zone that MUST * NOT be processed (see Section 5.1). */ if (rrset->rr_count != 1) { make_catalog_consumer_invalid(consumer_zone, "only a single PTR RR expected on '%s'", domain_to_string(member_id)); return; } /* A PTR rr always has 1 rdata element which is a dname */ if (rrset->rrs[0].rdata_count != 1) continue; member_domain = rrset->rrs[0].rdatas[0].domain; domain_to_string_buf(member_domain, member_domain_str); /* remove trailing dot */ member_domain_str[strlen(member_domain_str) - 1] = 0; valid_group_values = 0; /* Lookup group. TXT for matching patterns */ if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("group", domain_dname(member_id)), &group, &closest_encloser) || !(rrset = domain_find_rrset(group, zone, TYPE_TXT))) { ; /* pass */ } else for (i = 0; i < rrset->rr_count; i++) { /* Max single TXT rdata field length + '\x00' == 256 */ char group_value[256]; /* Looking for a single TXT rdata field */ if (rrset->rrs[i].rdata_count != 1 /* rdata field should be at least 1 char */ || rrset->rrs[i].rdatas[0].data[0] < 2 /* single rdata atom with single TXT rdata field */ || (uint16_t)(((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[0]) != (uint16_t) (rrset->rrs[i].rdatas[0].data[0]-1)) continue; memcpy( group_value , (uint8_t*)(rrset->rrs[i].rdatas[0].data+1) + 1 ,((uint8_t*)(rrset->rrs[i].rdatas[0].data+1))[0] ); group_value[ ((uint8_t*)(rrset->rrs[i].rdatas[0].data+1))[0] ] = 0; if ((pattern = pattern_options_find( xfrd->nsd->options, group_value))) valid_group_values += 1; } if (valid_group_values > 1) { log_msg(LOG_ERR, "member zone '%s': only a single " "group property that matches a pattern is " "allowed." "The pattern from \"catalog-member-pattern\" " "will be used instead.", domain_to_string(member_id)); valid_group_values = 0; } else if (valid_group_values == 1 && pattern && pattern->catalog_producer_zone) { log_msg(LOG_ERR, "member zone '%s': group property " "'%s' matches a catalog producer member zone " "pattern. In NSD, catalog member zones can be " "either a member of a catalog consumer zone or" " a catalog producer zone, but not both.", domain_to_string(member_id), pattern->pname); valid_group_values = 0; } if (valid_group_values == 1) { /* pass: pattern is already set */ assert(pattern); } else if (default_pattern) pattern = default_pattern; /* pass */ else if (!(pattern = default_pattern = catalog_member_pattern(consumer_zone))) { make_catalog_consumer_invalid(consumer_zone, "missing 'group.%s' TXT RR and no default " "pattern from \"catalog-member-pattern\"", domain_to_string(member_id)); return; } if (cursor == RBTREE_NULL) ; /* End of the current member zones list. * From here onwards, zones will only be added. */ else { int cmp = 0; #ifndef NDEBUG char member_id_str[5 * MAXDOMAINLEN]; domain_to_string_buf(member_id, member_id_str); #endif DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Comparing %s with %s", member_id_str, dname_to_string(cursor_member_id(cursor), NULL))); while (cursor != RBTREE_NULL && (cmp = dname_compare( domain_dname(member_id), cursor_member_id(cursor))) > 0) { /* member_id is ahead of the current catalog * member zone pointed to by cursor. * The member zone must be deleted. */ struct catalog_member_zone* to_delete = cursor_cmz(cursor); #ifndef NDEBUG const char *member_id_to_delete_str = dname_to_string(to_delete->member_id, NULL); #endif cursor = rbtree_next(cursor); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s > %s: delete %s", member_id_str, member_id_to_delete_str, member_id_to_delete_str)); catalog_del_consumer_member_zone( consumer_zone, to_delete); if(cursor != RBTREE_NULL) DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Comparing %s with %s", member_id_str, dname_to_string( cursor_member_id(cursor), NULL))); } if (cursor != RBTREE_NULL && cmp == 0) { /* member_id is also in an current catalog * member zone, and cursor is pointing * to it. So, move along ... */ /* ... but first check if the pattern needs * a change */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s == %s: " "Compare pattern %s with %s", member_id_str, member_id_str, cursor_cmz(cursor)->options.pattern->pname, pattern->pname)); if (cursor_cmz(cursor)->options.pattern == pattern) ; /* pass: Pattern remains the same */ else { /* Changing patterns is basically * deleting and adding the zone again */ zopt = &cursor_cmz(cursor)->options; dname = (dname_type *)zopt->node.key; task_new_del_zone( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); if(zone_is_slave(zopt)) { xfrd_del_slave_zone( xfrd , dname); } xfrd_del_notify(xfrd, dname); #ifdef MULTIPLE_CATALOG_CONSUMER_ZONES if(zone_is_catalog_consumer(zopt)) { xfrd_deinit_catalog_consumer_zone( xfrd, dname); } #endif /* It is a catalog consumer member, * so no need to check if it was a * catalog producer member zone to * delete and add */ zopt->pattern = pattern; task_new_add_zone( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zopt->name, pattern->pname, getzonestatid( xfrd->nsd->options , zopt)); zonestat_inc_ifneeded(); xfrd_set_reload_now(xfrd); #ifdef MULTIPLE_CATALOG_CONSUMER_ZONES if(zone_is_catalog_consumer(zopt)) { xfrd_init_catalog_consumer_zone( xfrd, zopt); } #endif init_notify_send(xfrd->notify_zones, xfrd->region, zopt); if(zone_is_slave(zopt)) { xfrd_init_slave_zone( xfrd, zopt); } } cursor = rbtree_next(cursor); continue; } /* member_id is not in the current catalog member zone * list, so it must be added */ assert(cursor == RBTREE_NULL || cmp < 0); } /* See if the zone already exists */ zopt = zone_options_find(xfrd->nsd->options, domain_dname(member_domain)); if (zopt) { /* Produce warning if zopt is from other catalog. * Give debug message if zopt is not from this catalog. */ switch(mode) { case try_to_add: mode = retry_to_add; break; case just_add: DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Cannot add " "catalog member zone %s (from %s): " "zone already exists", member_domain_str, domain_to_string(member_id))); break; default: break; } continue; } /* Add member zone if not already there */ log_msg(LOG_INFO, "Adding '%s' PTR '%s'", domain_to_string(member_id), member_domain_str); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Adding %s PTR %s", domain_to_string(member_id), member_domain_str)); to_add= catalog_member_zone_create(xfrd->nsd->options->region); to_add->options.name = region_strdup( xfrd->nsd->options->region, member_domain_str); to_add->options.pattern = pattern; if (!nsd_options_insert_zone(xfrd->nsd->options, &to_add->options)) { log_msg(LOG_ERR, "bad domain name '%s' pattern %s", member_domain_str, ( pattern->pname ? pattern->pname: "")); zone_options_delete(xfrd->nsd->options, &to_add->options); continue; } to_add->member_id = dname_copy( xfrd->nsd->options->region , domain_dname(member_id)); /* Insert into the members_id list */ to_add->node.key = to_add; if(!rbtree_insert( &consumer_zone->member_ids, &to_add->node)){ log_msg(LOG_ERR, "Error adding '%s' PTR '%s' to " "consumer_zone->member_ids", domain_to_string(member_id), member_domain_str); break; } else cursor = rbtree_next(&to_add->node); /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, member_domain_str, pattern->pname, getzonestatid(xfrd->nsd->options, &to_add->options)); zonestat_inc_ifneeded(); xfrd_set_reload_now(xfrd); #ifdef MULTIPLE_CATALOG_CONSUMER_ZONES /* add to xfrd - catalog consumer zones */ if(zone_is_catalog_consumer(&to_add->options)) { xfrd_init_catalog_consumer_zone(xfrd,&to_add->options); } #endif /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, &to_add->options); /* add to xfrd - slave */ if(zone_is_slave(&to_add->options)) { xfrd_init_slave_zone(xfrd, &to_add->options); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Added catalog " "member zone %s (from %s)", member_domain_str, domain_to_string(member_id))); } delete_members: while (cursor != RBTREE_NULL) { /* Any current catalog member zones remaining, don't have an * member_id in the catalog anymore, so should be deleted too. */ struct catalog_member_zone* to_delete = cursor_cmz(cursor); cursor = rbtree_next(cursor); catalog_del_consumer_member_zone(consumer_zone, to_delete); } if(mode == retry_to_add) { mode = just_add; goto retry_adding; } debug_log_consumer_members(consumer_zone); make_catalog_consumer_valid(consumer_zone); } /****************** ****************** ****************** catalog producer zone processing ****************** ****************** ******************/ static int member_id_compare(const void *left, const void *right) { return dname_compare( ((struct catalog_member_zone*)left )->member_id , ((struct catalog_member_zone*)right)->member_id); } static struct xfrd_catalog_producer_zone* xfrd_get_catalog_producer_zone(struct catalog_member_zone* cmz) { struct zone_options *producer_zopt; struct xfrd_catalog_producer_zone* producer_zone; const dname_type* producer_name; const char* producer_name_str; assert(xfrd); if(!cmz || !cmz->options.pattern->catalog_producer_zone) return NULL; /* TODO: Store as dname in pattern->catalog_producer_zone */ producer_name = dname_parse(xfrd->nsd->options->region, cmz->options.pattern->catalog_producer_zone); producer_zopt = zone_options_find(xfrd->nsd->options, producer_name); producer_name_str = dname_to_string(producer_name, NULL); region_recycle( xfrd->nsd->options->region, (void *)producer_name , dname_total_size(producer_name)); if(!producer_zopt) { log_msg(LOG_ERR, "catalog producer zone '%s' not found for " "zone '%s'", producer_name_str, cmz->options.name); return NULL; } if(!zone_is_catalog_producer(producer_zopt)) { log_msg(LOG_ERR, "cannot add catalog producer member " "zone '%s' to non producer zone '%s'", cmz->options.name, producer_zopt->name); return NULL; } producer_name = (dname_type*)producer_zopt->node.key; producer_zone = (struct xfrd_catalog_producer_zone*) rbtree_search(xfrd->catalog_producer_zones, producer_name); if (!producer_zone) { /* Create a new one */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO,"creating catalog producer zone" " '%s'", producer_zopt->name)); producer_zone = (struct xfrd_catalog_producer_zone*) region_alloc(xfrd->region, sizeof(*producer_zone)); memset(producer_zone , 0, sizeof(*producer_zone)); producer_zone->node.key = producer_zopt->node.key; producer_zone->options = producer_zopt; producer_zone->member_ids.region = xfrd->region; producer_zone->member_ids.root = RBTREE_NULL; producer_zone->member_ids.count = 0; producer_zone->member_ids.cmp = member_id_compare; producer_zone->serial = 0; producer_zone->to_delete = NULL; producer_zone->to_add = NULL; producer_zone->latest_pxfr = NULL; producer_zone->axfr = 1; rbtree_insert(xfrd->catalog_producer_zones, (rbnode_type*)producer_zone); } return producer_zone; } void xfrd_add_catalog_producer_member(struct catalog_member_zone* cmz) { struct xfrd_catalog_producer_zone* producer_zone; const dname_type* producer_name; struct xfrd_producer_member* to_add; assert(xfrd); if (!(producer_zone = xfrd_get_catalog_producer_zone(cmz))) { return; } producer_name = producer_zone->node.key; while(!cmz->member_id) { /* Make new member_id with this catalog producer */ char id_label[sizeof(uint32_t)*2+1]; uint32_t new_id = (uint32_t)random_generate(0x7fffffff); hex_ntop((void*)&new_id, sizeof(uint32_t), id_label, sizeof(id_label)); id_label[sizeof(uint32_t)*2] = 0; cmz->member_id = label_plus_dname(id_label, label_plus_dname("zones", producer_name)); DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "does member_id %s exist?", dname_to_string(cmz->member_id, NULL))); if (!rbtree_search(&producer_zone->member_ids, cmz)) { cmz->member_id = dname_copy(xfrd->nsd->options->region, cmz->member_id); break; } cmz->member_id = NULL; } cmz->node.key = cmz; rbtree_insert(&producer_zone->member_ids, &cmz->node); /* Put data to be added to the producer zone to the to_add stack */ to_add = (struct xfrd_producer_member*)region_alloc(xfrd->region, sizeof(struct xfrd_producer_member)); to_add->member_id = cmz->member_id; to_add->member_zone_name = (dname_type*)cmz->options.node.key; to_add->group_name = cmz->options.pattern->pname; to_add->next = producer_zone->to_add; producer_zone->to_add = to_add; } int xfrd_del_catalog_producer_member(struct xfrd_state* xfrd, const dname_type* member_zone_name) { struct xfrd_producer_member* to_delete; struct catalog_member_zone* cmz; struct xfrd_catalog_producer_zone* producer_zone; if(!(cmz = as_catalog_member_zone(zone_options_find(xfrd->nsd->options, member_zone_name))) || !(producer_zone = xfrd_get_catalog_producer_zone(cmz)) || !rbtree_delete(&producer_zone->member_ids, cmz)) return 0; to_delete = (struct xfrd_producer_member*)region_alloc(xfrd->region, sizeof(struct xfrd_producer_member)); to_delete->member_id = cmz->member_id; cmz->member_id = NULL; cmz->node = *RBTREE_NULL; to_delete->member_zone_name = member_zone_name; to_delete->group_name = cmz->options.pattern->pname; to_delete->next = producer_zone->to_delete; producer_zone->to_delete = to_delete; return 1; } static int try_buffer_write_SOA(buffer_type* packet, const dname_type* owner, uint32_t serial) { size_t mark = buffer_position(packet); if(try_buffer_write(packet, dname_name(owner), owner->name_size) && try_buffer_write_u16(packet, TYPE_SOA) && try_buffer_write_u16(packet, CLASS_IN) && try_buffer_write_u32(packet, 0) /* TTL*/ && try_buffer_write_u16(packet, 9 + 9 + 5 * sizeof(uint32_t)) && try_buffer_write(packet, "\007invalid\000", 9) /* primary */ && try_buffer_write(packet, "\007invalid\000", 9) /* mailbox */ && try_buffer_write_u32(packet, serial) /* serial */ && try_buffer_write_u32(packet, 3600) /* refresh*/ && try_buffer_write_u32(packet, 600) /* retry */ && try_buffer_write_u32(packet, 2147483646) /* expire */ && try_buffer_write_u32(packet, 0) /* minimum */) { ANCOUNT_SET(packet, ANCOUNT(packet) + 1); return 1; } buffer_set_position(packet, mark); return 0; } static int try_buffer_write_RR(buffer_type* packet, const dname_type* owner, uint16_t rr_type, uint16_t rdata_len, const void* rdata) { size_t mark = buffer_position(packet); if(try_buffer_write(packet, dname_name(owner), owner->name_size) && try_buffer_write_u16(packet, rr_type) && try_buffer_write_u16(packet, CLASS_IN) && try_buffer_write_u32(packet, 0) /* TTL*/ && try_buffer_write_u16(packet, rdata_len) && try_buffer_write(packet, rdata, rdata_len)) { ANCOUNT_SET(packet, ANCOUNT(packet) + 1); return 1; } buffer_set_position(packet, mark); return 0; } static inline int try_buffer_write_PTR(buffer_type* packet, const dname_type* owner, const dname_type* name) { return try_buffer_write_RR(packet, owner, TYPE_PTR, name->name_size, dname_name(name)); } static int try_buffer_write_TXT(buffer_type* packet, const dname_type* name, const char *txt) { size_t mark = buffer_position(packet); size_t len = strlen(txt); if(len > 255) { log_msg(LOG_ERR, "cannot make '%s 0 IN TXT \"%s\"': rdata " "field too long", dname_to_string(name, NULL), txt); return 1; } if(try_buffer_write(packet, dname_name(name), name->name_size) && try_buffer_write_u16(packet, TYPE_TXT) && try_buffer_write_u16(packet, CLASS_IN) && try_buffer_write_u32(packet, 0) /* TTL*/ && try_buffer_write_u16(packet, len + 1) && try_buffer_write_u8(packet, len) && try_buffer_write_string(packet, txt)) { ANCOUNT_SET(packet, ANCOUNT(packet) + 1); return 1; } buffer_set_position(packet, mark); return 0; } static void xfr_writer_init(struct xfrd_xfr_writer* xw, struct xfrd_catalog_producer_zone* producer_zone) { xw->producer_zone = producer_zone; memset(&xw->packet, 0, sizeof(xw->packet)); buffer_create_from(&xw->packet, xw->packet_space, sizeof(xw->packet_space)); buffer_write(&xw->packet, "\000\000\000\000\000\000" "\000\000\000\000\000\000", 12); /* header */ xw->seq_nr = 0; xw->old_serial = xw->producer_zone->serial; xw->new_serial = (uint32_t)xfrd_time(); if(xw->new_serial <= xw->old_serial) xw->new_serial = xw->old_serial + 1; if(producer_zone->axfr) { xw->old_serial = 0; producer_zone->axfr = 0; } xw->xfrfilenumber = xfrd->xfrfilenumber++; } static void xfr_writer_write_packet(struct xfrd_xfr_writer* xw) { const dname_type* producer_name = (const dname_type*)xw->producer_zone->options->node.key; /* We want some content at least, so not just a header * This can occur when final SOA was already written. */ if(buffer_position(&xw->packet) == 12) return; buffer_flip(&xw->packet); diff_write_packet( dname_to_string(producer_name, NULL) , xw->producer_zone->options->pattern->pname , xw->old_serial, xw->new_serial, xw->seq_nr , buffer_begin(&xw->packet), buffer_limit(&xw->packet) , xfrd->nsd, xw->xfrfilenumber); xw->seq_nr += 1; buffer_clear(&xw->packet); buffer_write(&xw->packet, "\000\000\000\000\000\000" "\000\000\000\000\000\000", 12); /* header */ } static void xfr_writer_commit(struct xfrd_xfr_writer* xw, const char *fmt, ...) { va_list args; char msg[1024]; const dname_type* producer_name = (const dname_type*)xw->producer_zone->options->node.key; va_start(args, fmt); if (vsnprintf(msg, sizeof(msg), fmt, args) >= (int)sizeof(msg)) { log_msg(LOG_WARNING, "truncated diff commit message: '%s'", msg); } xfr_writer_write_packet(xw); /* Write remaining data */ diff_write_commit( dname_to_string(producer_name, NULL) , xw->old_serial, xw->new_serial , xw->seq_nr /* Number of packets */ , 1, msg, xfrd->nsd, xw->xfrfilenumber); task_new_apply_xfr( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task , producer_name , xw->old_serial, xw->new_serial, xw->xfrfilenumber); xfrd_set_reload_now(xfrd); } static void xfrd_process_catalog_producer_zone( struct xfrd_catalog_producer_zone* producer_zone) { struct xfrd_xfr_writer xw; dname_type* producer_name; struct xfrd_producer_xfr* pxfr; if(!producer_zone->to_add && !producer_zone->to_delete) return; /* No changes */ producer_name = (dname_type*)producer_zone->node.key; xfr_writer_init(&xw, producer_zone); xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); if(xw.old_serial == 0) { /* initial deployment */ assert(producer_zone->to_add && !producer_zone->to_delete); xfr_writer_add_RR (&xw, producer_name , TYPE_NS, 9, "\007invalid\000"); xfr_writer_add_TXT(&xw, label_plus_dname("version" , producer_name), "2"); goto add_member_zones; } /* IXFR */ xfr_writer_add_SOA(&xw, producer_name, xw.old_serial); while(producer_zone->to_delete) { struct xfrd_producer_member* to_delete = producer_zone->to_delete; /* Pop to_delete from stack */ producer_zone->to_delete = to_delete->next; to_delete->next = NULL; /* Write PTR */ xfr_writer_add_PTR(&xw, to_delete->member_id , to_delete->member_zone_name); /* Write group. TXT */ xfr_writer_add_TXT( &xw , label_plus_dname("group" , to_delete->member_id) , to_delete->group_name); region_recycle( xfrd->nsd->options->region , (void *)to_delete->member_id , dname_total_size(to_delete->member_id)); region_recycle( xfrd->region /* allocated in perform_delzone */ , (void *)to_delete->member_zone_name , dname_total_size(to_delete->member_zone_name)); /* Don't recycle to_delete->group_name it's pattern->pname */ region_recycle( xfrd->region, to_delete, sizeof(*to_delete)); } xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); add_member_zones: while(producer_zone->to_add) { struct xfrd_producer_member* to_add = producer_zone->to_add; /* Pop to_add from stack */ producer_zone->to_add = to_add->next; to_add->next = NULL; /* Write PTR */ xfr_writer_add_PTR(&xw, to_add->member_id, to_add->member_zone_name); /* Write group. TXT */ xfr_writer_add_TXT( &xw , label_plus_dname("group" , to_add->member_id) , to_add->group_name); /* Don't recycle any of the struct attributes as they come * from zone_option's that are in use */ region_recycle(xfrd->region, to_add, sizeof(*to_add)); } xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); xfr_writer_commit(&xw, "xfr for catalog producer zone " "'%s' with %d members from %u to %u", dname_to_string(producer_name, NULL), producer_zone->member_ids.count, xw.old_serial, xw.new_serial); producer_zone->serial = xw.new_serial; /* Hook up an xfrd_producer_xfr, to delete the xfr file when applied */ pxfr = (struct xfrd_producer_xfr*)region_alloc(xfrd->region, sizeof(struct xfrd_producer_xfr)); pxfr->serial = xw.new_serial; pxfr->xfrfilenumber = xw.xfrfilenumber; if((pxfr->next = producer_zone->latest_pxfr)) pxfr->next->prev_next_ptr = &pxfr->next; pxfr->prev_next_ptr = &producer_zone->latest_pxfr; producer_zone->latest_pxfr = pxfr; } void xfrd_process_catalog_producer_zones() { struct xfrd_catalog_producer_zone* producer_zone; RBTREE_FOR(producer_zone, struct xfrd_catalog_producer_zone*, xfrd->catalog_producer_zones) { xfrd_process_catalog_producer_zone(producer_zone); } } nsd-4.12.0/xfr-inspect.c0000644000175000017500000002763615002373054014421 0ustar mozziemozzie/* xfr-inspect - list the contents and inspect an zone transfer XFR file * By W.C.A. Wijngaards * Copyright 2017, NLnet Labs. * BSD, see LICENSE. */ #include "config.h" #include "util.h" #include "buffer.h" #include "packet.h" #include "rdata.h" #include "namedb.h" #include "difffile.h" #include #include #include #include #include #include /** verbosity for inspect */ static int v = 0; /** shorthand for ease */ #ifdef ULL #undef ULL #endif #define ULL (unsigned long long) /** print usage text */ static void usage(void) { printf("usage: xfr-inspect [options] file\n"); printf(" -h this help\n"); printf(" -v increase verbosity: " "with -v(list chunks), -vv(inside chunks)\n"); printf(" -l list contents of transfer\n"); } static int xi_diff_read_64(FILE *in, uint64_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } static int xi_diff_read_32(FILE *in, uint32_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { *result = ntohl(*result); return 1; } else { return 0; } } static int xi_diff_read_8(FILE *in, uint8_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } static int xi_diff_read_str(FILE* in, char* buf, size_t len) { uint32_t disklen; if(!xi_diff_read_32(in, &disklen)) return 0; if(disklen >= len) return 0; if(fread(buf, disklen, 1, in) != 1) return 0; buf[disklen] = 0; return 1; } /** inspect header of xfr file, return num_parts */ static int inspect_header(FILE* in) { char zone_buf[3072]; char patname_buf[2048]; uint32_t old_serial, new_serial, num_parts, type; uint64_t time_end_0, time_start_0; uint32_t time_end_1, time_start_1; uint8_t committed; time_t time_end, time_start; if(!xi_diff_read_32(in, &type)) { printf("could not read type, file short\n"); fclose(in); exit(1); } if(type != DIFF_PART_XFRF) { printf("type: %x (BAD FILE TYPE)\n", type); fclose(in); exit(1); } if(!xi_diff_read_8(in, &committed) || !xi_diff_read_32(in, &num_parts) || !xi_diff_read_64(in, &time_end_0) || !xi_diff_read_32(in, &time_end_1) || !xi_diff_read_32(in, &old_serial) || !xi_diff_read_32(in, &new_serial) || !xi_diff_read_64(in, &time_start_0) || !xi_diff_read_32(in, &time_start_1) || !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) || !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) { printf("diff file bad commit part, file too short"); fclose(in); exit(1); } time_end = (time_t)time_end_0; time_start = (time_t)time_start_0; /* printf("type: %x\n", (int)type); */ printf("committed: %d (%s)\n", (int)committed, committed?"yes":"no"); printf("num_parts: %d\n", (int)num_parts); printf("time_end: %d.%6.6d %s", (int)time_end_0, (int)time_end_1, ctime(&time_end)); printf("old_serial: %u\n", (unsigned)old_serial); printf("new_serial: %u\n", (unsigned)new_serial); printf("time_start: %d.%6.6d %s", (int)time_start_0, (int)time_start_1, ctime(&time_start)); printf("zone: %s\n", zone_buf); printf("patname: %s\n", patname_buf); return num_parts; } /** print records in packet */ static void print_records(region_type* region, buffer_type* pkt, int num, int qsection) { domain_table_type* table; int i; rr_type* rr; region_type* tmpregion = region_create(xalloc, free); buffer_type* tmpbuf; if(!tmpregion) { printf("out of memory\n"); return; } tmpbuf = buffer_create(region, QIOBUFSZ); if(!tmpbuf) { printf("out of memory\n"); return; } table = domain_table_create(tmpregion); if(!table) { printf("out of memory\n"); return; } for(i=0; iowner), NULL)); printf("\t%s", rrclass_to_string(rr->klass)); if(rr->type == TYPE_IXFR) printf("\tIXFR\n"); else if(rr->type == TYPE_AXFR) printf("\tAXFR\n"); else printf("\t%s\n", rrtype_to_string(rr->type)); } else { if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) { printf("; cannot print rr %d\n", i); } } } region_destroy(tmpregion); } /** inspect packet (IXFR or AXFR) */ static void inspect_packet(region_type* region, buffer_type* pkt) { printf("\n"); if(buffer_limit(pkt) < QHEADERSZ) { printf("packet too short\n"); return; } printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n", ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"", RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"", AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)), OPCODE(pkt)); printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n", QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt)); buffer_skip(pkt, QHEADERSZ); if(QDCOUNT(pkt) != 0) { printf("; QUESTION SECTION\n"); print_records(region, pkt, QDCOUNT(pkt), 1); } if(ANCOUNT(pkt) != 0) { printf("; ANSWER SECTION\n"); print_records(region, pkt, ANCOUNT(pkt), 0); } if(NSCOUNT(pkt) != 0) { printf("; AUTHORITY SECTION\n"); print_records(region, pkt, NSCOUNT(pkt), 0); } if(ARCOUNT(pkt) != 0) { printf("; ADDITIONAL SECTION\n"); print_records(region, pkt, ARCOUNT(pkt), 0); } } /** inspect part of xfr file */ static void inspect_part(FILE* in, int partnum) { uint32_t pkttype, msglen, msglen2; region_type* region; buffer_type* packet; region = region_create(xalloc, free); if(!region) { printf("out of memory\n"); fclose(in); exit(1); } packet = buffer_create(region, QIOBUFSZ); if(!xi_diff_read_32(in, &pkttype)) { printf("cannot read part %d\n", partnum); fclose(in); exit(1); } if(pkttype != DIFF_PART_XXFR) { printf("bad part %d: not type XXFR\n", partnum); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen)) { printf("bad part %d: not msglen, file too short\n", partnum); fclose(in); exit(1); } if(msglen < QHEADERSZ || msglen > QIOBUFSZ) { printf("bad part %d: msglen %u (too short or too long)\n", partnum, (unsigned)msglen); fclose(in); exit(1); } if(fread(buffer_begin(packet), msglen, 1, in) != 1) { printf("bad part %d: short packet, file too short, %s\n", partnum, strerror(errno)); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen2)) { printf("bad part %d: cannot read msglen2, file too short\n", partnum); fclose(in); exit(1); } if(v==0) { region_destroy(region); return; } printf("\n"); /* printf("type : %x\n", pkttype); */ printf("part : %d\n", partnum); printf("msglen : %u\n", (unsigned)msglen); printf("msglen2 : %u (%s)\n", (unsigned)msglen2, (msglen==msglen2)?"ok":"wrong"); if(v>=2) { buffer_set_limit(packet, msglen); inspect_packet(region, packet); } region_destroy(region); } /** inspect parts of xfr file */ static void inspect_parts(FILE* in, int num) { int i; for(i=0; i QIOBUFSZ) { printf("bad part %d: msglen %u (too short or too long)\n", partnum, (unsigned)msglen); fclose(in); exit(1); } if(fread(buffer_begin(packet), msglen, 1, in) != 1) { printf("bad part %d: short packet, file too short, %s\n", partnum, strerror(errno)); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen2)) { printf("bad part %d: cannot read msglen2, file too short\n", partnum); fclose(in); exit(1); } buffer_set_limit(packet, msglen); list_packet(region, packet, partnum); region_destroy(region); } /** list parts of xfr file */ static void list_parts(FILE* in, int num) { int i; for(i=0; i # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif /* * Track position in zone to feed verifier more data as the input descriptor * becomes available. */ struct verifier_zone_feed { FILE *fh; struct event event; zone_rr_iter_type rriter; struct state_pretty_rr *rrprinter; struct region *region; struct buffer *buffer; }; /* 40 is (estimated) space already used on each logline. * (time, pid, priority, etc) */ #define LOGLINELEN (MAXSYSLOGMSGLEN-40) #define LOGBUFSIZE (LOGLINELEN * 2) /* * STDOUT and STDERR are logged per line. Lines that exceed LOGLINELEN, are * split over multiple entries. Line breaks are indicated with "..." in the log * before and after the break. */ struct verifier_stream { int fd; struct event event; int priority; int cut; char buf[LOGBUFSIZE+1]; size_t cnt; size_t off; }; struct verifier { struct nsd *nsd; struct zone *zone; pid_t pid; int was_ok; struct timeval timeout; struct event timeout_event; struct verifier_zone_feed zone_feed; struct verifier_stream output_stream; struct verifier_stream error_stream; }; struct zone *verify_next_zone(struct nsd *nsd, struct zone *zone); void verify_zone(struct nsd *nsd, struct zone *zone); void verify_handle_signal(int sig, short event, void *arg); void verify_handle_exit(int fd, short event, void *arg); void verify_handle_command(int fd, short event, void *arg); #endif /* VERIFY_H */ nsd-4.12.0/verify.c0000644000175000017500000003743615002373054013462 0ustar mozziemozzie/* * verify.c -- running verifiers and serving the zone to be verified. * * Copyright (c) 2012-2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG_H #include #endif /* HAVE_SYSLOG_H */ #include #include #include #include "region-allocator.h" #include "namedb.h" #include "nsd.h" #include "options.h" #include "difffile.h" #include "verify.h" #include "popen3.h" struct zone *verify_next_zone(struct nsd *nsd, struct zone *zone) { int verify; struct radnode *node; if(zone != NULL) { node = radix_next(zone->node); } else { node = radix_first(nsd->db->zonetree); } while(node != NULL) { zone = (struct zone *)node->elem; verify = zone->opts->pattern->verify_zone; if(verify == VERIFY_ZONE_INHERIT) { verify = nsd->options->verify_zones; } if(verify && zone->is_updated && !zone->is_checked) { return zone; } node = radix_next(node); } return NULL; } static inline ssize_t fill_buffer(struct verifier_stream *stream) { ssize_t cnt = 0; assert(stream); assert(stream->fd != -1); assert(stream->cnt <= LOGBUFSIZE); assert(stream->off <= stream->cnt); // move data to start of buffer assuming all complete lines are printed if (stream->off) { size_t len = stream->cnt - stream->off; memmove(stream->buf, stream->buf + stream->off, len); stream->off = 0; stream->cnt = len; stream->buf[stream->cnt] = '\0'; // always null-terminate } // read data if space is available cnt = read(stream->fd, stream->buf + stream->cnt, LOGBUFSIZE - stream->cnt); if (cnt > 0) stream->cnt += (size_t)cnt; assert(stream->cnt <= LOGBUFSIZE); assert(stream->off <= stream->cnt); stream->buf[stream->cnt] = '\0'; // always null-terminate return cnt; } static inline size_t print_line(struct verifier_stream *stream, int eof) { char *eol = NULL; size_t len; const char *fmt; if (stream->cnt == 0) return 0; assert(stream->off <= stream->cnt); if (stream->off == stream->cnt) return 0; // try to locate natural line break assert(stream->buf[stream->cnt] == '\0'); if ((eol = strchr(stream->buf + stream->off, '\n'))) { len = eol - (stream->buf + stream->off); } else { len = stream->cnt - stream->off; } assert(len <= (stream->cnt - stream->off)); // wait for buffer to contain a full line except on eof if (len < LOGLINELEN && !eol && !eof) return 0; if (len > LOGLINELEN) { fmt = stream->cut ? "verifier: .. %.*s .." : "verifier: %.*s .."; len = LOGLINELEN; // remainder printed next iteration stream->cut = 1; } else { fmt = stream->cut ? "verifier: .. %.*s" : "verifier: %.*s"; stream->cut = 0; } log_msg(stream->priority, fmt, len, stream->buf + stream->off); stream->off += len + (eol != NULL); assert(stream->off <= stream->cnt); return len; } /* * Log verifier output on STDOUT and STDERR. Lines longer than LOGLINELEN are * split over multiple lines. Line-breaks are indicated in the log with "...". */ static void verify_handle_stream(int fd, short event, void *arg) { int eof = 0; ssize_t cnt; struct verifier *verifier; struct verifier_stream *stream; assert(event & EV_READ); assert(arg != NULL); verifier = (struct verifier *)arg; if (fd == verifier->output_stream.fd) { stream = &verifier->output_stream; } else { assert(fd == verifier->error_stream.fd); stream = &verifier->error_stream; } assert(stream); assert(stream->fd != -1); do { cnt = fill_buffer(stream); eof = !cnt || (cnt < 0 && errno != EAGAIN && errno != EINTR); while (print_line(stream, eof)) ; } while (cnt > 0); if(eof) { event_del(&stream->event); close(stream->fd); stream->fd = -1; } } static void kill_verifier(struct verifier *verifier) { assert(verifier != NULL); assert(verifier->zone != NULL); if(kill(verifier->pid, SIGTERM) == -1) { log_msg(LOG_ERR, "verify: cannot kill verifier for " "zone %s (pid %d): %s", verifier->zone->opts->name, verifier->pid, strerror(errno)); } } static void close_stream(struct verifier *verifier, struct verifier_stream *stream) { if (stream->fd == -1) return; verify_handle_stream(stream->fd, EV_READ, verifier); if (stream->fd == -1) return; event_del(&stream->event); close(stream->fd); stream->fd = -1; } static void close_verifier(struct verifier *verifier) { /* unregister events and close streams (in that order) */ if(verifier->timeout.tv_sec > 0) { event_del(&verifier->timeout_event); verifier->timeout.tv_sec = 0; verifier->timeout.tv_usec = 0; } if(verifier->zone_feed.fh != NULL) { event_del(&verifier->zone_feed.event); fclose(verifier->zone_feed.fh); verifier->zone_feed.fh = NULL; region_destroy(verifier->zone_feed.region); } close_stream(verifier, &verifier->error_stream); close_stream(verifier, &verifier->output_stream); verifier->zone->is_ok = verifier->was_ok; verifier->pid = -1; verifier->zone = NULL; } /* * Feed zone to verifier over STDIN as it becomes available. */ static void verify_handle_feed(int fd, short event, void *arg) { struct verifier *verifier; struct rr *rr; (void)fd; assert(event == EV_WRITE); assert(arg != NULL); verifier = (struct verifier *)arg; if((rr = zone_rr_iter_next(&verifier->zone_feed.rriter)) != NULL) { print_rr(verifier->zone_feed.fh, verifier->zone_feed.rrprinter, rr, verifier->zone_feed.region, verifier->zone_feed.buffer); } else { event_del(&verifier->zone_feed.event); fclose(verifier->zone_feed.fh); verifier->zone_feed.fh = NULL; region_destroy(verifier->zone_feed.region); } } /* * This handler will be called when a verifier-timeout alarm goes off. It just * kills the verifier. server_verify_zones will make sure the zone will be * considered bad. */ void verify_handle_timeout(int fd, short event, void *arg) { struct verifier *verifier; (void)fd; assert(event & EV_TIMEOUT); assert(arg != NULL); verifier = (struct verifier *)arg; verifier->zone->is_bad = 1; log_msg(LOG_ERR, "verify: verifier for zone %s (pid %d) timed out", verifier->zone->opts->name, verifier->pid); /* kill verifier, process reaped by exit handler */ kill_verifier(verifier); } void verify_handle_signal(int sig, short event, void *arg) { char buf[1] = { '\0' }; struct nsd *nsd; assert(sig == SIGCHLD); assert(event & EV_SIGNAL); assert(arg != NULL); nsd = (struct nsd *)arg; if(write(nsd->verifier_pipe[1], buf, sizeof(buf)) == -1) { log_msg(LOG_ERR, "verify_handle_signal: write failed: %s", strerror(errno)); } } /* * Reap process and update status of respective zone based on the exit code * of a verifier. Everything from STDOUT and STDERR still available is read and * written to the log as it might contain valuable information. * * NOTE: A timeout might have caused the verifier to be terminated. */ void verify_handle_exit(int fd, short event, void *arg) { int wstatus; pid_t pid; struct nsd *nsd; char buf[1]; assert(event & EV_READ); assert(arg != NULL); nsd = (struct nsd *)arg; if(read(fd, buf, sizeof(buf)) == -1) { if(errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) log_msg(LOG_ERR, "verify_handle_exit: read failed: %s", strerror(errno)); } while(((pid = waitpid(-1, &wstatus, WNOHANG)) == -1 && errno == EINTR) || (pid > 0)) { struct verifier *verifier = NULL; for(size_t i = 0; !verifier && i < nsd->verifier_limit; i++) { if(nsd->verifiers[i].zone != NULL && nsd->verifiers[i].pid == pid) { verifier = &nsd->verifiers[i]; } } if(verifier == NULL) { continue; } if(!WIFEXITED(wstatus)) { log_msg(LOG_ERR, "verify: verifier for zone %s " "(pid %d) exited abnormally", verifier->zone->opts->name, pid); } else { int priority = LOG_INFO; int status = WEXITSTATUS(wstatus); if(status != 0) { priority = LOG_ERR; verifier->zone->is_bad = 1; } log_msg(priority, "verify: verifier for zone %s " "(pid %d) exited with %d", verifier->zone->opts->name, pid, status); } close_verifier(verifier); nsd->verifier_count--; } while(nsd->mode == NSD_RUN && nsd->verifier_count < nsd->verifier_limit && nsd->next_zone_to_verify != NULL) { verify_zone(nsd, nsd->next_zone_to_verify); nsd->next_zone_to_verify = verify_next_zone(nsd, nsd->next_zone_to_verify); } if(nsd->next_zone_to_verify == NULL && nsd->verifier_count == 0) { event_base_loopexit(nsd->event_base, NULL); return; } } /* * A parent may be terminated (by the NSD_QUIT signal (nsdc stop command)). * When a reload server process is running, the parent will then send a * NSD_QUIT command to that server. This handler makes sure that this command * is not neglected and that the reload server process will exit (gracefully). */ void verify_handle_command(int fd, short event, void *arg) { struct nsd *nsd = (struct nsd *)arg; int len; sig_atomic_t mode; assert(nsd != NULL); assert(event & (EV_READ #ifdef EV_CLOSED | EV_CLOSED #endif )); if((len = read(fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "verify: verify_handle_command: read: %s", strerror(errno)); return; } else if(len == 0) { log_msg(LOG_INFO, "verify: command channel closed"); mode = NSD_QUIT; } else if(mode != NSD_QUIT) { log_msg(LOG_ERR, "verify: bad command: %d", (int)mode); return; } nsd->mode = mode; if(nsd->verifier_count == 0) { event_base_loopexit(nsd->event_base, NULL); return; /* exit early if no verifiers are executing */ } /* kill verifiers, processes reaped elsewhere */ for(size_t i = 0; i < nsd->verifier_limit; i++) { if(nsd->verifiers[i].zone != NULL) { kill_verifier(&nsd->verifiers[i]); } } } /* * A verifier is executed for the specified zone (if a verifier is configured * and the zone has not been verified before). If one of the verifiers exits * with non-zero, the zone is marked bad and nsd drops the zone update and * reloads again. */ void verify_zone(struct nsd *nsd, struct zone *zone) { struct verifier *verifier = NULL; int32_t timeout; char **command; FILE *fin; int fdin, fderr, fdout, flags; assert(nsd != NULL); assert(nsd->verifier_count < nsd->verifier_limit); assert(zone != NULL); fin = NULL; fdin = fdout = fderr = -1; /* search for available verifier slot */ for(size_t i = 0; i < nsd->verifier_limit && !verifier; i++) { if(nsd->verifiers[i].zone == NULL) { verifier = &nsd->verifiers[i]; } } assert(verifier != NULL); if(zone->opts->pattern->verifier != NULL) { command = zone->opts->pattern->verifier; } else if (nsd->options->verifier != NULL) { command = nsd->options->verifier; } else { log_msg(LOG_ERR, "verify: no verifier for zone %s", zone->opts->name); return; } if(zone->opts->pattern->verifier_timeout != VERIFIER_TIMEOUT_INHERIT) { timeout = zone->opts->pattern->verifier_timeout; } else { timeout = nsd->options->verifier_timeout; } if(zone->opts->pattern->verifier_feed_zone != VERIFIER_FEED_ZONE_INHERIT) { fdin = zone->opts->pattern->verifier_feed_zone ? -2 : -1; } else { fdin = nsd->options->verifier_feed_zone ? -2 : -1; } assert(timeout >= 0); setenv("VERIFY_ZONE", zone->opts->name, 1); setenv("VERIFY_ZONE_ON_STDIN", fdin == -2 ? "yes" : "no", 1); verifier->pid = popen3( command, fdin == -2 ? &fdin : NULL, &fdout, &fderr); if(verifier->pid == -1) { log_msg(LOG_ERR, "verify: could not start verifier for zone " "%s: %s", zone->opts->name, strerror(errno)); goto fail_popen3; } flags = fcntl(fderr, F_GETFL, 0); if (fcntl(fderr, F_SETFL, flags | O_NONBLOCK) == -1) { log_msg(LOG_ERR, "verify: fcntl(stderr, ..., O_NONBLOCK) for " "zone %s: %s", zone->opts->name, strerror(errno)); goto fail_fcntl; } flags = fcntl(fdout, F_GETFL, 0); if(fcntl(fdout, F_SETFL, flags | O_NONBLOCK) == -1) { log_msg(LOG_ERR, "verify: fcntl(stdout, ..., O_NONBLOCK) for " "zone %s: %s", zone->opts->name, strerror(errno)); goto fail_fcntl; } if (fdin >= 0) { if ((fin = fdopen(fdin, "w")) == NULL) { log_msg(LOG_ERR, "verify: fdopen(stdin, ...) for " "zone %s: %s", zone->opts->name, strerror(errno)); goto fail_fcntl; } /* write unbuffered */ setbuf(fin, NULL); } verifier->zone = zone; verifier->was_ok = zone->is_ok; unsetenv("VERIFY_ZONE"); unsetenv("VERIFY_ZONE_ON_STDIN"); verifier->error_stream.fd = fderr; verifier->error_stream.cnt = 0; verifier->error_stream.off = 0; verifier->error_stream.buf[0] = '\0'; event_set(&verifier->error_stream.event, verifier->error_stream.fd, EV_READ|EV_PERSIST, verify_handle_stream, verifier); event_base_set(nsd->event_base, &verifier->error_stream.event); if(event_add(&verifier->error_stream.event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add error event for " "zone %s", zone->opts->name); goto fail_stderr; } verifier->output_stream.fd = fdout; verifier->output_stream.cnt = 0; verifier->output_stream.off = 0; verifier->output_stream.buf[0] = '\0'; event_set(&verifier->output_stream.event, verifier->output_stream.fd, EV_READ|EV_PERSIST, verify_handle_stream, verifier); event_base_set(nsd->event_base, &verifier->output_stream.event); if(event_add(&verifier->output_stream.event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add output event for " "zone %s", zone->opts->name); goto fail_stdout; } if(fin != NULL) { verifier->zone_feed.fh = fin; zone_rr_iter_init(&verifier->zone_feed.rriter, zone); verifier->zone_feed.rrprinter = create_pretty_rr(nsd->server_region); verifier->zone_feed.region = region_create(xalloc, free); verifier->zone_feed.buffer = buffer_create(nsd->server_region, MAX_RDLENGTH); event_set(&verifier->zone_feed.event, fileno(verifier->zone_feed.fh), EV_WRITE|EV_PERSIST, &verify_handle_feed, verifier); event_base_set(nsd->event_base, &verifier->zone_feed.event); if(event_add(&verifier->zone_feed.event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add input event " "for zone %s", zone->opts->name); goto fail_stdin; } } if(timeout > 0) { verifier->timeout.tv_sec = timeout; verifier->timeout.tv_usec = 0; event_set(&verifier->timeout_event, -1, EV_TIMEOUT, verify_handle_timeout, verifier); event_base_set(nsd->event_base, &verifier->timeout_event); if(event_add(&verifier->timeout_event, &verifier->timeout) != 0) { log_msg(LOG_ERR, "verify: could not add timeout event " "for zone %s", zone->opts->name); goto fail_timeout; } log_msg(LOG_INFO, "verify: started verifier for zone %s " "(pid %d), timeout is %d seconds", zone->opts->name, verifier->pid, timeout); } else { log_msg(LOG_INFO, "verify: started verifier for zone %s " "(pid %d)", zone->opts->name, verifier->pid); } zone->is_ok = 1; nsd->verifier_count++; return; fail_timeout: verifier->timeout.tv_sec = 0; verifier->timeout.tv_usec = 0; if(fin != NULL) { event_del(&verifier->zone_feed.event); } fail_stdin: verifier->zone_feed.fh = NULL; event_del(&verifier->output_stream.event); fail_stdout: verifier->output_stream.fd = -1; event_del(&verifier->error_stream.event); fail_stderr: verifier->error_stream.fd = -1; fail_fcntl: kill_verifier(verifier); if(fin != NULL) { fclose(fin); } else if (fdin >= 0) { close(fdin); } close(fdout); close(fderr); fail_popen3: zone->is_bad = 1; verifier->pid = -1; verifier->zone = NULL; } nsd-4.12.0/util/0000755000175000017500000000000015002373054012752 5ustar mozziemozziensd-4.12.0/util/proxy_protocol.h0000644000175000017500000001173015002373054016227 0ustar mozziemozzie/* * util/proxy_protocol.h - PROXY protocol * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains PROXY protocol structs and functions. * Only v2 is supported. TLVs are not currently supported. */ #ifndef PROXY_PROTOCOL_H #define PROXY_PROTOCOL_H #include "config.h" /** PROXYv2 minimum header size */ #define PP2_HEADER_SIZE 16 /** PROXYv2 header signature */ #define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" #define PP2_SIG_LEN 12 /** PROXYv2 version (protocol value) */ #define PP2_VERSION 0x2 /** * PROXYv2 command (protocol value). */ enum pp2_command { PP2_CMD_LOCAL = 0x0, PP2_CMD_PROXY = 0x1 }; /** * PROXYv2 address family (protocol value). */ enum pp2_af { PP2_AF_UNSPEC = 0x0, PP2_AF_INET = 0x1, PP2_AF_INET6 = 0x2, PP2_AF_UNIX = 0x3 }; /** * PROXYv2 protocol (protocol value). */ enum pp2_protocol { PP2_PROT_UNSPEC = 0x0, PP2_PROT_STREAM = 0x1, PP2_PROT_DGRAM = 0x2 }; /** * Expected combinations of address family and protocol values used in checks. */ enum pp2_af_protocol_combination { PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC, PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM, PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM, PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM, PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM, PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM, PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM }; /** * PROXYv2 header. */ struct pp2_header { uint8_t sig[PP2_SIG_LEN]; uint8_t ver_cmd; uint8_t fam_prot; uint16_t len; union { struct { /* for TCP/UDP over IPv4, len = 12 */ uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port; } addr4; struct { /* for TCP/UDP over IPv6, len = 36 */ uint8_t src_addr[16]; uint8_t dst_addr[16]; uint16_t src_port; uint16_t dst_port; } addr6; struct { /* for AF_UNIX sockets, len = 216 */ uint8_t src_addr[108]; uint8_t dst_addr[108]; } addru; } addr; }; /** * PROXY parse errors. */ enum pp_parse_errors { PP_PARSE_NOERROR = 0, PP_PARSE_SIZE, PP_PARSE_WRONG_HEADERv2, PP_PARSE_UNKNOWN_CMD, PP_PARSE_UNKNOWN_FAM_PROT, }; /** * Initialize the internal proxy structure. * @param write_uint16: pointer to a function that can write uint16. * @param write_uint32: pointer to a function that can write uint32. */ void pp_init(void (*write_uint16)(void* buf, uint16_t data), void (*write_uint32)(void* buf, uint32_t data)); /** * Lookup the parsing error description. * @param error: parsing error from pp2_read_header. * @return the description. */ const char* pp_lookup_error(enum pp_parse_errors error); /** * Write a PROXYv2 header at the current position of the buffer. * @param buf: pointer to the buffer to write data to. * @param buflen: available size on the buffer. * @param src: the source address. * @param stream: if the protocol is stream or datagram. * @return 1 on success, 0 on failure. */ size_t pp2_write_to_buf(uint8_t* buf, size_t buflen, #ifdef INET6 struct sockaddr_storage* src, #else struct sockaddr_in* src, #endif int stream); /** * Read a PROXYv2 header from the current position of the buffer. * It does initial validation and returns a pointer to the buffer position on * success. * @param buf: pointer to the buffer data to read from. * @param buflen: available size on the buffer. * @return parsing error, 0 on success. */ int pp2_read_header(uint8_t* buf, size_t buflen); #endif /* PROXY_PROTOCOL_H */ nsd-4.12.0/util/proxy_protocol.c0000644000175000017500000001303115002373054016216 0ustar mozziemozzie/* * util/proxy_protocol.c - event notification * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains PROXY protocol functions. */ #include "util/proxy_protocol.h" /** * Internal struct initialized with function pointers for writing uint16 and * uint32. */ struct proxy_protocol_data { void (*write_uint16)(void* buf, uint16_t data); void (*write_uint32)(void* buf, uint32_t data); }; struct proxy_protocol_data pp_data; /** * Internal lookup table; could be further generic like sldns_lookup_table * for all the future generic stuff. */ struct proxy_protocol_lookup_table { int id; const char *text; }; /** * Internal parsing error text; could be exposed with pp_lookup_error. */ static struct proxy_protocol_lookup_table pp_parse_errors_data[] = { { PP_PARSE_NOERROR, "no parse error" }, { PP_PARSE_SIZE, "not enough space for header" }, { PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" }, { PP_PARSE_UNKNOWN_CMD, "unknown command" }, { PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" }, }; void pp_init(void (*write_uint16)(void* buf, uint16_t data), void (*write_uint32)(void* buf, uint32_t data)) { pp_data.write_uint16 = write_uint16; pp_data.write_uint32 = write_uint32; } const char* pp_lookup_error(enum pp_parse_errors error) { return pp_parse_errors_data[error].text; } size_t pp2_write_to_buf(uint8_t* buf, size_t buflen, #ifdef INET6 struct sockaddr_storage* src, #else struct sockaddr_in* src, #endif int stream) { int af; size_t expected_size; if(!src) return 0; af = (int)((struct sockaddr_in*)src)->sin_family; expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36); if(buflen < expected_size) { return 0; } /* sig */ memcpy(buf, PP2_SIG, PP2_SIG_LEN); buf += PP2_SIG_LEN; /* version and command */ *buf = (PP2_VERSION << 4) | PP2_CMD_PROXY; buf++; switch(af) { case AF_INET: /* family and protocol */ *buf = (PP2_AF_INET<<4) | (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); buf++; /* length */ (*pp_data.write_uint16)(buf, 12); buf += 2; /* src addr */ memcpy(buf, &((struct sockaddr_in*)src)->sin_addr.s_addr, 4); buf += 4; /* dst addr */ (*pp_data.write_uint32)(buf, 0); buf += 4; /* src port */ memcpy(buf, &((struct sockaddr_in*)src)->sin_port, 2); buf += 2; /* dst addr */ /* dst port */ (*pp_data.write_uint16)(buf, 12); break; #ifdef INET6 case AF_INET6: /* family and protocol */ *buf = (PP2_AF_INET6<<4) | (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); buf++; /* length */ (*pp_data.write_uint16)(buf, 36); buf += 2; /* src addr */ memcpy(buf, &((struct sockaddr_in6*)src)->sin6_addr, 16); buf += 16; /* dst addr */ memset(buf, 0, 16); buf += 16; /* src port */ memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2); buf += 2; /* dst port */ (*pp_data.write_uint16)(buf, 0); break; #endif /* INET6 */ case AF_UNIX: /* fallthrough */ default: return 0; } return expected_size; } int pp2_read_header(uint8_t* buf, size_t buflen) { size_t size; struct pp2_header* header = (struct pp2_header*)buf; /* Try to fail all the unsupported cases first. */ if(buflen < PP2_HEADER_SIZE) { return PP_PARSE_SIZE; } /* Check for PROXYv2 header */ if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 || ((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) { return PP_PARSE_WRONG_HEADERv2; } /* Check the length */ size = PP2_HEADER_SIZE + ntohs(header->len); if(buflen < size) { return PP_PARSE_SIZE; } /* Check for supported commands */ if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL && (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { return PP_PARSE_UNKNOWN_CMD; } /* Check for supported family and protocol */ if(header->fam_prot != PP2_UNSPEC_UNSPEC && header->fam_prot != PP2_INET_STREAM && header->fam_prot != PP2_INET_DGRAM && header->fam_prot != PP2_INET6_STREAM && header->fam_prot != PP2_INET6_DGRAM && header->fam_prot != PP2_UNIX_STREAM && header->fam_prot != PP2_UNIX_DGRAM) { return PP_PARSE_UNKNOWN_FAM_PROT; } /* We have a correct header */ return PP_PARSE_NOERROR; } nsd-4.12.0/util.h0000644000175000017500000002605515002373054013133 0ustar mozziemozzie/* * util.h -- set of various support routines. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef UTIL_H #define UTIL_H #include #include #include #include struct rr; struct buffer; struct region; struct nsd; struct nsd_options; #ifdef HAVE_SYSLOG_H # include #else # define LOG_ERR 3 # define LOG_WARNING 4 # define LOG_NOTICE 5 # define LOG_INFO 6 /* Unused, but passed to log_open. */ # define LOG_PID 0x01 # define LOG_DAEMON (3<<3) #endif #define ALIGN_UP(n, alignment) \ (((n) + (alignment) - 1) & (~((alignment) - 1))) #define PADDING(n, alignment) \ (ALIGN_UP((n), (alignment)) - (n)) /* * Initialize the logging system. All messages are logged to stderr * until log_open and log_set_log_function are called. */ void log_init(const char *ident); #ifdef USE_LOG_PROCESS_ROLE /* * Set the name of the role for the process (for debugging purposes) */ void log_set_process_role(const char* role); #else #define log_set_process_role(role) /* empty */ #endif /* * Open the system log. If FILENAME is not NULL, a log file is opened * as well. */ void log_open(int option, int facility, const char *filename); /* * Reopen the logfile. */ void log_reopen(const char *filename, uint8_t verbose); /* * Finalize the logging system. */ void log_finalize(void); /* * Type of function to use for the actual logging. */ typedef void log_function_type(int priority, const char *message); /* * The function used to log to the log file. */ log_function_type log_file; /* * The function used to log to syslog. The messages are also logged * using log_file. */ log_function_type log_syslog; /* * The function used to log to syslog only. */ log_function_type log_only_syslog; /* * Set the logging function to use (log_file or log_syslog). */ void log_set_log_function(log_function_type *log_function); /* * Log a message using the current log function. */ void log_msg(int priority, const char *format, ...) ATTR_FORMAT(printf, 2, 3); /* * Log a message using the current log function. */ void log_vmsg(int priority, const char *format, va_list args); /* * Verbose output switch */ extern int verbosity; #define VERBOSITY(level, args) \ do { \ if ((level) <= verbosity) { \ log_msg args ; \ } \ } while (0) /* * Set the INDEXth bit of BITS to 1. */ void set_bit(uint8_t bits[], size_t index); /* * Set the INDEXth bit of BITS to 0. */ void clear_bit(uint8_t bits[], size_t index); /* * Return the value of the INDEXth bit of BITS. */ int get_bit(uint8_t bits[], size_t index); /* A general purpose lookup table */ typedef struct lookup_table lookup_table_type; struct lookup_table { int id; const char *name; }; /* * Looks up the table entry by name, returns NULL if not found. */ lookup_table_type *lookup_by_name(lookup_table_type table[], const char *name); /* * Looks up the table entry by id, returns NULL if not found. */ lookup_table_type *lookup_by_id(lookup_table_type table[], int id); /* * (Re-)allocate SIZE bytes of memory. Report an error if the memory * could not be allocated and exit the program. These functions never * return NULL. */ void *xalloc(size_t size); void *xmallocarray(size_t num, size_t size); void *xalloc_zero(size_t size); void *xalloc_array_zero(size_t num, size_t size); void *xrealloc(void *ptr, size_t size); char *xstrdup(const char *src); /* * Mmap allocator routines. * */ #ifdef USE_MMAP_ALLOC void *mmap_alloc(size_t size); void mmap_free(void *ptr); #endif /* USE_MMAP_ALLOC */ /* * Write SIZE bytes of DATA to FILE. Report an error on failure. * * Returns 0 on failure, 1 on success. */ int write_data(FILE *file, const void *data, size_t size); /* * like write_data, but keeps track of crc */ int write_data_crc(FILE *file, const void *data, size_t size, uint32_t* crc); /* * Write the complete buffer to the socket, irrespective of short * writes or interrupts. This function blocks to write the data. * Returns 0 on error, 1 on success. */ int write_socket(int s, const void *data, size_t size); /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ static inline void write_uint16(void *dst, uint16_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint16_t *) dst = htons(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 8) & 0xff); p[1] = (uint8_t) (data & 0xff); #endif } static inline void write_uint32(void *dst, uint32_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint32_t *) dst = htonl(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 24) & 0xff); p[1] = (uint8_t) ((data >> 16) & 0xff); p[2] = (uint8_t) ((data >> 8) & 0xff); p[3] = (uint8_t) (data & 0xff); #endif } static inline void write_uint64(void *dst, uint64_t data) { uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 56) & 0xff); p[1] = (uint8_t) ((data >> 48) & 0xff); p[2] = (uint8_t) ((data >> 40) & 0xff); p[3] = (uint8_t) ((data >> 32) & 0xff); p[4] = (uint8_t) ((data >> 24) & 0xff); p[5] = (uint8_t) ((data >> 16) & 0xff); p[6] = (uint8_t) ((data >> 8) & 0xff); p[7] = (uint8_t) (data & 0xff); } /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ static inline uint16_t read_uint16(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohs(* (const uint16_t *) src); #else const uint8_t *p = (const uint8_t *) src; return (p[0] << 8) | p[1]; #endif } static inline uint32_t read_uint32(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohl(* (const uint32_t *) src); #else const uint8_t *p = (const uint8_t *) src; return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; #endif } static inline uint64_t read_uint64(const void *src) { const uint8_t *p = (const uint8_t *) src; return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) | ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | ((uint64_t)p[6] << 8) | (uint64_t)p[7]; } /* * Print debugging information using log_msg, * set the logfile as /dev/stdout or /dev/stderr if you like. * nsd -F 0xFFFF enables all debug facilities. */ #define DEBUG_PARSER 0x0001U #define DEBUG_ZONEC 0x0002U #define DEBUG_QUERY 0x0004U #define DEBUG_DBACCESS 0x0008U #define DEBUG_NAME_COMPRESSION 0x0010U #define DEBUG_XFRD 0x0020U #define DEBUG_IPC 0x0040U extern unsigned nsd_debug_facilities; extern int nsd_debug_level; #ifdef NDEBUG #define DEBUG(facility, level, args) /* empty */ #else #define DEBUG(facility, level, args) \ do { \ if ((facility) & nsd_debug_facilities && \ (level) <= nsd_debug_level) { \ log_msg args ; \ } \ } while (0) #endif /* set to true to log time prettyprinted, or false to print epoch */ extern int log_time_asc; /* set to true to log time in iso format */ extern int log_time_iso; /* * Timespec functions. */ int timespec_compare(const struct timespec *left, const struct timespec *right); void timespec_add(struct timespec *left, const struct timespec *right); void timespec_subtract(struct timespec *left, const struct timespec *right); static inline void timeval_to_timespec(struct timespec *left, const struct timeval *right) { left->tv_sec = right->tv_sec; left->tv_nsec = 1000 * right->tv_usec; } /* get the time */ void get_time(struct timespec* t); /* * Convert binary data to a string of hexadecimal characters. */ ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize); /* * convert base32 data from and to string. Returns length. * -1 on error. Use (byte count*8)%5==0. */ int b32_pton(char const *src, uint8_t *target, size_t targsize); int b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); /* * Strip trailing and leading whitespace from str. */ void strip_string(char *str); /* * Convert a single (hexadecimal) digit to its integer value. */ int hexdigit_to_int(char ch); /* * Add bytes to given crc. Returns new CRC sum. * Start crc val with 0xffffffff on first call. XOR crc with * 0xffffffff at the end again to get final POSIX 1003.2 checksum. */ uint32_t compute_crc(uint32_t crc, uint8_t* data, size_t len); /* * Compares two 32-bit serial numbers as defined in RFC1982. Returns * <0 if a < b, 0 if a == b, and >0 if a > b. The result is undefined * if a != b but neither is greater or smaller (see RFC1982 section * 3.2.). */ int compare_serial(uint32_t a, uint32_t b); /* * Generate a random query ID. */ uint16_t qid_generate(void); /* value between 0 .. (max-1) inclusive */ int random_generate(int max); /* * call region_destroy on (region*)data, useful for region_add_cleanup(). */ void cleanup_region(void *data); /* * Region used to store owner and origin of previous RR (used * for pretty printing of zone data). * Keep the same between calls to print_rr. */ struct state_pretty_rr { struct region *previous_owner_region; const struct dname *previous_owner; const struct dname *previous_owner_origin; }; struct state_pretty_rr* create_pretty_rr(struct region* region); /* print rr to file, returns 0 on failure(nothing is written) */ int print_rr(FILE *out, struct state_pretty_rr* state, struct rr *record, struct region* tmp_region, struct buffer* tmp_buffer); /* * Convert a numeric rcode value to a human readable string */ const char* rcode2str(int rc); void addr2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len); /* print addr@port */ void addrport2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len); /** copy dirname string and append slash. Previous dirname is leaked, * but it is to be used once, at startup, for chroot */ void append_trailing_slash(const char** dirname, struct region* region); /** true if filename starts with chroot or is not absolute */ int file_inside_chroot(const char* fname, const char* chr); /** Something went wrong, give error messages and exit. */ void error(const char *format, ...) ATTR_FORMAT(printf, 1, 2) ATTR_NORETURN; #if HAVE_CPUSET_T int number_of_cpus(void); int set_cpu_affinity(cpuset_t *set); #endif /* Add a cookie secret. If there are no secrets yet, the secret will become * the active secret. Otherwise it will become the staging secret. * Active secrets are used to both verify and create new DNS Cookies. * Staging secrets are only used to verify DNS Cookies. */ void add_cookie_secret(struct nsd* nsd, uint8_t* secret); /* Makes the staging cookie secret active and the active secret staging. */ void activate_cookie_secret(struct nsd* nsd); /* Drop a cookie secret. Drops the staging secret. An active secret will not * be dropped. */ void drop_cookie_secret(struct nsd* nsd); /* Configure nsd struct with how to respond to DNS Cookies based on options */ void reconfig_cookies(struct nsd* nsd, struct nsd_options* options); #endif /* UTIL_H */ nsd-4.12.0/util.c0000644000175000017500000007710215002373054013125 0ustar mozziemozzie/* * util.c -- set of various support routines. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #ifdef HAVE_OPENSSL_RAND_H #include #endif #include #include #include #include #ifdef HAVE_SCHED_H #include #endif /* HAVE_SCHED_H */ #ifdef HAVE_SYS_CPUSET_H #include #endif /* HAVE_SYS_CPUSET_H */ #ifdef HAVE_SYSLOG_H #include #endif /* HAVE_SYSLOG_H */ #include #ifdef HAVE_SYS_RANDOM_H #include #endif #include "util.h" #include "region-allocator.h" #include "dname.h" #include "namedb.h" #include "rdata.h" #include "zonec.h" #include "nsd.h" #include "options.h" #ifdef USE_MMAP_ALLOC #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #elif defined(MAP_ANONYMOUS) && !defined(MAP_ANON) #define MAP_ANON MAP_ANONYMOUS #endif #endif /* USE_MMAP_ALLOC */ #ifndef NDEBUG unsigned nsd_debug_facilities = 0xffff; int nsd_debug_level = 0; #endif #define MSB_32 0x80000000 int verbosity = 0; static const char *global_ident = NULL; static log_function_type *current_log_function = log_file; static FILE *current_log_file = NULL; int log_time_asc = 1; int log_time_iso = 0; #ifdef USE_LOG_PROCESS_ROLE void log_set_process_role(const char *process_role) { global_ident = process_role; } #endif void log_init(const char *ident) { global_ident = ident; current_log_file = stderr; } void log_open(int option, int facility, const char *filename) { #ifdef HAVE_SYSLOG_H openlog(global_ident, option, facility); #endif /* HAVE_SYSLOG_H */ if (filename) { FILE *file = fopen(filename, "a"); if (!file) { log_msg(LOG_ERR, "Cannot open %s for appending (%s), " "logging to stderr", filename, strerror(errno)); } else { current_log_file = file; } } } void log_reopen(const char *filename, uint8_t verbose) { if (filename) { FILE *file; if(strcmp(filename, "/dev/stdout")==0 || strcmp(filename, "/dev/stderr")==0) return; file = fopen(filename, "a"); if (!file) { if (verbose) VERBOSITY(2, (LOG_WARNING, "Cannot reopen %s for appending (%s), " "keeping old logfile", filename, strerror(errno))); } else { if (current_log_file && current_log_file != stderr) fclose(current_log_file); current_log_file = file; } } } void log_finalize(void) { #ifdef HAVE_SYSLOG_H closelog(); #endif /* HAVE_SYSLOG_H */ if (current_log_file && current_log_file != stderr) { fclose(current_log_file); } current_log_file = NULL; } static lookup_table_type log_priority_table[] = { { LOG_ERR, "error" }, { LOG_WARNING, "warning" }, { LOG_NOTICE, "notice" }, { LOG_INFO, "info" }, { 0, NULL } }; void log_file(int priority, const char *message) { size_t length; lookup_table_type *priority_info; const char *priority_text = "unknown"; assert(global_ident); assert(current_log_file); priority_info = lookup_by_id(log_priority_table, priority); if (priority_info) { priority_text = priority_info->name; } /* Bug #104, add time_t timestamp */ #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) if(log_time_asc) { struct timeval tv; char tmbuf[32]; tmbuf[0]=0; tv.tv_usec = 0; if(log_time_iso) { char tzbuf[16]; tzbuf[0]=0; /* log time in iso format */ if(gettimeofday(&tv, NULL) == 0) { struct tm tm, *tm_p; time_t now = (time_t)tv.tv_sec; tm_p = localtime_r(&now, &tm); strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%dT%H:%M:%S", tm_p); if(strftime(tzbuf, sizeof(tzbuf), "%z", tm_p) == 5) { /* put ':' in "+hh:mm" */ tzbuf[5] = tzbuf[4]; tzbuf[4] = tzbuf[3]; tzbuf[3] = ':'; tzbuf[6] = 0; } } fprintf(current_log_file, "%s.%3.3d%s %s[%d]: %s: %s", tmbuf, (int)tv.tv_usec/1000, tzbuf, global_ident, (int) getpid(), priority_text, message); } else { /* log time in ascii format */ if(gettimeofday(&tv, NULL) == 0) { struct tm tm; time_t now = (time_t)tv.tv_sec; strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", localtime_r(&now, &tm)); } fprintf(current_log_file, "[%s.%3.3d] %s[%d]: %s: %s", tmbuf, (int)tv.tv_usec/1000, global_ident, (int) getpid(), priority_text, message); } } else #endif /* have time functions */ fprintf(current_log_file, "[%d] %s[%d]: %s: %s", (int)time(NULL), global_ident, (int) getpid(), priority_text, message); length = strlen(message); if (length == 0 || message[length - 1] != '\n') { fprintf(current_log_file, "\n"); } fflush(current_log_file); } void log_syslog(int priority, const char *message) { #ifdef HAVE_SYSLOG_H syslog(priority, "%s", message); #endif /* !HAVE_SYSLOG_H */ log_file(priority, message); } void log_only_syslog(int priority, const char *message) { #ifdef HAVE_SYSLOG_H syslog(priority, "%s", message); #else /* !HAVE_SYSLOG_H */ /* no syslog, use stderr */ log_file(priority, message); #endif } void log_set_log_function(log_function_type *log_function) { current_log_function = log_function; } void log_msg(int priority, const char *format, ...) { va_list args; va_start(args, format); log_vmsg(priority, format, args); va_end(args); } void log_vmsg(int priority, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; vsnprintf(message, sizeof(message), format, args); current_log_function(priority, message); } void set_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ bits[index / 8] |= (1 << (7 - index % 8)); } void clear_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ bits[index / 8] &= ~(1 << (7 - index % 8)); } int get_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ return bits[index / 8] & (1 << (7 - index % 8)); } lookup_table_type * lookup_by_name(lookup_table_type *table, const char *name) { while (table->name != NULL) { if (strcasecmp(name, table->name) == 0) return table; table++; } return NULL; } lookup_table_type * lookup_by_id(lookup_table_type *table, int id) { while (table->name != NULL) { if (table->id == id) return table; table++; } return NULL; } char * xstrdup(const char *src) { char *result = strdup(src); if(!result) { log_msg(LOG_ERR, "strdup failed: %s", strerror(errno)); exit(1); } return result; } void * xalloc(size_t size) { void *result = malloc(size); if (!result) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } return result; } void * xmallocarray(size_t num, size_t size) { void *result = reallocarray(NULL, num, size); if (!result) { log_msg(LOG_ERR, "reallocarray failed: %s", strerror(errno)); exit(1); } return result; } void * xalloc_zero(size_t size) { void *result = calloc(1, size); if (!result) { log_msg(LOG_ERR, "calloc failed: %s", strerror(errno)); exit(1); } return result; } void * xalloc_array_zero(size_t num, size_t size) { void *result = calloc(num, size); if (!result) { log_msg(LOG_ERR, "calloc failed: %s", strerror(errno)); exit(1); } return result; } void * xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (!ptr) { log_msg(LOG_ERR, "realloc failed: %s", strerror(errno)); exit(1); } return ptr; } #ifdef USE_MMAP_ALLOC void * mmap_alloc(size_t size) { void *base; size += MMAP_ALLOC_HEADER_SIZE; #ifdef HAVE_MMAP base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (base == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE_MMAP */ log_msg(LOG_ERR, "mmap failed: don't have mmap"); exit(1); #endif /* HAVE_MMAP */ *((size_t*) base) = size; return (void*)((uintptr_t)base + MMAP_ALLOC_HEADER_SIZE); } void mmap_free(void *ptr) { void *base; size_t size; if (!ptr) return; base = (void*)((uintptr_t)ptr - MMAP_ALLOC_HEADER_SIZE); size = *((size_t*) base); #ifdef HAVE_MUNMAP if (munmap(base, size) == -1) { log_msg(LOG_ERR, "munmap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE_MUNMAP */ log_msg(LOG_ERR, "munmap failed: don't have munmap"); exit(1); #endif /* HAVE_MUNMAP */ } #endif /* USE_MMAP_ALLOC */ int write_data(FILE *file, const void *data, size_t size) { size_t result; if (size == 0) return 1; result = fwrite(data, 1, size, file); if (result == 0) { log_msg(LOG_ERR, "write failed: %s", strerror(errno)); return 0; } else if (result < size) { log_msg(LOG_ERR, "short write (disk full?)"); return 0; } else { return 1; } } int write_socket(int s, const void *buf, size_t size) { const char* data = (const char*)buf; size_t total_count = 0; while (total_count < size) { ssize_t count = write(s, data + total_count, size - total_count); if (count == -1) { if (errno != EAGAIN && errno != EINTR) { return 0; } else { continue; } } total_count += count; } return 1; } void get_time(struct timespec* t) { struct timeval tv; #ifdef HAVE_CLOCK_GETTIME /* first try nanosecond precision */ if(clock_gettime(CLOCK_REALTIME, t)>=0) { return; /* success */ } log_msg(LOG_ERR, "clock_gettime: %s", strerror(errno)); #endif /* try millisecond precision */ if(gettimeofday(&tv, NULL)>=0) { t->tv_sec = tv.tv_sec; t->tv_nsec = tv.tv_usec*1000; return; /* success */ } log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); /* whole seconds precision */ t->tv_sec = time(0); t->tv_nsec = 0; } int timespec_compare(const struct timespec *left, const struct timespec *right) { /* Compare seconds. */ if (left->tv_sec < right->tv_sec) { return -1; } else if (left->tv_sec > right->tv_sec) { return 1; } else { /* Seconds are equal, compare nanoseconds. */ if (left->tv_nsec < right->tv_nsec) { return -1; } else if (left->tv_nsec > right->tv_nsec) { return 1; } else { return 0; } } } /* One second is 1e9 nanoseconds. */ #define NANOSECONDS_PER_SECOND 1000000000L void timespec_add(struct timespec *left, const struct timespec *right) { left->tv_sec += right->tv_sec; left->tv_nsec += right->tv_nsec; if (left->tv_nsec >= NANOSECONDS_PER_SECOND) { /* Carry. */ ++left->tv_sec; left->tv_nsec -= NANOSECONDS_PER_SECOND; } } void timespec_subtract(struct timespec *left, const struct timespec *right) { left->tv_sec -= right->tv_sec; left->tv_nsec -= right->tv_nsec; if (left->tv_nsec < 0L) { /* Borrow. */ --left->tv_sec; left->tv_nsec += NANOSECONDS_PER_SECOND; } } ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { static char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; size_t i; if (targsize < srclength * 2 + 1) { return -1; } for (i = 0; i < srclength; ++i) { *target++ = hexdigits[src[i] >> 4U]; *target++ = hexdigits[src[i] & 0xfU]; } *target = '\0'; return 2 * srclength; } ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize) { uint8_t *t = target; if(strlen(src) % 2 != 0 || strlen(src)/2 > targsize) { return -1; } while(*src) { if(!isxdigit((unsigned char)src[0]) || !isxdigit((unsigned char)src[1])) return -1; *t++ = hexdigit_to_int(src[0]) * 16 + hexdigit_to_int(src[1]) ; src += 2; } return t-target; } int b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { static char b32[]="0123456789abcdefghijklmnopqrstuv"; char buf[9]; ssize_t len=0; while(srclength > 0) { int t; memset(buf,'\0',sizeof buf); /* xxxxx000 00000000 00000000 00000000 00000000 */ buf[0]=b32[src[0] >> 3]; /* 00000xxx xx000000 00000000 00000000 00000000 */ t=(src[0]&7) << 2; if(srclength > 1) t+=src[1] >> 6; buf[1]=b32[t]; if(srclength == 1) break; /* 00000000 00xxxxx0 00000000 00000000 00000000 */ buf[2]=b32[(src[1] >> 1)&0x1f]; /* 00000000 0000000x xxxx0000 00000000 00000000 */ t=(src[1]&1) << 4; if(srclength > 2) t+=src[2] >> 4; buf[3]=b32[t]; if(srclength == 2) break; /* 00000000 00000000 0000xxxx x0000000 00000000 */ t=(src[2]&0xf) << 1; if(srclength > 3) t+=src[3] >> 7; buf[4]=b32[t]; if(srclength == 3) break; /* 00000000 00000000 00000000 0xxxxx00 00000000 */ buf[5]=b32[(src[3] >> 2)&0x1f]; /* 00000000 00000000 00000000 000000xx xxx00000 */ t=(src[3]&3) << 3; if(srclength > 4) t+=src[4] >> 5; buf[6]=b32[t]; if(srclength == 4) break; /* 00000000 00000000 00000000 00000000 000xxxxx */ buf[7]=b32[src[4]&0x1f]; if(targsize < 8) return -1; src += 5; srclength -= 5; memcpy(target,buf,8); target += 8; targsize -= 8; len += 8; } if(srclength) { size_t tlen = strlcpy(target, buf, targsize); if (tlen >= targsize) return -1; len += tlen; } else if(targsize < 1) return -1; else *target='\0'; return len; } int b32_pton(const char *src, uint8_t *target, size_t tsize) { char ch; size_t p=0; memset(target,'\0',tsize); while((ch = *src++)) { uint8_t d; size_t b; size_t n; if(p+5 >= tsize*8) return -1; if(isspace((unsigned char)ch)) continue; if(ch >= '0' && ch <= '9') d=ch-'0'; else if(ch >= 'A' && ch <= 'V') d=ch-'A'+10; else if(ch >= 'a' && ch <= 'v') d=ch-'a'+10; else return -1; b=7-p%8; n=p/8; if(b >= 4) target[n]|=d << (b-4); else { target[n]|=d >> (4-b); target[n+1]|=d << (b+4); } p+=5; } return (p+7)/8; } void strip_string(char *str) { char *start = str; char *end = str + strlen(str) - 1; while (isspace((unsigned char)*start)) ++start; if (start > end) { /* Completely blank. */ str[0] = '\0'; } else { while (isspace((unsigned char)*end)) --end; *++end = '\0'; if (str != start) memmove(str, start, end - start + 1); } } int hexdigit_to_int(char ch) { switch (ch) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: abort(); } } /* code to calculate CRC. Lifted from BSD 4.4 crc.c in cksum(1). BSD license. http://www.tsfr.org/~orc/Code/bsd/bsd-current/cksum/crc.c. or http://gobsd.com/code/freebsd/usr.bin/cksum/crc.c The polynomial is 0x04c11db7L. */ static uint32_t crctab[] = { 0x0, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] uint32_t compute_crc(uint32_t crc, uint8_t* data, size_t len) { size_t i; for(i=0; i b && a - b > cutoff)) { return -1; } else { return 1; } } uint16_t qid_generate(void) { #ifdef HAVE_GETRANDOM uint16_t r; if(getrandom(&r, sizeof(r), 0) == -1) { log_msg(LOG_ERR, "getrandom failed: %s", strerror(errno)); exit(1); } return r; #elif defined(HAVE_ARC4RANDOM) /* arc4random_uniform not needed because range is a power of 2 */ return (uint16_t) arc4random(); #else return (uint16_t) random(); #endif } int random_generate(int max) { #ifdef HAVE_GETRANDOM int r; if(getrandom(&r, sizeof(r), 0) == -1) { log_msg(LOG_ERR, "getrandom failed: %s", strerror(errno)); exit(1); } return (int)(((unsigned)r)%max); #elif defined(HAVE_ARC4RANDOM_UNIFORM) return (int) arc4random_uniform(max); #elif defined(HAVE_ARC4RANDOM) return (int) (arc4random() % max); #else return (int) ((unsigned)random() % max); #endif } void cleanup_region(void *data) { region_type *region = (region_type *) data; region_destroy(region); } struct state_pretty_rr* create_pretty_rr(struct region* region) { struct state_pretty_rr* state = (struct state_pretty_rr*) region_alloc(region, sizeof(struct state_pretty_rr)); state->previous_owner_region = region_create(xalloc, free); state->previous_owner = NULL; state->previous_owner_origin = NULL; region_add_cleanup(region, cleanup_region, state->previous_owner_region); return state; } static void set_previous_owner(struct state_pretty_rr *state, const dname_type *dname) { region_free_all(state->previous_owner_region); state->previous_owner = dname_copy(state->previous_owner_region, dname); state->previous_owner_origin = dname_origin( state->previous_owner_region, state->previous_owner); } int print_rr(FILE *out, struct state_pretty_rr *state, rr_type *record, region_type* rr_region, buffer_type* output) { rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(record->type); int result; const dname_type *owner = domain_dname(record->owner); buffer_clear(output); if (state) { if (!state->previous_owner || dname_compare(state->previous_owner, owner) != 0) { const dname_type *owner_origin = dname_origin(rr_region, owner); int origin_changed = (!state->previous_owner_origin || dname_compare(state->previous_owner_origin, owner_origin) != 0); if (origin_changed) { buffer_printf(output, "$ORIGIN %s\n", dname_to_string(owner_origin, NULL)); } set_previous_owner(state, owner); buffer_printf(output, "%s", dname_to_string(owner, state->previous_owner_origin)); region_free_all(rr_region); } } else { buffer_printf(output, "%s", dname_to_string(owner, NULL)); } buffer_printf(output, "\t%lu\t%s\t%s", (unsigned long) record->ttl, rrclass_to_string(record->klass), rrtype_to_string(record->type)); result = print_rdata(output, descriptor, record); if (!result) { /* * Some RDATA failed to print, so print the record's * RDATA in unknown format. */ result = rdata_atoms_to_unknown_string(output, descriptor, record->rdata_count, record->rdatas); } if (result) { buffer_printf(output, "\n"); buffer_flip(output); result = write_data(out, buffer_current(output), buffer_remaining(output)); } return result; } const char* rcode2str(int rc) { switch(rc) { case RCODE_OK: return "NO ERROR"; case RCODE_FORMAT: return "FORMAT ERROR"; case RCODE_SERVFAIL: return "SERVFAIL"; case RCODE_NXDOMAIN: return "NAME ERROR"; case RCODE_IMPL: return "NOT IMPL"; case RCODE_REFUSE: return "REFUSED"; case RCODE_YXDOMAIN: return "YXDOMAIN"; case RCODE_YXRRSET: return "YXRRSET"; case RCODE_NXRRSET: return "NXRRSET"; case RCODE_NOTAUTH: return "SERVER NOT AUTHORITATIVE FOR ZONE"; case RCODE_NOTZONE: /* Name not contained in zone */ return "NOTZONE"; default: return "UNKNOWN ERROR"; } return NULL; /* ENOREACH */ } void addr2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len) { #ifdef INET6 if (addr->ss_family == AF_INET6) { if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, str, len)) strlcpy(str, "[unknown ip6, inet_ntop failed]", len); return; } #endif if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, str, len)) strlcpy(str, "[unknown ip4, inet_ntop failed]", len); } void addrport2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len) { char ip[256]; #ifdef INET6 if (addr->ss_family == AF_INET6) { if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, ip, sizeof(ip))) strlcpy(ip, "[unknown ip6, inet_ntop failed]", sizeof(ip)); /* append port number */ snprintf(str, len, "%s@%u", ip, (unsigned)ntohs(((struct sockaddr_in6 *)addr)->sin6_port)); return; } else #endif if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, ip, sizeof(ip))) strlcpy(ip, "[unknown ip4, inet_ntop failed]", sizeof(ip)); /* append port number */ snprintf(str, len, "%s@%u", ip, (unsigned)ntohs(((struct sockaddr_in *)addr)->sin_port)); } void append_trailing_slash(const char** dirname, region_type* region) { int l = strlen(*dirname); if (l>0 && (*dirname)[l-1] != '/' && l < 0xffffff) { char *dirname_slash = region_alloc(region, l+2); memcpy(dirname_slash, *dirname, l+1); strlcat(dirname_slash, "/", l+2); /* old dirname is leaked, this is only used for chroot, once */ *dirname = dirname_slash; } } int file_inside_chroot(const char* fname, const char* chr) { /* true if filename starts with chroot or is not absolute */ return ((fname && fname[0] && strncmp(fname, chr, strlen(chr)) == 0) || (fname && fname[0] != '/')); } /* * Something went wrong, give error messages and exit. */ void error(const char *format, ...) { va_list args; va_start(args, format); log_vmsg(LOG_ERR, format, args); va_end(args); exit(1); } #ifdef HAVE_CPUSET_T #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) /* exists on Linux and FreeBSD */ int number_of_cpus(void) { return (int)sysconf(_SC_NPROCESSORS_CONF); } #else int number_of_cpus(void) { return -1; } #endif #ifdef __gnu_hurd__ /* HURD has no sched_setaffinity implementation, but links an always fail, * with a linker error, we print an error when it is used */ int set_cpu_affinity(cpuset_t *ATTR_UNUSED(set)) { log_msg(LOG_ERR, "sched_setaffinity: not available on this system"); return -1; } #elif defined(HAVE_SCHED_SETAFFINITY) /* Linux */ int set_cpu_affinity(cpuset_t *set) { assert(set != NULL); return sched_setaffinity(getpid(), sizeof(*set), set); } #else /* FreeBSD */ int set_cpu_affinity(cpuset_t *set) { assert(set != NULL); return cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(*set), set); } #endif #endif /* HAVE_CPUSET_T */ void add_cookie_secret(struct nsd* nsd, uint8_t* secret) { /* New cookie secret becomes the staging secret (position 1) * unless there is no active cookie yet, then it becomes the active * secret. If the NSD_COOKIE_HISTORY_SIZE > 2 then all staging cookies * are moved one position down. */ if(nsd->cookie_count == 0) { memcpy( nsd->cookie_secrets->cookie_secret , secret, NSD_COOKIE_SECRET_SIZE); nsd->cookie_count = 1; explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE); return; } #if NSD_COOKIE_HISTORY_SIZE > 2 memmove( &nsd->cookie_secrets[2], &nsd->cookie_secrets[1] , sizeof(struct cookie_secret) * (NSD_COOKIE_HISTORY_SIZE - 2)); #endif memcpy( nsd->cookie_secrets[1].cookie_secret , secret, NSD_COOKIE_SECRET_SIZE); nsd->cookie_count = nsd->cookie_count < NSD_COOKIE_HISTORY_SIZE ? nsd->cookie_count + 1 : NSD_COOKIE_HISTORY_SIZE; explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE); } void activate_cookie_secret(struct nsd* nsd) { uint8_t active_secret[NSD_COOKIE_SECRET_SIZE]; /* The staging secret becomes the active secret. * The active secret becomes a staging secret. * If the NSD_COOKIE_HISTORY_SIZE > 2 then all staging secrets are moved * one position up and the previously active secret becomes the last * staging secret. */ if(nsd->cookie_count < 2) return; memcpy( active_secret, nsd->cookie_secrets[0].cookie_secret , NSD_COOKIE_SECRET_SIZE); memmove( &nsd->cookie_secrets[0], &nsd->cookie_secrets[1] , sizeof(struct cookie_secret) * (NSD_COOKIE_HISTORY_SIZE - 1)); memcpy( nsd->cookie_secrets[nsd->cookie_count - 1].cookie_secret , active_secret, NSD_COOKIE_SECRET_SIZE); explicit_bzero(active_secret, NSD_COOKIE_SECRET_SIZE); } void drop_cookie_secret(struct nsd* nsd) { /* Drops a staging cookie secret. If there are more than one, it will * drop the last staging secret. */ if(nsd->cookie_count < 2) return; explicit_bzero( nsd->cookie_secrets[nsd->cookie_count - 1].cookie_secret , NSD_COOKIE_SECRET_SIZE); nsd->cookie_count -= 1; } void reconfig_cookies(struct nsd* nsd, struct nsd_options* options) { cookie_secret_type cookie_secrets[NSD_COOKIE_HISTORY_SIZE]; char secret[NSD_COOKIE_SECRET_SIZE * 2 + 2/*'\n' and '\0'*/]; FILE* f = NULL; size_t count = 0; const char* fn; size_t i, j; nsd->do_answer_cookie = options->answer_cookie; /* Cookie secrets in the configuration file take precedence */ if(options->cookie_secret) { #ifndef NDEBUG ssize_t len = #endif hex_pton(options->cookie_secret, nsd->cookie_secrets[0].cookie_secret, NSD_COOKIE_SECRET_SIZE); /* Cookie length guaranteed in configparser.y */ assert(len == NSD_COOKIE_SECRET_SIZE); nsd->cookie_count = 1; if(options->cookie_staging_secret) { #ifndef NDEBUG len = #endif hex_pton(options->cookie_staging_secret, nsd->cookie_secrets[1].cookie_secret, NSD_COOKIE_SECRET_SIZE); /* Cookie length guaranteed in configparser.y */ assert(len == NSD_COOKIE_SECRET_SIZE); nsd->cookie_count = 2; } /*************************************************************/ nsd->cookie_secrets_source = COOKIE_SECRETS_FROM_CONFIG; return; /*************************************************************/ } /* Are cookies from file explicitly disabled? */ if(!(fn = nsd->options->cookie_secret_file)) goto generate_cookie_secrets; else if((f = fopen(fn, "r")) != NULL) ; /* pass */ /* a non-existing cookie file is not necessarily an error */ else if(errno != ENOENT) { log_msg( LOG_ERR , "error reading cookie secret file \"%s\": \"%s\"" , fn, strerror(errno)); goto generate_cookie_secrets; /* Only at startup cookie_secrets_source == COOKIE_SECRETS_NONE. * Only then the previous default file location will be tried * when the current default file location didn't exist. */ } else if(nsd->cookie_secrets_source == COOKIE_SECRETS_NONE && nsd->options->cookie_secret_file_is_default && (f = fopen((fn = CONFIGDIR"/nsd_cookiesecrets.txt"),"r"))) ; /* pass */ else if(errno != ENOENT) { log_msg( LOG_ERR , "error reading cookie secret file \"%s\": \"%s\"" , fn, strerror(errno)); goto generate_cookie_secrets; } else goto generate_cookie_secrets; /* cookie secret file exists and is readable */ for( count = 0; count < NSD_COOKIE_HISTORY_SIZE; count++ ) { size_t secret_len = 0; ssize_t decoded_len = 0; if( fgets(secret, sizeof(secret), f) == NULL ) { break; } secret_len = strlen(secret); if( secret_len == 0 ) { break; } assert( secret_len <= sizeof(secret) ); secret_len = secret[secret_len - 1] == '\n' ? secret_len - 1 : secret_len; if( secret_len != NSD_COOKIE_SECRET_SIZE * 2 ) { fclose(f); log_msg( LOG_ERR , "error parsing cookie secret file \"%s\"" , fn); explicit_bzero(cookie_secrets, sizeof(cookie_secrets)); explicit_bzero(secret, sizeof(secret)); goto generate_cookie_secrets; } /* needed for `hex_pton`; stripping potential `\n` */ secret[secret_len] = '\0'; decoded_len = hex_pton(secret, cookie_secrets[count].cookie_secret, NSD_COOKIE_SECRET_SIZE); if( decoded_len != NSD_COOKIE_SECRET_SIZE ) { fclose(f); log_msg( LOG_ERR , "error parsing cookie secret file \"%s\"" , fn); explicit_bzero(cookie_secrets, sizeof(cookie_secrets)); explicit_bzero(secret, sizeof(secret)); goto generate_cookie_secrets; } explicit_bzero(secret, sizeof(secret)); } fclose(f); if(count) { nsd->cookie_count = count; memcpy(nsd->cookie_secrets, cookie_secrets, sizeof(cookie_secrets)); region_str_replace( nsd->region , &nsd->cookie_secrets_filename, fn ); explicit_bzero(cookie_secrets, sizeof(cookie_secrets)); /*************************************************************/ nsd->cookie_secrets_source = COOKIE_SECRETS_FROM_FILE; return; /*************************************************************/ } explicit_bzero(cookie_secrets, sizeof(cookie_secrets)); generate_cookie_secrets: /* Calculate a new random secret */ srandom(getpid() ^ time(NULL)); for( j = 0; j < NSD_COOKIE_HISTORY_SIZE; j++) { #if defined(HAVE_SSL) if (!RAND_status() || !RAND_bytes(nsd->cookie_secrets[j].cookie_secret, NSD_COOKIE_SECRET_SIZE)) #endif for (i = 0; i < NSD_COOKIE_SECRET_SIZE; i++) nsd->cookie_secrets[j].cookie_secret[i] = random_generate(256); } nsd->cookie_count = 1; /*********************************************************************/ nsd->cookie_secrets_source = COOKIE_SECRETS_GENERATED; /*********************************************************************/ } nsd-4.12.0/udb.h0000644000175000017500000006270215002373054012727 0ustar mozziemozzie/* udb.h - u(micro) data base, stores data and index information in mmap file. * By W.C.A. Wijngaards * Copyright 2010, NLnet Labs. * BSD, see LICENSE. */ #ifndef UDB_H #define UDB_H #include /** * The micro data base UDB. * * File data.udb is mmapped and used to lookup and edit. * it contains a header with space-allocation-info, and a reference to the * base information, an object that is the entry point for the file. * Then it contains a lot of data and index objects. * * The space allocator is 'buddy system', 1megareas, larger get own area. * So worst case is 2xdata filesize (+header). Growth semi-linear. * Chunks have size and type (for recovery). Call to reserve space. * Call to 'realloc-in-place', if space permits. * * Usually you want a record-type and its indexes (sorted) to be stored in * the file. This is a table (named by string). The record is opaque * data. * * To be able to use pointers in the mmapped file, there is conversion of * relative-pointers(to file base) to system-pointers. * * If an item is moved its internal pointers need to be recalculated. * Thus a recordtype (that has internal pointers) must provide a routine. * Structures that are 'on-disk', are denoted with _d. Except rel_ptr which * is also on-disk. * * About 64-bit trouble. The pointer-size which which the application is * compiled determines the file layout, because this makes it perform well * in a mmap. It could in theory be converted if you really wanted to. * Nonpointer data is best stored as a fixed bitsize (uint8, 16, 32, 64). */ typedef struct udb_base udb_base; typedef struct udb_alloc udb_alloc; /** these checks are very slow, disabled by default */ #if 0 /** perform extra checks (when --enable-checking is used) */ #ifndef NDEBUG #define UDB_CHECK 1 #endif #endif /** pointers are stored like this */ typedef uint64_t udb_void; /** convert relptr to usable pointer */ #define UDB_REL(base, relptr) ((void*)((char*)(base) + (relptr))) /** from system pointer to relative pointer */ #define UDB_SYSTOREL(base, ptr) ((udb_void)((char*)(ptr) - (char*)(base))) /** MAX 2**x exponent of alloced chunks, for 1Mbytes. The smallest * chunk is 16bytes (8preamble+8data), so 0-3 is unused. */ #define UDB_ALLOC_CHUNKS_MAX 20 /** size of areas that are subdivided */ #define UDB_ALLOC_CHUNK_SIZE ((uint64_t)1<= amount. */ int udb_exp_size(uint64_t amount); /** * Utility for alloc, what is the size that the current offset supports * as a maximum 2**x chunk. * Does not work for offset = 0 (result is infinite). * @param offset: the offset into the memory region. * @return maximum exponent where 2**x is fits the offset, thus * offset % (2**x) == 0 and x cannot be larger. */ int udb_exp_offset(uint64_t offset); /** * Convert pointer to the data part to a pointer to the base of the chunk. * @param data: data part. * @return pointer to the base of the chunk. */ udb_void chunk_from_dataptr_ext(udb_void data); /** * Create empty UDB allocate structure to write to disk to initialize file. * @param a: allocation structure to initialize. system pointer. */ void udb_alloc_init_new(udb_alloc_d* a); /** * Create new udb allocator, with specific data on disk * @param udb: the udb. * @param disk: disk data. * @return udb allocator or NULL on (malloc) failure. */ udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk); /** * Free the udb allocator from memory. * @param alloc: the udb space allocator. */ void udb_alloc_delete(udb_alloc* alloc); /** * Allocate space on the disk. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param sz: size you want to use. * @return relative pointer (or 0 on alloc failure). */ udb_void udb_alloc_space(udb_alloc* alloc, size_t sz); /** * Allocate space on disk, give already the data you want there. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param d: data you want there (system pointer). * @param sz: size you want to use. * @return relative pointer (or 0 on alloc failure). */ udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz); /** * free allocated space. It may shrink the file. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param r: relative pointer to data you want to free. * @param sz: the size of the data you stop using. * @return false if the free failed, it failed the close and mmap. */ int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz); /** * realloc an existing allocated space. It may grow the file. * This may involve closing and reopening the mmap. * It could also use the existing space where it is now. * @param alloc: the udb space allocator. * @param r: relative pointer to data you want to realloc. * if 0 then this is alloc_space(), and osz is ignored. * @param osz: the old size of the data. * @param sz: the size of the data you want to get. * if this is 0 then a free() is done, but please do it directly, * as you then get a returnvalue (file errors). * @return relative pointer (0 on alloc failure, same if not moved). */ udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz, size_t sz); /** * Prepare for a lot of new entries. Grow space for that. * This can involve closing and reopening the mmap. * This space (if large) is going to be released on next free() or close(). * @param alloc: the udb space allocator. * @param sz: size of the entries. * @param num: number of entries. * @return false on failure to grow or re-mmap. */ int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num); /** * attempt to compact the data and move free space to the end * can shrink the db, which calls sync on the db (for portability). * @param udb: the udb base. * @return 0 on failure (to remap the (possibly) changed udb base). */ int udb_compact(udb_base* udb); /** * set the udb to inhibit or uninhibit compaction. Does not perform * the compaction itself if enabled, for that call udb_compact. * @param udb: the udb base * @param inhibit: 0 or 1. */ void udb_compact_inhibited(udb_base* udb, int inhibit); /** * Set the alloc type for a newly alloced piece of data * @param alloc: the udb space allocator. * @param r: relativeptr to the data. * @param tp: the type of that block. */ void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp); /** * See if a pointer could be valid (it points within valid space), * for the given type side. For debug checks. * @param udb: the udb * @param to: the ptr (offset). * @param destsize: the size_of of the destination of the pointer. * @return true if it points to a valid region. */ int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize); /** * See if a pointer is valid (it points to a chunk). For debug checks. * @param udb: the udb. * @param to: the ptr (offset). * @return true if it points to the start of a chunks data region. */ int udb_valid_dataptr(udb_base* udb, udb_void to); /** * See if a pointer is on the relptrlist for dataptr. For debug checks. * @param udb: the udb. * @param rptr: the rel_ptr (offset). * @param to: dataptr of the chunk on which ptrlist the rptr is searched. * @return true if rptr is valid and on the ptrlist. */ int udb_valid_rptr(udb_base* udb, udb_void rptr, udb_void to); /*** UDB_REL_PTR ***/ /** * Init a new UDB rel ptr at NULL. * @param ptr: sysptr, becomes inited. */ void udb_rel_ptr_init(udb_rel_ptr* ptr); /** * Unlink a UDB rel ptr. * @param base: the udb base * @param ptr: sysptr, unlinked */ void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr); /** * Link a UDB rel ptr to a new chunk * @param base: the udb base * @param ptr: sysptr, linked to new value. * @param to: the data to point to (relative ptr). */ void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to); /** * Change rel ptr to a new value (point to another record) * @param base: the udb base * @param ptr: sysptr, points to new value. * @param to: the data to point to (relative ptr). */ void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to); /** * A chunk has moved and now edit all the relptrs in list to fix them up * @param base: the udb base * @param list: start of the ptr list * @param to: where the chunk has moved to relptr to its userdata. */ void udb_rel_ptr_edit(void* base, udb_void list, udb_void to); /** * Get system pointer. Assumes there is a variable named 'base' * that points to the udb base. * @param ptr: the relative pointer (a sysptr to it). * @return void* to the data. */ #define UDB_SYSPTR(ptr) UDB_REL(base, (ptr)->data) /** get sys ptr for char* string */ #define UDB_CHAR(ptr) ((char*)UDB_REL(base, ptr)) /** get sys ptr for udb_rel_ptr */ #define UDB_REL_PTR(ptr) ((udb_rel_ptr*)UDB_REL(base, ptr)) /** get sys ptr for udb_glob_d */ #define UDB_GLOB(ptr) ((udb_glob_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_chunk_d */ #define UDB_CHUNK(ptr) ((udb_chunk_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_free_chunk_d */ #define UDB_FREE_CHUNK(ptr) ((udb_free_chunk_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_xl_chunk_d */ #define UDB_XL_CHUNK(ptr) ((udb_xl_chunk_d*)UDB_REL(base, ptr)) /* udb_ptr */ /** * Initialize an udb ptr. Set to NULL. (and thus not linked can be deleted). * You MUST set it to 0 before you stop using the ptr. * @param ptr: the ptr to initialise (caller has allocated it). * @param udb: the udb base to link it to. */ void udb_ptr_init(udb_ptr* ptr, udb_base* udb); /** * Set udp ptr to a new value. If set to NULL you can delete it. * @param ptr: the ptr. * @param udb: the udb base to link up with that data segment's administration. * @param newval: new value to point to (udb_void relative file offset to data). */ void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval); /** dereference udb_ptr */ #define UDB_PTR(ptr) (UDB_REL(*((ptr)->base), (ptr)->data)) /** * Ease of use udb ptr, allocate space and return ptr to it * You MUST udb_ptr_set it to 0 before you stop using the ptr. * @param base: udb base to use. * @param ptr: ptr is overwritten, can be uninitialised. * @param type: type of the allocation. * You need a special type if the block contains udb_rel_ptr's. * You can use udb_type_data for plain data. * @param sz: amount to allocate. * @return 0 on alloc failure. */ int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type, size_t sz); /** * Ease of use udb ptr, free space and set ptr to NULL (to it can be deleted). * The space is freed on disk. * @param ptr: the ptr. * @param udb: udb base. * @param sz: the size of the data you stop using. */ void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz); /** * Get pointer to the data of the ptr. or use a macro to cast UDB_PTR to * the type of your structure(.._d) */ static inline uint8_t* udb_ptr_data(udb_ptr* ptr) { return (uint8_t*)UDB_PTR(ptr); } /** * See if udb ptr is null */ static inline int udb_ptr_is_null(udb_ptr* ptr) { return (ptr->data == 0); } /** * Get the type of a udb_ptr chunk. * @param ptr: udb pointer * @return type of chunk */ udb_chunk_type udb_ptr_get_type(udb_ptr* ptr); /** Ease of use, create new pointer to destination relptr * You MUST udb_ptr_set it to 0 before you stop using the ptr. */ static inline void udb_ptr_new(udb_ptr* ptr, udb_base* udb, udb_rel_ptr* d) { udb_ptr_init(ptr, udb); udb_ptr_set(ptr, udb, d->data); } /** Ease of use. Stop using this ptr */ static inline void udb_ptr_unlink(udb_ptr* ptr, udb_base* udb) { if(ptr->data) udb_base_unlink_ptr(udb, ptr); } /* Ease of use. Assign rptr from rptr */ static inline void udb_rptr_set_rptr(udb_rel_ptr* dest, udb_base* udb, udb_rel_ptr* p) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } if(p->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, p), p->data)); } #endif udb_rel_ptr_set(udb->base, dest, p->data); } /* Ease of use. Assign rptr from ptr */ static inline void udb_rptr_set_ptr(udb_rel_ptr* dest, udb_base* udb, udb_ptr* p) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } if(p->data) { assert(udb_valid_dataptr(udb, p->data)); } #endif udb_rel_ptr_set(udb->base, dest, p->data); } /* Ease of use. Assign ptr from rptr */ static inline void udb_ptr_set_rptr(udb_ptr* dest, udb_base* udb, udb_rel_ptr* p) { #ifdef UDB_CHECK if(p->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, p), p->data)); } #endif udb_ptr_set(dest, udb, p->data); } /* Ease of use. Assign ptr from ptr */ static inline void udb_ptr_set_ptr(udb_ptr* dest, udb_base* udb, udb_ptr* p) { udb_ptr_set(dest, udb, p->data); } /* Ease of use, zero rptr. You use this to zero an existing pointer. * A new rptr should be rel_ptr_init-ed before it is taken into use. */ static inline void udb_rptr_zero(udb_rel_ptr* dest, udb_base* udb) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } #endif udb_rel_ptr_set(udb->base, dest, 0); } /* Ease of use, zero ptr */ static inline void udb_ptr_zero(udb_ptr* dest, udb_base* udb) { udb_ptr_set(dest, udb, 0); } /** ease of use, delete memory pointed at by relptr */ static inline void udb_rel_ptr_free_space(udb_rel_ptr* ptr, udb_base* udb, size_t sz) { udb_void d = ptr->data; #ifdef UDB_CHECK if(d) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, ptr), d)); } #endif udb_rel_ptr_set(udb->base, ptr, 0); udb_alloc_free(udb->alloc, d, sz); } #endif /* UDB_H */ nsd-4.12.0/udb.c0000644000175000017500000016447115002373054012730 0ustar mozziemozzie/* udb.c - u(micro) data base. * By W.C.A. Wijngaards * Copyright 2010, NLnet Labs. * BSD, see LICENSE. */ #include "config.h" #include "udb.h" #include #include #include #include #include #include "lookup3.h" #include "util.h" /* mmap and friends */ #include #include #include #include /* for systems without, portable definition, failed-1 and async is a flag */ #ifndef MAP_FAILED #define MAP_FAILED ((void*)-1) #endif #ifndef MS_SYNC #define MS_SYNC 0 #endif /** move and fixup xl segment */ static void move_xl_segment(void* base, udb_base* udb, udb_void xl, udb_void n, uint64_t sz, uint64_t startseg); /** attempt to compact the data and move free space to the end */ static int udb_alloc_compact(void* base, udb_alloc* alloc); /** convert pointer to the data part to a pointer to the base of the chunk */ static udb_void chunk_from_dataptr(udb_void data) { /* we use that sizeof(udb_chunk_d) != sizeof(udb_xl_chunk_d) and * that xl_chunk_d is aligned on x**1024 boundaries. */ udb_void xl = data - sizeof(udb_xl_chunk_d); if( (xl & (UDB_ALLOC_CHUNK_SIZE-1)) == 0) return xl; return data - sizeof(udb_chunk_d); } udb_void chunk_from_dataptr_ext(udb_void data) { return chunk_from_dataptr(data); } #ifndef NDEBUG /** read last octet from a chunk */ static uint8_t chunk_get_last(void* base, udb_void chunk, int exp) { return *((uint8_t*)UDB_REL(base, chunk+(1<= 0 && exp <= 63); *((uint8_t*)UDB_REL(base, chunk+((uint64_t)1<fname = strdup(fname); if(!udb->fname) { log_msg(LOG_ERR, "out of memory"); free(udb); close(fd); return NULL; } udb->walkfunc = walkfunc; udb->walkarg = arg; udb->fd = fd; udb->ram_size = 1024; udb->ram_mask = (int)udb->ram_size - 1; udb->ram_hash = (udb_ptr**)xalloc_array_zero(sizeof(udb_ptr*), udb->ram_size); if(!udb->ram_hash) { free(udb->fname); free(udb); log_msg(LOG_ERR, "out of memory"); close(fd); return NULL; } /* read magic */ if((r=read(fd, &m, sizeof(m))) == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); goto fail; } else if(r != (ssize_t)sizeof(m)) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } /* TODO : what if bigendian and littleendian file, see magic */ if(m != UDB_MAGIC) { log_msg(LOG_ERR, "%s: wrong type of file", fname); goto fail; } /* read header */ if((r=read(fd, &g, sizeof(g))) == -1) { log_msg(LOG_ERR, "%s: %s\n", fname, strerror(errno)); goto fail; } else if(r != (ssize_t)sizeof(g)) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } if(g.version != 0) { log_msg(LOG_ERR, "%s: unknown file version %d", fname, (int)g.version); goto fail; } if(g.hsize < UDB_HEADER_SIZE) { log_msg(LOG_ERR, "%s: header size too small %d", fname, (int)g.hsize); goto fail; } if(g.hsize > UDB_HEADER_SIZE) { log_msg(LOG_WARNING, "%s: header size too large %d", fname, (int)g.hsize); goto fail; } if(g.clean_close != 1) { log_msg(LOG_WARNING, "%s: not cleanly closed %d", fname, (int)g.clean_close); goto fail; } if(g.dirty_alloc != 0) { log_msg(LOG_WARNING, "%s: not cleanly closed (alloc:%d)", fname, (int)g.dirty_alloc); goto fail; } /* check file size correctly written, for 4.0.2 nsd.db failure */ fsz = (uint64_t)lseek(fd, (off_t)0, SEEK_END); (void)lseek(fd, (off_t)0, SEEK_SET); if(g.fsize != fsz) { log_msg(LOG_WARNING, "%s: file size %llu but mmap header " "has size %llu", fname, (unsigned long long)fsz, (unsigned long long)g.fsize); goto fail; } /* mmap it */ if(g.fsize < UDB_HEADER_SIZE || g.fsize < g.hsize) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } if(g.fsize > (uint64_t)400*1024*1024*1024*1024) /* 400 Tb */ { log_msg(LOG_WARNING, "%s: file size too large %llu", fname, (unsigned long long)g.fsize); goto fail; } udb->base_size = (size_t)g.fsize; #ifdef HAVE_MMAP /* note the size_t casts must be there for portability, on some * systems the layout of memory is otherwise broken. */ udb->base = mmap(NULL, (size_t)udb->base_size, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); #else udb->base = MAP_FAILED; errno = ENOSYS; #endif if(udb->base == MAP_FAILED) { udb->base = NULL; log_msg(LOG_ERR, "mmap(size %u) error: %s", (unsigned)udb->base_size, strerror(errno)); fail: close(fd); free(udb->fname); free(udb->ram_hash); free(udb); return NULL; } /* init completion */ udb->glob_data = (udb_glob_d*)((char*)udb->base+sizeof(uint64_t)); r = 0; /* cannot be dirty because that is goto fail above */ if(udb->glob_data->dirty_alloc != udb_dirty_clean) r = 1; udb->alloc = udb_alloc_create(udb, (udb_alloc_d*)( (char*)udb->glob_data+sizeof(*udb->glob_data))); if(!udb->alloc) { log_msg(LOG_ERR, "out of memory"); udb_base_free(udb); return NULL; } if(r) { /* and compact now, or resume compacting */ udb_alloc_compact(udb, udb->alloc); udb_base_sync(udb, 1); } udb->glob_data->clean_close = 0; return udb; } udb_base* udb_base_create_read(const char* fname, udb_walk_relptr_func walkfunc, void* arg) { int fd = open(fname, O_RDWR); if(fd == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); return NULL; } return udb_base_create_fd(fname, fd, walkfunc, arg); } /** init new udb_global structure */ static void udb_glob_init_new(udb_glob_d* g) { memset(g, 0, sizeof(*g)); g->hsize = UDB_HEADER_SIZE; g->fsize = UDB_HEADER_SIZE; } /** write data to file and check result */ static int write_fdata(const char* fname, int fd, void* data, size_t len) { ssize_t w; if((w=write(fd, data, len)) == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); close(fd); return 0; } else if(w != (ssize_t)len) { log_msg(LOG_ERR, "%s: short write (disk full?)", fname); close(fd); return 0; } return 1; } udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc, void* arg) { uint64_t m; udb_glob_d g; udb_alloc_d a; uint64_t endsize = UDB_HEADER_SIZE; uint64_t endexp = 0; int fd = open(fname, O_CREAT|O_RDWR, 0600); if(fd == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); return NULL; } m = UDB_MAGIC; udb_glob_init_new(&g); udb_alloc_init_new(&a); g.clean_close = 1; /* write new data to file (closes fd on error) */ if(!write_fdata(fname, fd, &m, sizeof(m))) return NULL; if(!write_fdata(fname, fd, &g, sizeof(g))) return NULL; if(!write_fdata(fname, fd, &a, sizeof(a))) return NULL; if(!write_fdata(fname, fd, &endsize, sizeof(endsize))) return NULL; if(!write_fdata(fname, fd, &endexp, sizeof(endexp))) return NULL; /* rewind to start */ if(lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { log_msg(LOG_ERR, "%s: lseek %s", fname, strerror(errno)); close(fd); return NULL; } /* truncate to the right size */ if(ftruncate(fd, (off_t)g.fsize) < 0) { log_msg(LOG_ERR, "%s: ftruncate(%d): %s", fname, (int)g.fsize, strerror(errno)); close(fd); return NULL; } return udb_base_create_fd(fname, fd, walkfunc, arg); } /** shrink the udb base if it has unused space at the end */ static void udb_base_shrink(udb_base* udb, uint64_t nsize) { udb->glob_data->dirty_alloc = udb_dirty_fsize; udb->glob_data->fsize = nsize; /* sync, does not *seem* to be required on Linux, but it is certainly required on OpenBSD. Otherwise changed data is lost. */ #ifdef HAVE_MMAP msync(udb->base, udb->base_size, MS_ASYNC); #endif if(ftruncate(udb->fd, (off_t)nsize) != 0) { log_msg(LOG_ERR, "%s: ftruncate(%u) %s", udb->fname, (unsigned)nsize, strerror(errno)); } udb->glob_data->dirty_alloc = udb_dirty_clean; } void udb_base_close(udb_base* udb) { if(!udb) return; if(udb->fd != -1 && udb->base && udb->alloc) { uint64_t nsize = udb->alloc->disk->nextgrow; if(nsize < udb->base_size) udb_base_shrink(udb, nsize); } if(udb->fd != -1) { udb->glob_data->clean_close = 1; close(udb->fd); udb->fd = -1; } if(udb->base) { #ifdef HAVE_MMAP if(munmap(udb->base, udb->base_size) == -1) { log_msg(LOG_ERR, "munmap: %s", strerror(errno)); } #endif udb->base = NULL; } } void udb_base_free(udb_base* udb) { if(!udb) return; udb_base_close(udb); udb_alloc_delete(udb->alloc); free(udb->ram_hash); free(udb->fname); free(udb); } void udb_base_free_keep_mmap(udb_base* udb) { if(!udb) return; if(udb->fd != -1) { close(udb->fd); udb->fd = -1; } udb->base = NULL; udb_alloc_delete(udb->alloc); free(udb->ram_hash); free(udb->fname); free(udb); } void udb_base_sync(udb_base* udb, int wait) { if(!udb) return; #ifdef HAVE_MMAP if(msync(udb->base, udb->base_size, wait?MS_SYNC:MS_ASYNC) != 0) { log_msg(LOG_ERR, "msync(%s) error %s", udb->fname, strerror(errno)); } #else (void)wait; #endif } /** hash a chunk pointer */ static uint32_t chunk_hash_ptr(udb_void p) { /* put p into an array of uint32 */ uint32_t h[sizeof(p)/sizeof(uint32_t)]; memcpy(&h, &p, sizeof(h)); return hashword(h, sizeof(p)/sizeof(uint32_t), 0x8763); } /** check that the given pointer is on the bucket for the given offset */ int udb_ptr_is_on_bucket(udb_base* udb, udb_ptr* ptr, udb_void to) { uint32_t i = chunk_hash_ptr(to) & udb->ram_mask; udb_ptr* p; assert((size_t)i < udb->ram_size); for(p = udb->ram_hash[i]; p; p=p->next) { if(p == ptr) return 1; } return 0; } /** grow the ram array */ static void grow_ram_hash(udb_base* udb, udb_ptr** newhash) { size_t i; size_t osize= udb->ram_size; udb_ptr* p, *np; udb_ptr** oldhash = udb->ram_hash; udb->ram_size *= 2; udb->ram_mask <<= 1; udb->ram_mask |= 1; udb->ram_hash = newhash; /* have to link in every element in the old list into the new list*/ for(i=0; inext; /* link into newhash */ p->prev=NULL; p->next=newhash[chunk_hash_ptr(p->data)&udb->ram_mask]; if(p->next) p->next->prev = p; /* go to next element of oldhash */ p = np; } } free(oldhash); } void udb_base_link_ptr(udb_base* udb, udb_ptr* ptr) { uint32_t i; #ifdef UDB_CHECK assert(udb_valid_dataptr(udb, ptr->data)); /* must be to whole chunk*/ #endif udb->ram_num++; if(udb->ram_num == udb->ram_size && udb->ram_size<(size_t)0x7fffffff) { /* grow the array, if allocation succeeds */ udb_ptr** newram = (udb_ptr**)xalloc_array_zero( sizeof(udb_ptr*), udb->ram_size*2); if(newram) { grow_ram_hash(udb, newram); } } i = chunk_hash_ptr(ptr->data) & udb->ram_mask; assert((size_t)i < udb->ram_size); ptr->prev = NULL; ptr->next = udb->ram_hash[i]; udb->ram_hash[i] = ptr; if(ptr->next) ptr->next->prev = ptr; } void udb_base_unlink_ptr(udb_base* udb, udb_ptr* ptr) { assert(ptr->data); #ifdef UDB_CHECK assert(udb_valid_dataptr(udb, ptr->data)); /* ptr must be inited */ assert(udb_ptr_is_on_bucket(udb, ptr, ptr->data)); #endif udb->ram_num--; if(ptr->next) ptr->next->prev = ptr->prev; if(ptr->prev) ptr->prev->next = ptr->next; else { uint32_t i = chunk_hash_ptr(ptr->data) & udb->ram_mask; assert((size_t)i < udb->ram_size); udb->ram_hash[i] = ptr->next; } } /** change a set of ram ptrs to a new value */ static void udb_base_ram_ptr_edit(udb_base* udb, udb_void old, udb_void newd) { uint32_t io = chunk_hash_ptr(old) & udb->ram_mask; udb_ptr* p, *np; /* edit them and move them into the new position */ p = udb->ram_hash[io]; while(p) { np = p->next; if(p->data == old) { udb_base_unlink_ptr(udb, p); p->data = newd; udb_base_link_ptr(udb, p); } p = np; } } udb_rel_ptr* udb_base_get_userdata(udb_base* udb) { return &udb->glob_data->user_global; } void udb_base_set_userdata(udb_base* udb, udb_void user) { #ifdef UDB_CHECK if(user) { assert(udb_valid_dataptr(udb, user)); } #endif udb_rel_ptr_set(udb->base, &udb->glob_data->user_global, user); } void udb_base_set_userflags(udb_base* udb, uint8_t v) { udb->glob_data->userflags = v; } uint8_t udb_base_get_userflags(udb_base* udb) { return udb->glob_data->userflags; } /** re-mmap the udb to specified size */ static void* udb_base_remap(udb_base* udb, udb_alloc* alloc, uint64_t nsize) { #ifdef HAVE_MMAP void* nb; /* for use with valgrind, do not use mremap, but the other version */ #ifdef MREMAP_MAYMOVE nb = mremap(udb->base, udb->base_size, nsize, MREMAP_MAYMOVE); if(nb == MAP_FAILED) { log_msg(LOG_ERR, "mremap(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); return 0; } #else /* !HAVE MREMAP */ /* use munmap-mmap to simulate mremap */ if(munmap(udb->base, udb->base_size) != 0) { log_msg(LOG_ERR, "munmap(%s) error %s", udb->fname, strerror(errno)); } /* provide hint for new location */ /* note the size_t casts must be there for portability, on some * systems the layout of memory is otherwise broken. */ nb = mmap(udb->base, (size_t)nsize, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); /* retry the mmap without basept in case of ENOMEM (FreeBSD8), * the kernel can then try to mmap it at a different location * where more memory is available */ if(nb == MAP_FAILED && errno == ENOMEM) { nb = mmap(NULL, (size_t)nsize, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); } if(nb == MAP_FAILED) { log_msg(LOG_ERR, "mmap(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); udb->base = NULL; return 0; } #endif /* HAVE MREMAP */ if(nb != udb->base) { /* fix up realpointers in udb and alloc */ /* but mremap may have been nice and not move the base */ udb->base = nb; udb->glob_data = (udb_glob_d*)((char*)nb+sizeof(uint64_t)); /* use passed alloc pointer because the udb->alloc may not * be initialized yet */ alloc->disk = (udb_alloc_d*)((char*)udb->glob_data +sizeof(*udb->glob_data)); } udb->base_size = nsize; return nb; #else /* HAVE_MMAP */ (void)udb; (void)alloc; (void)nsize; return NULL; #endif /* HAVE_MMAP */ } void udb_base_remap_process(udb_base* udb) { /* assume that fsize is still accessible */ udb_base_remap(udb, udb->alloc, udb->glob_data->fsize); } /** grow file to specified size and re-mmap, return new base */ static void* udb_base_grow_and_remap(udb_base* udb, uint64_t nsize) { /* grow file by writing a single zero at that spot, the * rest is filled in with zeroes. */ uint8_t z = 0; ssize_t w; assert(nsize > 0); udb->glob_data->dirty_alloc = udb_dirty_fsize; #ifdef HAVE_PWRITE if((w=pwrite(udb->fd, &z, sizeof(z), (off_t)(nsize-1))) == -1) { #else if(lseek(udb->fd, (off_t)(nsize-1), SEEK_SET) == -1) { log_msg(LOG_ERR, "fseek %s: %s", udb->fname, strerror(errno)); return 0; } if((w=write(udb->fd, &z, sizeof(z))) == -1) { #endif log_msg(LOG_ERR, "grow(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); return 0; } else if(w != (ssize_t)sizeof(z)) { log_msg(LOG_ERR, "grow(%s, size %u) failed (disk full?)", udb->fname, (unsigned)nsize); return 0; } udb->glob_data->fsize = nsize; udb->glob_data->dirty_alloc = udb_dirty_clean; return udb_base_remap(udb, udb->alloc, nsize); } int udb_exp_size(uint64_t a) { /* find enclosing value such that 2**x >= a */ int x = 0; uint64_t i = a; assert(a != 0); i --; /* could optimise this with uint8* access, depends on endianness */ /* first whole bytes */ while( (i&(~(uint64_t)0xff)) ) { i >>= 8; x += 8; } /* now details */ while(i) { i >>= 1; x ++; } assert( x>=0 && x<=63); assert( ((uint64_t)1<= a); assert( x==0 || /* <>1) < a); return x; } int udb_exp_offset(uint64_t o) { /* this means measuring the number of 0 bits on the right */ /* so, if exp zero bits then (o&(2**x-1))==0 */ int x = 0; uint64_t i = o; assert(o != 0); /* first whole bytes */ while( (i&(uint64_t)0xff) == 0) { i >>= 8; x += 8; } /* now details */ while( (i&(uint64_t)0x1) == 0) { i >>= 1; x ++; } assert( o % ((uint64_t)1<nextgrow = UDB_HEADER_SIZE; } /** fsck the file size, false if failed and file is useless */ static int fsck_fsize(udb_base* udb, udb_alloc* alloc) { off_t realsize; log_msg(LOG_WARNING, "udb-fsck %s: file size wrong", udb->fname); realsize = lseek(udb->fd, (off_t)0, SEEK_END); if(realsize == (off_t)-1) { log_msg(LOG_ERR, "lseek(%s): %s", udb->fname, strerror(errno)); return 0; } udb->glob_data->fsize = (uint64_t)realsize; if(!udb_base_remap(udb, alloc, (uint64_t)realsize)) return 0; udb->glob_data->dirty_alloc = udb_dirty_clean; log_msg(LOG_WARNING, "udb-fsck %s: file size fixed (sync)", udb->fname); udb_base_sync(udb, 1); return 1; } /** regenerate freelist add a new free chunk, return next todo */ static udb_void regen_free(void* base, udb_void c, int exp, udb_alloc_d* regen) { udb_free_chunk_d* cp = UDB_FREE_CHUNK(c); uint64_t esz = (uint64_t)1< UDB_ALLOC_CHUNKS_MAX) { return 0; } cp->type = udb_chunk_type_free; cp->flags = 0; chunk_set_last(base, c, exp, (uint8_t)exp); cp->prev = 0; cp->next = regen->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(cp->next) UDB_FREE_CHUNK(cp->next)->prev = c; regen->stat_free += esz; return c + esz; } /** regenerate xl chunk, return next todo */ static udb_void regen_xl(void* base, udb_void c, udb_alloc_d* regen) { udb_xl_chunk_d* cp = UDB_XL_CHUNK(c); uint64_t xlsz = cp->size; if( (xlsz&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) { return 0; } if( (c&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) { return 0; } /* fixup end-size and end-expmarker */ regen->stat_alloc += xlsz; return c + xlsz; } /** regenerate data chunk, return next todo */ static udb_void regen_data(void* base, udb_void c, int exp, udb_alloc_d* regen) { uint64_t esz = (uint64_t)1< UDB_ALLOC_CHUNKS_MAX) { return 0; } chunk_set_last(base, c, exp, (uint8_t)exp); regen->stat_alloc += esz; return c + esz; } /** regenerate a relptr structure inside a data segment */ static void regen_relptr_func(void* base, udb_rel_ptr* rp, void* arg) { udb_void* a = (udb_void*)arg; /* ignore 0 pointers */ if(!rp->data) return; /* edit relptrs that point to oldmoved to point to newmoved. */ if(rp->data == a[0]) rp->data = a[1]; /* regenerate relptr lists, add this item to the relptr list for * the data that it points to */ udb_rel_ptr_link(base, rp, rp->data); } /** regenerate the relptrs store in this data segment */ static void regen_its_ptrs(void* base, udb_base* udb, udb_chunk_d* atp, void* data, uint64_t dsz, udb_void rb_old, udb_void rb_new) { udb_void arg[2]; arg[0] = rb_old; arg[1] = rb_new; /* walk through the structs here and put them on their respective * relptr lists */ (*udb->walkfunc)(base, udb->walkarg, atp->type, data, dsz, ®en_relptr_func, arg); } /** regenerate relptrlists in the file */ static void regen_ptrlist(void* base, udb_base* udb, udb_alloc* alloc, udb_void rb_old, udb_void rb_new) { udb_void at = alloc->udb->glob_data->hsize; /* clear all ptrlist start pointers in the file. */ while(at < alloc->disk->nextgrow) { int exp = (int)UDB_CHUNK(at)->exp; udb_chunk_type tp = (udb_chunk_type)UDB_CHUNK(at)->type; if(exp == UDB_EXP_XL) { UDB_XL_CHUNK(at)->ptrlist = 0; at += UDB_XL_CHUNK(at)->size; } else if(tp == udb_chunk_type_free) { at += (uint64_t)1<ptrlist = 0; at += (uint64_t)1<udb->glob_data->hsize; while(at < alloc->disk->nextgrow) { udb_chunk_d* atp = UDB_CHUNK(at); int exp = (int)atp->exp; udb_chunk_type tp = (udb_chunk_type)atp->type; uint64_t sz = ((exp == UDB_EXP_XL)?UDB_XL_CHUNK(at)->size: (uint64_t)1<= UDB_ALLOC_CHUNK_SIZE*/ assert(s >= UDB_ALLOC_CHUNK_SIZE); while(q >= s) { UDB_CHUNK(q)->exp = UDB_ALLOC_CHUNKS_MAX; UDB_CHUNK(q)->type = udb_chunk_type_free; q -= UDB_ALLOC_CHUNK_SIZE; } } /** fsck rollback or rollforward XL move results */ static int fsck_rb_xl(void* base, udb_base* udb, udb_void rb_old, udb_void rb_new, uint64_t rb_size, uint64_t rb_seg) { if(rb_old <= rb_new) return 0; /* XL move one way */ if( (rb_size&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if( (rb_old&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if( (rb_new&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if(rb_new + rb_size <= rb_old) { /* not overlapping: resume copy */ memcpy(UDB_CHUNK(rb_new), UDB_CHUNK(rb_old), rb_size); /* and free up old piece(s) */ rb_mark_free_segs(base, rb_old, rb_size); } else { /* overlapping, see what segment we stopped at * and continue there. */ move_xl_segment(base, udb, rb_old, rb_new, rb_size, rb_seg); /* free up old piece(s); from the end of the moved segment, * until the end of the old segment */ rb_mark_free_segs(base, rb_new+rb_size, (rb_old+rb_size)- (rb_new+rb_size)); } /* do not call fix_ptrs, regenptrs does the job */ return 1; } /** fsck rollback or rollforward move results */ static int fsck_rb(void* base, udb_void rb_old, udb_void rb_new, uint64_t rb_size, udb_void* make_free) { if( (rb_size&(rb_size-1)) != 0) return 0; /* not powerof2 */ if( (rb_old&(rb_size-1)) != 0) return 0; /* not aligned */ if( (rb_new&(rb_size-1)) != 0) return 0; /* not aligned */ /* resume copy */ memcpy(UDB_CHUNK(rb_new), UDB_CHUNK(rb_old), rb_size); /* do not call fix_ptrs, regenptrs does the job */ /* make sure udb_old is freed */ *make_free = rb_old; return 1; } /** fsck the file and salvage, false if failed and file is useless */ static int fsck_file(udb_base* udb, udb_alloc* alloc, int moved) { void* base = udb->base; udb_alloc_d regen; udb_void at = udb->glob_data->hsize; udb_void rb_old = udb->glob_data->rb_old; udb_void rb_new = udb->glob_data->rb_new; udb_void rb_seg = udb->glob_data->rb_seg; udb_void make_free = 0; uint64_t rb_size = udb->glob_data->rb_size; log_msg(LOG_WARNING, "udb-fsck %s: salvaging", udb->fname); /* walk through the file, use the exp values to see what can be * salvaged */ if(moved && rb_old && rb_new && rb_size) { if(rb_old+rb_size <= alloc->disk->nextgrow && rb_new+rb_size <= alloc->disk->nextgrow) { /* we can use the move information to fix up the * duplicate element (or partially moved element) */ if(rb_size > 1024*1024) { /* XL chunk */ if(!fsck_rb_xl(base, udb, rb_old, rb_new, rb_size, rb_seg)) return 0; } else { if(!fsck_rb(base, rb_old, rb_new, rb_size, &make_free)) return 0; } } } /* rebuild freelists */ /* recalculate stats in alloc (except 'stat_data') */ /* possibly new end 'nextgrow' value */ memset(®en, 0, sizeof(regen)); regen.nextgrow = alloc->disk->nextgrow; while(at < regen.nextgrow) { /* figure out this chunk */ int exp = (int)UDB_CHUNK(at)->exp; udb_chunk_type tp = (udb_chunk_type)UDB_CHUNK(at)->type; /* consistency check possible here with end-exp */ if(tp == udb_chunk_type_free || at == make_free) { at = regen_free(base, at, exp, ®en); if(!at) return 0; } else if(exp == UDB_EXP_XL) { /* allocated data of XL size */ at = regen_xl(base, at, ®en); if(!at) return 0; } else if(exp >= UDB_ALLOC_CHUNK_MINEXP && exp <= UDB_ALLOC_CHUNKS_MAX) { /* allocated data */ at = regen_data(base, at, exp, ®en); if(!at) return 0; } else { /* garbage; this must be EOF then */ regen.nextgrow = at; break; } } *alloc->disk = regen; /* rebuild relptr lists */ regen_ptrlist(base, udb, alloc, rb_old, rb_new); log_msg(LOG_WARNING, "udb-fsck %s: salvaged successfully (sync)", udb->fname); udb->glob_data->rb_old = 0; udb->glob_data->rb_new = 0; udb->glob_data->rb_size = 0; udb->glob_data->dirty_alloc = udb_dirty_clean; udb_base_sync(udb, 1); return 1; } udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk) { udb_alloc* alloc = (udb_alloc*)xalloc_zero(sizeof(*alloc)); if(!alloc) return NULL; alloc->udb = udb; alloc->disk = disk; /* see if committed but uncompleted actions need to be done */ /* preserves the alloc state */ if(udb->glob_data->dirty_alloc != udb_dirty_clean) { if(udb->glob_data->dirty_alloc == udb_dirty_fsize) { if(fsck_fsize(udb, alloc)) return alloc; } else if(udb->glob_data->dirty_alloc == udb_dirty_fl) { if(fsck_file(udb, alloc, 0)) return alloc; } else if(udb->glob_data->dirty_alloc == udb_dirty_compact) { if(fsck_file(udb, alloc, 1)) return alloc; } log_msg(LOG_ERR, "error: file allocation dirty (%d)", (int)udb->glob_data->dirty_alloc); free(alloc); return NULL; } return alloc; } void udb_alloc_delete(udb_alloc* alloc) { if(!alloc) return; free(alloc); } /** unlink this element from its freelist */ static void udb_alloc_unlink_fl(void* base, udb_alloc* alloc, udb_void chunk, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(chunk); assert(chunk); /* chunk is a free chunk */ assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, chunk, exp) == (uint8_t)exp); /* and thus freelist not empty */ assert(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]); /* unlink */ if(fp->prev) UDB_FREE_CHUNK(fp->prev)->next = fp->next; else alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = fp->next; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = fp->prev; } /** pop first element off freelist, list may not be empty */ static udb_void udb_alloc_pop_fl(void* base, udb_alloc* alloc, int exp) { udb_void f = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, f, exp) == (uint8_t)exp); alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = fp->next; if(fp->next) { UDB_FREE_CHUNK(fp->next)->prev = 0; } return f; } /** push new element onto freelist */ static void udb_alloc_push_fl(void* base, udb_alloc* alloc, udb_void f, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); fp->exp = (uint8_t)exp; fp->type = udb_chunk_type_free; fp->flags = 0; fp->prev = 0; fp->next = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = f; chunk_set_last(base, f, exp, (uint8_t)exp); alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = f; } /** push new element onto freelist - do not initialize the elt */ static void udb_alloc_push_fl_noinit(void* base, udb_alloc* alloc, udb_void f, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, f, exp) == (uint8_t)exp); fp->prev = 0; fp->next = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = f; alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = f; } /** add free chunks at end until specified alignment occurs */ static void grow_align(void* base, udb_alloc* alloc, uint64_t esz) { while( (alloc->disk->nextgrow & (esz-1)) != 0) { /* the nextgrow is not a whole multiple of esz. */ /* grow a free chunk of max allowed size */ int fexp = udb_exp_offset(alloc->disk->nextgrow); uint64_t fsz = (uint64_t)1<disk->nextgrow; udb_void fn = alloc->disk->nextgrow+fsz; assert(fn <= alloc->udb->base_size); alloc->disk->stat_free += fsz; udb_alloc_push_fl(base, alloc, f, fexp); /* now increase nextgrow to commit that free chunk */ alloc->disk->nextgrow = fn; } } /** append chunks at end of memory space to get size exp, return dataptr */ static udb_void grow_chunks(void* base, udb_alloc* alloc, size_t sz, int exp) { uint64_t esz = (uint64_t)1<udb->glob_data->dirty_alloc = udb_dirty_fl; grow_align(base, alloc, esz); /* free chunks are grown, grow the one we want to use */ ret = alloc->disk->nextgrow; /* take a new alloced chunk into use */ UDB_CHUNK(ret)->exp = (uint8_t)exp; UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; UDB_CHUNK(ret)->type = udb_chunk_type_data; /* store last octet */ chunk_set_last(base, ret, exp, (uint8_t)exp); /* update stats */ alloc->disk->stat_alloc += esz; alloc->disk->stat_data += sz; /* now increase nextgrow to commit this newly allocated chunk */ alloc->disk->nextgrow += esz; assert(alloc->disk->nextgrow <= alloc->udb->base_size); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /** calculate how much space is necessary to grow for this exp */ static uint64_t grow_end_calc(udb_alloc* alloc, int exp) { uint64_t sz = (uint64_t)1<disk->nextgrow; uint64_t res; /* if nextgrow is 2**expness, no extra growth needed, only size */ if( (ng & (sz-1)) == 0) { /* sz-1 is like 0xfff, and checks if ng is whole 2**exp */ return ng+sz; /* must grow exactly 2**exp */ } /* grow until 2**expness and then we need 2**exp as well */ /* so, round ng down to whole sz (basically ng-ng%sz, or ng/sz*sz) * and then add the sz twice (go up to whole sz, and to allocate) */ res = (ng & ~(sz-1)) + 2*sz; return res; } /** see if we need to grow more than specified to enable sustained growth */ static uint64_t grow_extra_check(udb_alloc* alloc, uint64_t ge) { const uint64_t mb = 1024*1024; uint64_t bsz = alloc->udb->base_size; if(bsz <= mb) { /* below 1 Mb, double sizes for exponential growth */ /* takes about 15 times to grow to 1Mb */ if(ge < bsz*2) return bsz*2; } else { uint64_t gnow = ge - bsz; /* above 1Mb, grow at least 1 Mb, or 12.5% of current size, * in whole megabytes rounded up. */ uint64_t want = ((bsz / 8) & ~(mb-1)) + mb; if(gnow < want) return bsz + want; } return ge; } /** see if free space is enough to warrant shrink (while file is open) */ static int enough_free(udb_alloc* alloc) { if(alloc->udb->base_size <= 2*1024*1024) { /* below 1 Mb, grown by double size, (so up to 2 mb), * do not shrink unless we can 1/3 in size */ if(((size_t)alloc->disk->nextgrow)*3 <= alloc->udb->base_size) return 1; } else { /* grown 12.5%, shrink 25% if possible, at least one mb */ /* between 1mb and 4mb size, it shrinks by 1mb if possible */ uint64_t space = alloc->udb->base_size - alloc->disk->nextgrow; if(space >= 1024*1024 && (space*4 >= alloc->udb->base_size || alloc->udb->base_size < 4*1024*1024)) return 1; } return 0; } /** grow space for a chunk of 2**exp and return dataptr */ static udb_void udb_alloc_grow_space(void* base, udb_alloc* alloc, size_t sz, int exp) { /* commit the grow action * - the file grow only changes filesize, but not the nextgrow. * - taking space after nextgrow into use (as free space), * is like free-ing a chunk (one at a time). * - and the last chunk taken into use is like alloc. */ /* predict how much free space is needed for this */ uint64_t grow_end = grow_end_calc(alloc, exp); assert(alloc->udb->base_size >= alloc->disk->nextgrow); if(grow_end <= alloc->udb->base_size) { /* we can do this with the available space */ return grow_chunks(base, alloc, sz, exp); } /* we have to grow the file, re-mmap */ /* see if we need to grow a little more, to avoid endless grow * efforts on adding data */ grow_end = grow_extra_check(alloc, grow_end); if(!(base=udb_base_grow_and_remap(alloc->udb, grow_end))) { return 0; /* mmap or write failed (disk or mem full) */ } /* we have enough space now */ assert(grow_end <= alloc->udb->base_size); assert(alloc->udb->glob_data->fsize == alloc->udb->base_size); return grow_chunks(base, alloc, sz, exp); } /** take XL allocation into use at end of file, return dataptr */ static udb_void grow_xl(void* base, udb_alloc* alloc, uint64_t xlsz, uint64_t sz) { udb_void ret; udb_xl_chunk_d* p; alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; /* align growth to whole mbs */ grow_align(base, alloc, UDB_ALLOC_CHUNK_SIZE); /* grow XL segment */ ret = alloc->disk->nextgrow; p = UDB_XL_CHUNK(ret); p->exp = UDB_EXP_XL; p->size = xlsz; p->flags = 0; p->ptrlist = 0; p->type = udb_chunk_type_data; /* also put size and marker at end for compaction */ *((uint64_t*)(UDB_REL(base, ret+xlsz-sizeof(uint64_t)*2))) = xlsz; *((uint8_t*)(UDB_REL(base, ret+xlsz-1))) = UDB_EXP_XL; /* stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += xlsz; /* now increase the nextgrow to commit this xl chunk */ alloc->disk->nextgrow += xlsz; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_xl_chunk_d); /* data ptr */ } /** make space for XL allocation */ static udb_void udb_alloc_xl_space(void* base, udb_alloc* alloc, size_t sz) { /* allocate whole mbs of space, at end of space */ uint64_t asz = sz + sizeof(udb_xl_chunk_d) + sizeof(uint64_t)*2; uint64_t need=(asz+UDB_ALLOC_CHUNK_SIZE-1)&(~(UDB_ALLOC_CHUNK_SIZE-1)); uint64_t grow_end = grow_end_calc(alloc, UDB_ALLOC_CHUNKS_MAX) + need; assert(need >= asz); if(grow_end <= alloc->udb->base_size) { /* can do this in available space */ return grow_xl(base, alloc, need, sz); } /* have to grow file and re-mmap */ grow_end = grow_extra_check(alloc, grow_end); if(!(base=udb_base_grow_and_remap(alloc->udb, grow_end))) { return 0; /* mmap or write failed (disk or mem full) */ } /* we have enough space now */ assert(grow_end <= alloc->udb->base_size); assert(alloc->udb->glob_data->fsize == alloc->udb->base_size); return grow_xl(base, alloc, need, sz); } /** divide big(2**e2) into pieces so 2**exp fits */ static udb_void udb_alloc_subdivide(void* base, udb_alloc* alloc, udb_void big, int e2, int exp) { int e = e2; uint64_t sz = (uint64_t)1< exp); /* so the returned piece to use is the first piece, * offload the later half until it fits */ do { sz >>= 1; /* divide size of big by two */ e--; /* that means its exp is one smaller */ udb_alloc_push_fl(base, alloc, big+sz, e); } while(e != exp); /* exit loop when last pushed is same size as what we want */ return big; } /** returns the exponent size of the chunk needed for data sz */ static int udb_alloc_exp_needed(size_t sz) { uint64_t asz = sz + sizeof(udb_chunk_d) + 1; int exp; if(asz > UDB_ALLOC_CHUNK_SIZE) { return UDB_EXP_XL; } else if(asz <= UDB_ALLOC_CHUNK_MINSIZE) { return UDB_ALLOC_CHUNK_MINEXP; } exp = udb_exp_size(asz); assert(exp <= UDB_ALLOC_CHUNKS_MAX); return exp; } udb_void udb_alloc_space(udb_alloc* alloc, size_t sz) { void* base = alloc->udb->base; /* calculate actual allocation size */ int e2, exp = udb_alloc_exp_needed(sz); if(exp == UDB_EXP_XL) return udb_alloc_xl_space(base, alloc, sz); /* see if there is a free chunk of that size exactly */ if(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]) { /* snip from freelist, udb_chunk_d */ udb_void ret; alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; ret = udb_alloc_pop_fl(base, alloc, exp); /* use it - size octets already OK */ UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; UDB_CHUNK(ret)->type = udb_chunk_type_data; /* update stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += (1<disk->stat_free >= (1u<disk->stat_free -= (1<udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /* see if we can subdivide a larger chunk */ for(e2 = exp+1; e2 <= UDB_ALLOC_CHUNKS_MAX; e2++) if(alloc->disk->free[e2-UDB_ALLOC_CHUNK_MINEXP]) { udb_void big, ret; /* udb_chunk_d */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; big = udb_alloc_pop_fl(base, alloc, e2); /* push other parts onto freelists (needs inited) */ ret = udb_alloc_subdivide(base, alloc, big, e2, exp); /* use final part (needs inited) */ UDB_CHUNK(ret)->exp = (uint8_t)exp; /* if stop here; the new exp makes smaller free chunk*/ UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; /* set type to commit data chunk */ UDB_CHUNK(ret)->type = udb_chunk_type_data; /* store last octet */ chunk_set_last(base, ret, exp, (uint8_t)exp); /* update stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += (1<disk->stat_free >= (1u<disk->stat_free -= (1<udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /* we need to grow an extra chunk */ return udb_alloc_grow_space(base, alloc, sz, exp); } /** see if there is free space to allocate a chunk into */ static int have_free_for(udb_alloc* alloc, int exp) { int e2; if(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]) return exp; for(e2 = exp+1; e2 <= UDB_ALLOC_CHUNKS_MAX; e2++) if(alloc->disk->free[e2-UDB_ALLOC_CHUNK_MINEXP]) { return e2; } return 0; } /** fix relptr prev and next for moved relptr structures */ static void chunk_fix_ptr_each(void* base, udb_rel_ptr* rp, void* arg) { udb_void* data = (udb_void*)arg; udb_void r; if(!rp->data) return; r = UDB_SYSTOREL(base, rp); if(rp->next) UDB_REL_PTR(rp->next)->prev = r; if(rp->prev) UDB_REL_PTR(rp->prev)->next = r; else { /* if this is a pointer to its own chunk, fix it up; * the data ptr gets set by relptr_edit later. */ if(rp->data == data[0]) UDB_CHUNK(data[1])->ptrlist = r; else UDB_CHUNK(chunk_from_dataptr(rp->data))->ptrlist = r; } } /** fix pointers from and to a moved chunk */ static void chunk_fix_ptrs(void* base, udb_base* udb, udb_chunk_d* cp, udb_void data, uint64_t dsz, udb_void olddata) { udb_void d[2]; d[0] = olddata; d[1] = data; (*udb->walkfunc)(base, udb->walkarg, cp->type, UDB_REL(base, data), dsz, &chunk_fix_ptr_each, d); udb_rel_ptr_edit(base, cp->ptrlist, data); udb_base_ram_ptr_edit(udb, olddata, data); } /** move an allocated chunk to use a free chunk */ static void move_chunk(void* base, udb_alloc* alloc, udb_void f, int exp, uint64_t esz, int e2) { udb_void res = udb_alloc_pop_fl(base, alloc, e2); udb_chunk_d* rp; udb_chunk_d* fp; if(exp != e2) { /* it is bigger, subdivide it */ res = udb_alloc_subdivide(base, alloc, res, e2, exp); } assert(res != f); /* setup rollback information */ alloc->udb->glob_data->rb_old = f; alloc->udb->glob_data->rb_new = res; alloc->udb->glob_data->rb_size = esz; /* take the res, exp into use */ rp = UDB_CHUNK(res); fp = UDB_CHUNK(f); /* copy over the data */ memcpy(rp, fp, esz); /* adjust rel ptrs */ chunk_fix_ptrs(base, alloc->udb, rp, res+sizeof(udb_chunk_d), esz-sizeof(udb_chunk_d)-1, f+sizeof(udb_chunk_d)); /* do not freeup the fp; caller does that */ } /** unlink several free elements to overwrite with xl chunk */ static void free_xl_space(void* base, udb_alloc* alloc, udb_void s, uint64_t m) { udb_void q = s + m - UDB_ALLOC_CHUNK_SIZE; /* because of header and alignment we know s >= UDB_ALLOC_CHUNK_SIZE*/ assert(s >= UDB_ALLOC_CHUNK_SIZE); while(q >= s) { assert(UDB_CHUNK(q)->exp == UDB_ALLOC_CHUNKS_MAX); assert(UDB_CHUNK(q)->type == udb_chunk_type_free); udb_alloc_unlink_fl(base, alloc, q, UDB_ALLOC_CHUNKS_MAX); q -= UDB_ALLOC_CHUNK_SIZE; } } /** move an XL chunk, and keep track of segments for rollback */ static void move_xl_segment(void* base, udb_base* udb, udb_void xl, udb_void n, uint64_t sz, uint64_t startseg) { udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); udb_xl_chunk_d* np = UDB_XL_CHUNK(n); uint64_t amount = xl - n; assert(n < xl); /* move to compact */ /* setup move rollback */ udb->glob_data->rb_old = xl; udb->glob_data->rb_new = n; udb->glob_data->rb_size = sz; /* is it overlapping? */ if(sz <= amount) { memcpy(np, xlp, sz); } else { /* move and commit per 1M segment to avoid data loss */ uint64_t seg, maxseg = amount/UDB_ALLOC_CHUNK_SIZE; for(seg = startseg; segglob_data->rb_seg = seg; memcpy(np+seg*UDB_ALLOC_CHUNK_SIZE, xlp+seg*UDB_ALLOC_CHUNK_SIZE, UDB_ALLOC_CHUNK_SIZE); } } } /** move list of XL chunks to the front by the shift amount */ static void move_xl_list(void* base, udb_alloc* alloc, udb_void xl_start, uint64_t xl_sz, uint64_t amount) { udb_void xl = xl_start; assert( (xl_start&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* aligned */ assert( (amount&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* multiples */ assert( (xl_sz&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* multiples */ while(xl < xl_start+xl_sz) { udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); udb_void n = xl-amount; uint64_t sz = xlp->size; assert(xlp->exp == UDB_EXP_XL); move_xl_segment(base, alloc->udb, xl, n, sz, 0); chunk_fix_ptrs(base, alloc->udb, UDB_CHUNK(n), n+sizeof(udb_xl_chunk_d), sz-sizeof(udb_xl_chunk_d)-sizeof(uint64_t)*2, xl+sizeof(udb_xl_chunk_d)); } alloc->disk->stat_free -= amount; alloc->disk->nextgrow -= amount; alloc->udb->glob_data->rb_old = 0; alloc->udb->glob_data->rb_new = 0; alloc->udb->glob_data->rb_size = 0; } /** see if free chunk can coagulate with another chunk, return other chunk */ static udb_void coagulate_possible(void* base, udb_alloc* alloc, udb_void f, int exp, uint64_t esz) { udb_void other = f^esz; if(exp == UDB_ALLOC_CHUNKS_MAX) return 0; /* no further merges */ if(other >= alloc->udb->base_size) return 0; /* not allocated */ if(other >= alloc->disk->nextgrow) return 0; /* not in use */ if(other < alloc->udb->glob_data->hsize) return 0; /* cannot merge with header */ /* the header is also protected by the special exp marker */ /* see if the other chunk is a free chunk */ /* check closest marker to avoid large memory churn */ /* and also it makes XL allocations and header special markers work */ if(f > other) { assert(f > 1); /* this is certain because of header */ if(*((uint8_t*)UDB_REL(base, f-1)) == (uint8_t)exp) { /* can do it if the other part is a free chunk */ assert(UDB_FREE_CHUNK(other)->exp == (uint8_t)exp); if(UDB_CHUNK(other)->type == udb_chunk_type_free) return other; } } else { if(UDB_CHUNK(other)->exp == (uint8_t)exp) { /* can do it if the other part is a free chunk */ assert(chunk_get_last(base, other, exp)==(uint8_t)exp); if(UDB_CHUNK(other)->type == udb_chunk_type_free) return other; } } return 0; } /** coagulate and then add new free segment, return final free segment */ static udb_void coagulate_and_push(void* base, udb_alloc* alloc, udb_void last, int exp, uint64_t esz) { /* new free chunk here, attempt coagulate */ udb_void other; while( (other=coagulate_possible(base, alloc, last, exp, esz)) ) { /* unlink that other chunk */ udb_alloc_unlink_fl(base, alloc, other, exp); /* merge up */ if(other < last) last = other; exp++; esz <<= 1; } /* free the final segment */ udb_alloc_push_fl(base, alloc, last, exp); return last; } /** attempt to compact the data and move free space to the end */ int udb_alloc_compact(void* base, udb_alloc* alloc) { udb_void last; int exp, e2; uint64_t esz; uint64_t at = alloc->disk->nextgrow; udb_void xl_start = 0; uint64_t xl_sz = 0; if(alloc->udb->inhibit_compact) return 1; alloc->udb->useful_compact = 0; while(at > alloc->udb->glob_data->hsize) { /* grab last entry */ exp = (int)*((uint8_t*)UDB_REL(base, at-1)); if(exp == UDB_EXP_XL) { /* for XL chunks: * - inspect the size of the XLchunklist at end * - attempt to compact in front of of XLchunklist */ uint64_t xlsz = *((uint64_t*)UDB_REL(base, at-sizeof(uint64_t)*2)); udb_void xl = at-xlsz; #ifndef NDEBUG udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); assert(xlp->exp == UDB_EXP_XL); assert(xlp->type != udb_chunk_type_free); #endif /* got thesegment add to the xl chunk list */ if(xl_start != 0 && xl+xlsz != xl_start) { /* nonadjoining XL part, but they are aligned, * so the space in between is whole Mbs, * shift the later part(s) and continue */ uint64_t m = xl_start - (xl+xlsz); assert(xl_start > xl+xlsz); alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; free_xl_space(base, alloc, xl+xlsz, m); move_xl_list(base, alloc, xl_start, xl_sz, m); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } xl_start = xl; xl_sz += xlsz; at = xl; continue; /* end of XL if */ } else if(exp < UDB_ALLOC_CHUNK_MINEXP || exp > UDB_ALLOC_CHUNKS_MAX) break; /* special chunk or garbage */ esz = (uint64_t)1<exp == (uint8_t)exp); if(UDB_CHUNK(last)->type == udb_chunk_type_free) { /* if xlstart continue looking to move stuff, but do * not unlink this free segment */ if(!xl_start) { /* it is a free chunk, remove it */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; udb_alloc_unlink_fl(base, alloc, last, exp); alloc->disk->stat_free -= esz; alloc->disk->nextgrow = last; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* and continue at this point */ } at = last; } else if( (e2=have_free_for(alloc, exp)) ) { /* last entry can be allocated in free chunks * move it to its new position, adjust rel_ptrs */ alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; move_chunk(base, alloc, last, exp, esz, e2); if(xl_start) { last = coagulate_and_push(base, alloc, last, exp, esz); } else { /* shorten usage */ alloc->disk->stat_free -= esz; alloc->disk->nextgrow = last; } alloc->udb->glob_data->rb_old = 0; alloc->udb->glob_data->rb_new = 0; alloc->udb->glob_data->rb_size = 0; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* and continue in front of it */ at = last; } else { /* cannot compact this block, stop compacting */ break; } /* if that worked, repeat it */ } /* if we passed xl chunks, see if XL-chunklist can move */ if(xl_start) { /* calculate free space in front of the XLchunklist. */ /* has to be whole mbs of free space */ /* if so, we can move the XL chunks. Move them all back * by the new free space. */ /* this compacts very well, but the XL chunks can be moved * multiple times; worst case for every mb freed a huge sized * xlchunklist gets moved. */ /* free space must be, since aligned and coagulated, in * chunks of a whole MB */ udb_void at = xl_start; uint64_t m = 0; while(*((uint8_t*)UDB_REL(base, at-1))==UDB_ALLOC_CHUNKS_MAX){ udb_void chunk = at - UDB_ALLOC_CHUNK_SIZE; if(UDB_CHUNK(chunk)->type != udb_chunk_type_free) break; assert(UDB_CHUNK(chunk)->exp==UDB_ALLOC_CHUNKS_MAX); m += UDB_ALLOC_CHUNK_SIZE; at = chunk; } if(m != 0) { assert(at+m == xl_start); alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; free_xl_space(base, alloc, at, m); move_xl_list(base, alloc, xl_start, xl_sz, m); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } } /* if enough free, shrink the file; re-mmap */ if(enough_free(alloc)) { uint64_t nsize = alloc->disk->nextgrow; udb_base_shrink(alloc->udb, nsize); if(!udb_base_remap(alloc->udb, alloc, nsize)) return 0; } return 1; } int udb_compact(udb_base* udb) { if(!udb) return 1; if(!udb->useful_compact) return 1; DEBUG(DEBUG_DBACCESS, 1, (LOG_INFO, "Compacting database...")); return udb_alloc_compact(udb->base, udb->alloc); } void udb_compact_inhibited(udb_base* udb, int inhibit) { if(!udb) return; udb->inhibit_compact = inhibit; } #ifdef UDB_CHECK /** check that rptrs are really zero before free */ void udb_check_rptr_zero(void* base, udb_rel_ptr* p, void* arg) { (void)base; (void)arg; assert(p->data == 0); } #endif /* UDB_CHECK */ /** free XL chunk as multiples of CHUNK_SIZE free segments */ static void udb_free_xl(void* base, udb_alloc* alloc, udb_void f, udb_xl_chunk_d* fp, size_t sz) { uint64_t xlsz = fp->size; uint64_t c; /* lightweight check for buffer overflow in xl data */ assert(*((uint64_t*)(UDB_REL(base, f+xlsz-sizeof(uint64_t)*2)))==xlsz); assert(*((uint8_t*)(UDB_REL(base, f+xlsz-1))) == UDB_EXP_XL); assert( (xlsz & (UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* whole mbs */ assert( (f & (UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* aligned */ #ifdef UDB_CHECK /* check that relptrs in this chunk have been zeroed */ (*alloc->udb->walkfunc)(base, alloc->udb->walkarg, fp->type, UDB_REL(base, f+sizeof(udb_xl_chunk_d)), xlsz, &udb_check_rptr_zero, NULL); #endif alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; /* update stats */ alloc->disk->stat_data -= sz; alloc->disk->stat_alloc -= xlsz; alloc->disk->stat_free += xlsz; /* walk in reverse, so the front blocks go first on the list */ c = f + xlsz - UDB_ALLOC_CHUNK_SIZE; /* because of header and alignment we know f >= UDB_ALLOC_CHUNK_SIZE*/ assert(f >= UDB_ALLOC_CHUNK_SIZE); while(c >= f) { /* free a block of CHUNK_SIZE (1 Mb) */ udb_alloc_push_fl(base, alloc, c, UDB_ALLOC_CHUNKS_MAX); c -= UDB_ALLOC_CHUNK_SIZE; } alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz) { void* base; /* lookup chunk ptr */ udb_void f; udb_chunk_d* fp; uint64_t esz; int exp; udb_void other; int coagulated = 0; if(!r) return 1; /* free(NULL) does nothing */ /* lookup size of chunk */ base = alloc->udb->base; /* fails for XL blocks */ f = chunk_from_dataptr(r); fp = UDB_CHUNK(f); assert(fp->type != udb_chunk_type_free); /* see if it has a ptrlist, if so: trouble, the list is not properly * cleaned up. (although you can imagine a wholesale delete where * it does not matter) */ assert(fp->ptrlist == 0); /* set ptrlist to 0 to stop relptr from using it, robustness. */ fp->ptrlist = 0; if(fp->exp == UDB_EXP_XL) { udb_free_xl(base, alloc, f, (udb_xl_chunk_d*)fp, sz); /* compact */ if(alloc->udb->inhibit_compact) { alloc->udb->useful_compact = 1; return 1; } return udb_alloc_compact(base, alloc); } /* it is a regular chunk of 2**exp size */ exp = (int)fp->exp; esz = (uint64_t)1<udb->walkfunc)(base, alloc->udb->walkarg, fp->type, UDB_REL(base, r), esz, &udb_check_rptr_zero, NULL); #endif /* update the stats */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; alloc->disk->stat_data -= sz; alloc->disk->stat_free += esz; alloc->disk->stat_alloc -= esz; /* if it can be merged with other free chunks, do so */ while( (other=coagulate_possible(base, alloc, f, exp, esz)) ) { coagulated = 1; /* unlink that other chunk and expand it (it has same size) */ udb_alloc_unlink_fl(base, alloc, other, exp); /* merge up */ if(other < f) f = other; exp++; esz <<= 1; } if(coagulated) { /* put big free chunk into freelist, and init it */ udb_alloc_push_fl(base, alloc, f, exp); } else { /* we do not need to touch the last-exp-byte, which may save * a reference to that page of memory */ fp->type = udb_chunk_type_free; fp->flags = 0; udb_alloc_push_fl_noinit(base, alloc, f, exp); } alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* compact */ if(alloc->udb->inhibit_compact) { alloc->udb->useful_compact = 1; return 1; } return udb_alloc_compact(base, alloc); } udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz) { /* could be faster maybe, if grown? */ udb_void r = udb_alloc_space(alloc, sz); if(!r) return r; memcpy(UDB_REL(alloc->udb->base, r), d, sz); return r; } udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz, size_t sz) { void* base = alloc->udb->base; udb_void c, n, newd; udb_chunk_d* cp, *np; uint64_t avail; uint8_t cp_type; /* emulate some posix realloc stuff */ if(r == 0) return udb_alloc_space(alloc, sz); if(sz == 0) { if(!udb_alloc_free(alloc, r, osz)) log_msg(LOG_ERR, "udb_alloc_realloc: free failed"); return 0; } c = chunk_from_dataptr(r); cp = UDB_CHUNK(c); cp_type = cp->type; if(cp->exp == UDB_EXP_XL) { avail = UDB_XL_CHUNK(c)->size - sizeof(udb_xl_chunk_d) - sizeof(uint64_t)*2; } else { avail = ((uint64_t)1<exp) - sizeof(udb_chunk_d) - 1; } if(sz <= avail) return r; /* reallocate it, and copy */ newd = udb_alloc_space(alloc, sz); if(!newd) return 0; /* re-base after alloc, since re-mmap may have happened */ base = alloc->udb->base; cp = NULL; /* may be invalid now, robustness */ n = chunk_from_dataptr(newd); np = UDB_CHUNK(n); np->type = cp_type; memcpy(UDB_REL(base, newd), UDB_REL(base, r), osz); /* fixup ptrs */ chunk_fix_ptrs(base, alloc->udb, np, newd, osz, r); if(!udb_alloc_free(alloc, r, osz)) log_msg(LOG_ERR, "udb_alloc_realloc: free failed"); return newd; } int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num) { const uint64_t mb = 1024*1024; int exp = udb_alloc_exp_needed(sz); uint64_t esz; uint64_t want; if(exp == UDB_EXP_XL) esz = (sz&(mb-1))+mb; else esz = (uint64_t)1<= alloc->udb->base_size); if(!udb_base_grow_and_remap(alloc->udb, want)) { log_msg(LOG_ERR, "failed to grow the specified amount"); return 0; } return 1; } void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp) { void* base = alloc->udb->base; udb_void f = chunk_from_dataptr(r); udb_chunk_d* fp = UDB_CHUNK(f); /* not the 'free' type, that must be set by allocation routines */ assert(fp->type != udb_chunk_type_free); assert(tp != udb_chunk_type_free); fp->type = tp; } int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize) { /* pointers are not valid before the header-size or after the * used-region of the mmap */ return ( (to+destsize) <= udb->base_size && to >= (udb->glob_data->hsize-2*sizeof(udb_rel_ptr)) && (to+destsize) <= udb->alloc->disk->nextgrow); } int udb_valid_dataptr(udb_base* udb, udb_void to) { void* base = udb->base; udb_void ch; int exp; uint64_t esz; /* our data chunks are aligned and at least 8 bytes */ if(!udb_valid_offset(udb, to, sizeof(uint64_t))) return 0; /* get the chunk pointer */ ch = chunk_from_dataptr(to); if(!udb_valid_offset(udb, ch, sizeof(udb_chunk_d))) return 0; /* check its size */ exp = UDB_CHUNK(ch)->exp; if(exp == UDB_EXP_XL) { /* check XL chunk */ uint64_t xlsz; if(!udb_valid_offset(udb, ch, sizeof(udb_xl_chunk_d))) return 0; xlsz = UDB_XL_CHUNK(ch)->size; if(!udb_valid_offset(udb, ch+xlsz-1, 1)) return 0; if(*((uint8_t*)UDB_REL(base, ch+xlsz-1)) != UDB_EXP_XL) return 0; if(*((uint64_t*)UDB_REL(base, ch+xlsz-sizeof(uint64_t)*2)) != xlsz) return 0; return 1; } /* check if regular chunk has matching end byte */ if(exp < UDB_ALLOC_CHUNK_MINEXP || exp > UDB_ALLOC_CHUNKS_MAX) return 0; /* cannot be a valid chunk */ esz = 1<base; udb_void p; if(!udb_valid_offset(udb, rptr, sizeof(udb_rel_ptr))) return 0; if(!udb_valid_dataptr(udb, to)) return 0; p = UDB_CHUNK(chunk_from_dataptr(to))->ptrlist; while(p) { if(!udb_valid_offset(udb, p, sizeof(udb_rel_ptr))) return 0; if(p == rptr) return 1; p = UDB_REL_PTR(p)->next; } return 0; } void udb_rel_ptr_init(udb_rel_ptr* ptr) { memset(ptr, 0, sizeof(*ptr)); } void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr) { if(!ptr->data) return; if(ptr->prev) { UDB_REL_PTR(ptr->prev)->next = ptr->next; } else { UDB_CHUNK(chunk_from_dataptr(ptr->data))->ptrlist = ptr->next; } if(ptr->next) { UDB_REL_PTR(ptr->next)->prev = ptr->prev; } } void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to) { udb_chunk_d* chunk = UDB_CHUNK(chunk_from_dataptr(to)); ptr->prev = 0; ptr->next = chunk->ptrlist; if(ptr->next) UDB_REL_PTR(ptr->next)->prev = UDB_SYSTOREL(base, ptr); chunk->ptrlist = UDB_SYSTOREL(base, ptr); ptr->data = to; } void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to) { assert(to == 0 || to > 64); udb_rel_ptr_unlink(base, ptr); if(to) udb_rel_ptr_link(base, ptr, to); else ptr->data = to; } void udb_rel_ptr_edit(void* base, udb_void list, udb_void to) { udb_void p = list; while(p) { UDB_REL_PTR(p)->data = to; p = UDB_REL_PTR(p)->next; } } #ifdef UDB_CHECK /** check that all pointers are validly chained */ static void udb_check_ptrs_valid(udb_base* udb) { size_t i; udb_ptr* p, *prev; for(i=0; iram_size; i++) { prev = NULL; for(p=udb->ram_hash[i]; p; p=p->next) { assert(p->prev == prev); assert((size_t)(chunk_hash_ptr(p->data)&udb->ram_mask) == i); assert(p->base == &udb->base); prev = p; } } } #endif /* UDB_CHECK */ void udb_ptr_init(udb_ptr* ptr, udb_base* udb) { #ifdef UDB_CHECK udb_check_ptrs_valid(udb); /* previous ptrs have been unlinked */ #endif memset(ptr, 0, sizeof(*ptr)); ptr->base = &udb->base; } void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval) { assert(newval == 0 || newval > 64); if(ptr->data) udb_base_unlink_ptr(udb, ptr); ptr->data = newval; if(newval) udb_base_link_ptr(udb, ptr); } int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type, size_t sz) { udb_void r; r = udb_alloc_space(udb->alloc, sz); if(!r) return 0; udb_alloc_set_type(udb->alloc, r, type); udb_ptr_init(ptr, udb); udb_ptr_set(ptr, udb, r); return 1; } void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz) { if(ptr->data) { udb_void d = ptr->data; udb_ptr_set(ptr, udb, 0); udb_alloc_free(udb->alloc, d, sz); } } udb_chunk_type udb_ptr_get_type(udb_ptr* ptr) { udb_void f; if(!ptr || ptr->data == 0) return udb_chunk_type_internal; /* something bad*/ f = chunk_from_dataptr(ptr->data); return ((udb_chunk_d*)UDB_REL(*ptr->base, f))->type; } nsd-4.12.0/tsig.h0000644000175000017500000001650115002373054013117 0ustar mozziemozzie/* * tsig.h -- TSIG definitions (RFC 2845). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef TSIG_H #define TSIG_H #include #include #include #include "buffer.h" #include "dname.h" #define TSIG_ERROR_NOERROR 0 #define TSIG_ERROR_BADSIG 16 #define TSIG_ERROR_BADKEY 17 #define TSIG_ERROR_BADTIME 18 typedef struct tsig_algorithm tsig_algorithm_type; typedef struct tsig_key tsig_key_type; typedef struct tsig_record tsig_record_type; enum tsig_status { TSIG_NOT_PRESENT, TSIG_OK, TSIG_ERROR }; typedef enum tsig_status tsig_status_type; struct tsig_lookup_struct_table { uint8_t id; const char* short_name; }; typedef struct tsig_lookup_struct_table tsig_lookup_algorithm_table; /* * A TSIG HMAC algorithm, such as hmac-md5. */ struct tsig_algorithm { /* * Short name of the algorithm, such as "hmac-md5". */ const char *short_name; /* * Full wireformat name of the algorithm, such as * "hmac-md5.sig-alg.reg.int." */ const dname_type *wireformat_name; /* * The maximum size of a digest generated by this algorithm. */ size_t maximum_digest_size; /* * Algorithm implementation specific data. */ const void *data; /* * Create a new HMAC context. */ void *(*hmac_create_context)(region_type *region); /* * Initialize an HMAC context with the specified algorithm and * key. */ void (*hmac_init_context)(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key); /* * Update the HMAC context with the specified data. */ void (*hmac_update)(void *context, const void *data, size_t size); /* * Generate the final digest. DIGEST points to a buffer of at * least maximum_digest_size bytes. */ void (*hmac_final)(void *context, uint8_t *digest, size_t *size); }; /* * A TSIG key used to sign and verify packets. */ struct tsig_key { const dname_type *name; size_t size; uint8_t *data; }; struct tsig_record { tsig_status_type status; size_t position; size_t response_count; size_t updates_since_last_prepare; void *context; tsig_algorithm_type *algorithm; tsig_key_type *key; size_t prior_mac_size; uint8_t *prior_mac_data; /* TSIG RR data is allocated in the rr_region. */ region_type *rr_region; region_type *context_region; const dname_type *key_name; const dname_type *algorithm_name; uint16_t signed_time_high; uint32_t signed_time_low; uint16_t signed_time_fudge; uint16_t mac_size; uint8_t *mac_data; uint16_t original_query_id; uint16_t error_code; uint16_t other_size; uint8_t *other_data; }; /* * Initialize the TSIG module (including TSIG implementation modules * such as tsig-openssl). */ int tsig_init(region_type *region); /* * Add the specified key to the TSIG key table. */ void tsig_add_key(tsig_key_type *key); void tsig_del_key(tsig_key_type *key); /* * Add the specified algorithm to the TSIG algorithm table. */ void tsig_add_algorithm(tsig_algorithm_type *algorithm); /* * Find an HMAC algorithm based on its short name. */ tsig_algorithm_type *tsig_get_algorithm_by_name(const char *name); /* * Return a descriptive error message based on the TSIG error code. */ const char *tsig_error(int error_code); /* * Create the tsig record internal structure. Allocs it. * Call init_record afterwards before doing more with it. * * The region is used to attach a cleanup function that destroys the tsig. */ void tsig_create_record(tsig_record_type* tsig, region_type* region); /* * Like tsig_create_record, with custom region settings. * The size params are used to customise the rr_region and context_region. * If region is NULL, no cleanup is attached to it. */ void tsig_create_record_custom(tsig_record_type* tsig, region_type* region, size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size); /* * Destroy tsig record internals (the main ptr is user alloced). * if region is nonNULL, removes cleanup. */ void tsig_delete_record(tsig_record_type* tsig, region_type* region); /* * Call this before starting to analyze or signing a sequence of * packets. * * ALGORITHM and KEY are optional and are only needed if you want to * sign the initial query. Otherwise the key and algorithm are looked * up in the algorithm and key table when a received TSIG RR is * processed. */ void tsig_init_record(tsig_record_type *data, tsig_algorithm_type *algorithm, tsig_key_type *key); /* * Validate the TSIG RR key and algorithm from the TSIG RR. Otherwise * update the TSIG error code. The MAC itself is not validated. * * Returns non-zero if the key and algorithm could be validated. */ int tsig_from_query(tsig_record_type *tsig); /* * Prepare TSIG for signing of a query. This initializes TSIG with * the algorithm and key stored in the TSIG record. */ void tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id); /* * Prepare TSIG for performing an HMAC calculation. If the TSIG * contains a prior HMAC it is inserted first into the hash * calculation. */ void tsig_prepare(tsig_record_type *tsig); /* * Add the first LENGTH octets of PACKET to the TSIG hash, replacing * the PACKET's id with the original query id from TSIG. If the query * is a response the TSIG response count is incremented. */ void tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length); /* * Finalize the TSIG record by hashing the TSIG data. If the TSIG * response count is greater than 1 only the timers are hashed. * Signed time is set to the current time. The TSIG record can be * added to a packet using tsig_append_rr(). * * The calculated MAC is also stored as the prior MAC, so it can be * used as a running MAC. */ void tsig_sign(tsig_record_type *tsig); /* * Verify the calculated MAC against the MAC in the TSIG RR. * * The calculated MAC is also stored as the prior MAC, so it can be * used as a running MAC. */ int tsig_verify(tsig_record_type *tsig); /* * Find the TSIG RR in QUERY and parse it if present. Store the * parsed results in TSIG. * * Returns non-zero if no parsing error occurred, use the tsig->status * field to find out if the TSIG record was present. */ int tsig_find_rr(tsig_record_type *tsig, buffer_type *packet); /* * Call this to analyze the TSIG RR starting at the current location * of PACKET. On success true is returned and the results are stored * in TSIG. * * Returns non-zero if no parsing error occurred, use the tsig->status * field to find out if the TSIG record was present. */ int tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet); /* * Append the TSIG record to the response PACKET. */ void tsig_append_rr(tsig_record_type *tsig, buffer_type *packet); /* * The amount of space to reserve in the response for the TSIG data * (if required). */ size_t tsig_reserved_space(tsig_record_type *tsig); /* * status or error_code must already be in error. * prepares content for error packet. */ void tsig_error_reply(tsig_record_type *tsig); /* * compare tsig algorithm names case insensitive. */ int tsig_strlowercmp(const char* str1, const char* str2); /* * cleanup tsig openssl stuff. */ void tsig_finalize(void); #endif /* TSIG_H */ nsd-4.12.0/tsig.c0000644000175000017500000004523515002373054013120 0ustar mozziemozzie/* * tsig.c -- TSIG implementation (RFC 2845). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "tsig.h" #include "tsig-openssl.h" #include "dns.h" #include "packet.h" #include "query.h" #include "rbtree.h" #if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP) /* we need fixed time compare */ #define CRYPTO_memcmp memcmp_fixedtime int memcmp_fixedtime(const void *s1, const void *s2, size_t n) { size_t i; const uint8_t* u1 = (const uint8_t*)s1; const uint8_t* u2 = (const uint8_t*)s2; int ret = 0, haveit = 0, bret = 0, bhaveit = 0; /* this routine loops for every byte in the strings. * every loop, it tests ==, < and >. All three. One succeeds, * as every time it must be equal, smaller or larger. The one * that succeeds has one if-comparison and two assignments. */ for(i=0; i statements */ if(haveit) { bret = -1; /* waste time */ bhaveit = 1; } else { bret = 1; /* waste time */ bhaveit = 1; } } if(u1[i] < u2[i]) { if(haveit) { bret = -1; /* waste time equal to the else */ bhaveit = 1; } else { ret = -1; haveit = 1; } } if(u1[i] > u2[i]) { if(haveit) { bret = 1; /* waste time equal to the else */ bhaveit = 1; } else { ret = 1; haveit = 1; } } } /* use the variables to stop the compiler from excluding them */ if(bhaveit) { if(bret == -2) ret = 0; /* never happens */ } else { if(bret == -2) ret = 0; /* never happens */ } return ret; } #endif static region_type *tsig_region; struct tsig_key_table { rbnode_type node; /* by dname */ tsig_key_type *key; }; typedef struct tsig_key_table tsig_key_table_type; static rbtree_type *tsig_key_table; struct tsig_algorithm_table { struct tsig_algorithm_table *next; tsig_algorithm_type *algorithm; }; typedef struct tsig_algorithm_table tsig_algorithm_table_type; static tsig_algorithm_table_type *tsig_algorithm_table; static size_t max_algo_digest_size = 0; static void tsig_digest_variables(tsig_record_type *tsig, int tsig_timers_only) { uint16_t klass = htons(CLASS_ANY); uint32_t ttl = htonl(0); uint16_t signed_time_high = htons(tsig->signed_time_high); uint32_t signed_time_low = htonl(tsig->signed_time_low); uint16_t signed_time_fudge = htons(tsig->signed_time_fudge); uint16_t error_code = htons(tsig->error_code); uint16_t other_size = htons(tsig->other_size); if (!tsig_timers_only) { tsig->algorithm->hmac_update(tsig->context, dname_name(tsig->key_name), tsig->key_name->name_size); tsig->algorithm->hmac_update(tsig->context, &klass, sizeof(klass)); tsig->algorithm->hmac_update(tsig->context, &ttl, sizeof(ttl)); tsig->algorithm->hmac_update(tsig->context, dname_name(tsig->algorithm_name), tsig->algorithm_name->name_size); } tsig->algorithm->hmac_update(tsig->context, &signed_time_high, sizeof(signed_time_high)); tsig->algorithm->hmac_update(tsig->context, &signed_time_low, sizeof(signed_time_low)); tsig->algorithm->hmac_update(tsig->context, &signed_time_fudge, sizeof(signed_time_fudge)); if (!tsig_timers_only) { tsig->algorithm->hmac_update(tsig->context, &error_code, sizeof(error_code)); tsig->algorithm->hmac_update(tsig->context, &other_size, sizeof(other_size)); tsig->algorithm->hmac_update(tsig->context, tsig->other_data, tsig->other_size); } } static int tree_dname_compare(const void* a, const void* b) { return dname_compare((const dname_type*)a, (const dname_type*)b); } int tsig_init(region_type *region) { tsig_region = region; tsig_key_table = rbtree_create(region, &tree_dname_compare); tsig_algorithm_table = NULL; #if defined(HAVE_SSL) return tsig_openssl_init(region); #endif /* defined(HAVE_SSL) */ return 1; } void tsig_add_key(tsig_key_type *key) { tsig_key_table_type *entry = (tsig_key_table_type *) region_alloc_zero( tsig_region, sizeof(tsig_key_table_type)); entry->key = key; entry->node.key = entry->key->name; (void)rbtree_insert(tsig_key_table, &entry->node); } void tsig_del_key(tsig_key_type *key) { tsig_key_table_type *entry; if(!key) return; entry = (tsig_key_table_type*)rbtree_delete(tsig_key_table, key->name); if(!entry) return; region_recycle(tsig_region, entry, sizeof(tsig_key_table_type)); } tsig_key_type* tsig_find_key(const dname_type* name) { tsig_key_table_type* entry; entry = (tsig_key_table_type*)rbtree_search(tsig_key_table, name); if(entry) return entry->key; return NULL; } void tsig_add_algorithm(tsig_algorithm_type *algorithm) { tsig_algorithm_table_type *entry = (tsig_algorithm_table_type *) region_alloc( tsig_region, sizeof(tsig_algorithm_table_type)); entry->algorithm = algorithm; entry->next = tsig_algorithm_table; tsig_algorithm_table = entry; if(algorithm->maximum_digest_size > max_algo_digest_size) max_algo_digest_size = algorithm->maximum_digest_size; } /** * compare a tsig algorithm string lowercased */ int tsig_strlowercmp(const char* str1, const char* str2) { while (str1 && str2 && *str1 != '\0' && *str2 != '\0') { if(tolower((unsigned char)*str1) != tolower((unsigned char)*str2)) { if(tolower((unsigned char)*str1) < tolower((unsigned char)*str2)) return -1; return 1; } str1++; str2++; } if (str1 && str2) { if (*str1 == *str2) return 0; else if (*str1 == '\0') return -1; } else if (!str1 && !str2) return 0; else if (!str1 && str2) return -1; return 1; } /* * Find an HMAC algorithm based on its short name. */ tsig_algorithm_type * tsig_get_algorithm_by_name(const char *name) { tsig_algorithm_table_type *algorithm_entry; for (algorithm_entry = tsig_algorithm_table; algorithm_entry; algorithm_entry = algorithm_entry->next) { if (tsig_strlowercmp(name, algorithm_entry->algorithm->short_name) == 0) { return algorithm_entry->algorithm; } if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) == 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) { return algorithm_entry->algorithm; } } return NULL; } const char * tsig_error(int error_code) { static char message[1000]; switch (error_code) { case TSIG_ERROR_NOERROR: return "No Error"; break; case TSIG_ERROR_BADSIG: return "Bad Signature"; break; case TSIG_ERROR_BADKEY: return "Bad Key"; break; case TSIG_ERROR_BADTIME: return "Bad Time"; break; default: if(error_code < 16) /* DNS rcodes */ return rcode2str(error_code); snprintf(message, sizeof(message), "Unknown Error %d", error_code); break; } return message; } static void tsig_cleanup(void *data) { tsig_record_type *tsig = (tsig_record_type *) data; region_destroy(tsig->rr_region); region_destroy(tsig->context_region); } void tsig_create_record(tsig_record_type *tsig, region_type *region) { tsig_create_record_custom(tsig, region, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE); } void tsig_create_record_custom(tsig_record_type *tsig, region_type *region, size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size) { tsig->rr_region = region_create_custom(xalloc, free, chunk_size, large_object_size, initial_cleanup_size, 0); tsig->context_region = region_create_custom(xalloc, free, chunk_size, large_object_size, initial_cleanup_size, 0); if(region) region_add_cleanup(region, tsig_cleanup, tsig); tsig_init_record(tsig, NULL, NULL); } void tsig_delete_record(tsig_record_type* tsig, region_type* region) { if(region) region_remove_cleanup(region, tsig_cleanup, tsig); region_destroy(tsig->rr_region); region_destroy(tsig->context_region); } void tsig_init_record(tsig_record_type *tsig, tsig_algorithm_type *algorithm, tsig_key_type *key) { tsig->status = TSIG_NOT_PRESENT; tsig->error_code = TSIG_ERROR_NOERROR; tsig->position = 0; tsig->response_count = 0; tsig->context = NULL; tsig->algorithm = algorithm; tsig->key = key; tsig->prior_mac_size = 0; tsig->prior_mac_data = NULL; region_free_all(tsig->context_region); } int tsig_from_query(tsig_record_type *tsig) { tsig_key_type *key = NULL; tsig_algorithm_table_type *algorithm_entry; tsig_algorithm_type *algorithm = NULL; uint64_t current_time; uint64_t signed_time; assert(tsig->status == TSIG_OK); assert(!tsig->algorithm); assert(!tsig->key); key = (tsig_key_type*)tsig_find_key(tsig->key_name); for (algorithm_entry = tsig_algorithm_table; algorithm_entry; algorithm_entry = algorithm_entry->next) { if (dname_compare( tsig->algorithm_name, algorithm_entry->algorithm->wireformat_name) == 0) { algorithm = algorithm_entry->algorithm; break; } } if (!algorithm || !key) { /* Algorithm or key is unknown, cannot authenticate. */ tsig->error_code = TSIG_ERROR_BADKEY; return 0; } if ((tsig->algorithm && algorithm != tsig->algorithm) || (tsig->key && key != tsig->key)) { /* * Algorithm or key changed during a single connection, * return error. */ tsig->error_code = TSIG_ERROR_BADKEY; return 0; } signed_time = ((((uint64_t) tsig->signed_time_high) << 32) | ((uint64_t) tsig->signed_time_low)); current_time = (uint64_t) time(NULL); if ((current_time < signed_time - tsig->signed_time_fudge) || (current_time > signed_time + tsig->signed_time_fudge)) { uint16_t current_time_high; uint32_t current_time_low; #if 0 /* debug */ char current_time_text[26]; char signed_time_text[26]; time_t clock; clock = (time_t) current_time; ctime_r(&clock, current_time_text); current_time_text[24] = '\0'; clock = (time_t) signed_time; ctime_r(&clock, signed_time_text); signed_time_text[24] = '\0'; log_msg(LOG_ERR, "current server time %s is outside the range of TSIG" " signed time %s with fudge %u", current_time_text, signed_time_text, (unsigned) tsig->signed_time_fudge); #endif tsig->error_code = TSIG_ERROR_BADTIME; current_time_high = (uint16_t) (current_time >> 32); current_time_low = (uint32_t) current_time; tsig->other_size = 6; tsig->other_data = (uint8_t *) region_alloc( tsig->rr_region, sizeof(uint16_t) + sizeof(uint32_t)); write_uint16(tsig->other_data, current_time_high); write_uint32(tsig->other_data + 2, current_time_low); return 0; } tsig->algorithm = algorithm; tsig->key = key; tsig->response_count = 0; tsig->prior_mac_size = 0; return 1; } void tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id) { assert(tsig); assert(tsig->algorithm); assert(tsig->key); tsig->response_count = 0; tsig->prior_mac_size = 0; tsig->algorithm_name = tsig->algorithm->wireformat_name; tsig->key_name = tsig->key->name; tsig->mac_size = 0; tsig->mac_data = NULL; tsig->original_query_id = original_query_id; tsig->error_code = TSIG_ERROR_NOERROR; tsig->other_size = 0; tsig->other_data = NULL; } void tsig_prepare(tsig_record_type *tsig) { if (!tsig->context) { assert(tsig->algorithm); tsig->context = tsig->algorithm->hmac_create_context( tsig->context_region); tsig->prior_mac_data = (uint8_t *) region_alloc( tsig->context_region, tsig->algorithm->maximum_digest_size); } tsig->algorithm->hmac_init_context(tsig->context, tsig->algorithm, tsig->key); if (tsig->prior_mac_size > 0) { uint16_t mac_size = htons(tsig->prior_mac_size); tsig->algorithm->hmac_update(tsig->context, &mac_size, sizeof(mac_size)); tsig->algorithm->hmac_update(tsig->context, tsig->prior_mac_data, tsig->prior_mac_size); } tsig->updates_since_last_prepare = 0; } void tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length) { uint16_t original_query_id = htons(tsig->original_query_id); assert(length <= buffer_limit(packet)); tsig->algorithm->hmac_update(tsig->context, &original_query_id, sizeof(original_query_id)); tsig->algorithm->hmac_update( tsig->context, buffer_at(packet, sizeof(original_query_id)), length - sizeof(original_query_id)); if (QR(packet)) { ++tsig->response_count; } ++tsig->updates_since_last_prepare; } void tsig_sign(tsig_record_type *tsig) { uint64_t current_time = (uint64_t) time(NULL); tsig->signed_time_high = (uint16_t) (current_time >> 32); tsig->signed_time_low = (uint32_t) current_time; tsig->signed_time_fudge = 300; /* XXX; hardcoded value */ tsig_digest_variables(tsig, tsig->response_count > 1); tsig->algorithm->hmac_final(tsig->context, tsig->prior_mac_data, &tsig->prior_mac_size); tsig->mac_size = tsig->prior_mac_size; tsig->mac_data = tsig->prior_mac_data; } int tsig_verify(tsig_record_type *tsig) { tsig_digest_variables(tsig, tsig->response_count > 1); tsig->algorithm->hmac_final(tsig->context, tsig->prior_mac_data, &tsig->prior_mac_size); if (tsig->mac_size != tsig->prior_mac_size || CRYPTO_memcmp(tsig->mac_data, tsig->prior_mac_data, tsig->mac_size) != 0) { /* Digest is incorrect, cannot authenticate. */ tsig->error_code = TSIG_ERROR_BADSIG; return 0; } else { return 1; } } int tsig_find_rr(tsig_record_type *tsig, buffer_type *packet) { size_t saved_position = buffer_position(packet); size_t rrcount = ((size_t)QDCOUNT(packet) + (size_t)ANCOUNT(packet) + (size_t)NSCOUNT(packet) + (size_t)ARCOUNT(packet)); size_t i; int result; if (ARCOUNT(packet) == 0) { tsig->status = TSIG_NOT_PRESENT; return 1; } if(rrcount > 65530) { /* impossibly high number of records in 64k, reject packet */ buffer_set_position(packet, saved_position); return 0; } buffer_set_position(packet, QHEADERSZ); /* TSIG must be the last record, so skip all others. */ for (i = 0; i < rrcount - 1; ++i) { if (!packet_skip_rr(packet, i < QDCOUNT(packet))) { buffer_set_position(packet, saved_position); return 0; } } result = tsig_parse_rr(tsig, packet); buffer_set_position(packet, saved_position); return result; } int tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet) { uint16_t type; uint16_t klass; uint32_t ttl; uint16_t rdlen; tsig->status = TSIG_NOT_PRESENT; tsig->position = buffer_position(packet); tsig->key_name = NULL; tsig->algorithm_name = NULL; tsig->mac_data = NULL; tsig->other_data = NULL; region_free_all(tsig->rr_region); tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1); if (!tsig->key_name) { buffer_set_position(packet, tsig->position); return 0; } if (!buffer_available(packet, 10)) { buffer_set_position(packet, tsig->position); return 0; } type = buffer_read_u16(packet); klass = buffer_read_u16(packet); /* TSIG not present */ if (type != TYPE_TSIG || klass != CLASS_ANY) { buffer_set_position(packet, tsig->position); return 1; } ttl = buffer_read_u32(packet); rdlen = buffer_read_u16(packet); tsig->status = TSIG_ERROR; tsig->error_code = RCODE_FORMAT; if (ttl != 0 || !buffer_available(packet, rdlen)) { buffer_set_position(packet, tsig->position); return 0; } tsig->algorithm_name = dname_make_from_packet( tsig->rr_region, packet, 1, 1); if (!tsig->algorithm_name || !buffer_available(packet, 10)) { buffer_set_position(packet, tsig->position); return 0; } tsig->signed_time_high = buffer_read_u16(packet); tsig->signed_time_low = buffer_read_u32(packet); tsig->signed_time_fudge = buffer_read_u16(packet); tsig->mac_size = buffer_read_u16(packet); if (!buffer_available(packet, tsig->mac_size)) { buffer_set_position(packet, tsig->position); tsig->mac_size = 0; return 0; } if(tsig->mac_size > 16384) { /* the hash should not be too big, really 512/8=64 bytes */ buffer_set_position(packet, tsig->position); tsig->mac_size = 0; return 0; } tsig->mac_data = (uint8_t *) region_alloc_init( tsig->rr_region, buffer_current(packet), tsig->mac_size); buffer_skip(packet, tsig->mac_size); if (!buffer_available(packet, 6)) { buffer_set_position(packet, tsig->position); return 0; } tsig->original_query_id = buffer_read_u16(packet); tsig->error_code = buffer_read_u16(packet); tsig->other_size = buffer_read_u16(packet); if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) { tsig->other_size = 0; buffer_set_position(packet, tsig->position); return 0; } tsig->other_data = (uint8_t *) region_alloc_init( tsig->rr_region, buffer_current(packet), tsig->other_size); buffer_skip(packet, tsig->other_size); tsig->status = TSIG_OK; return 1; } void tsig_append_rr(tsig_record_type *tsig, buffer_type *packet) { size_t rdlength_pos; /* XXX: TODO key name compression? */ if(tsig->key_name) buffer_write(packet, dname_name(tsig->key_name), tsig->key_name->name_size); else buffer_write_u8(packet, 0); buffer_write_u16(packet, TYPE_TSIG); buffer_write_u16(packet, CLASS_ANY); buffer_write_u32(packet, 0); /* TTL */ rdlength_pos = buffer_position(packet); buffer_skip(packet, sizeof(uint16_t)); if(tsig->algorithm_name) buffer_write(packet, dname_name(tsig->algorithm_name), tsig->algorithm_name->name_size); else buffer_write_u8(packet, 0); buffer_write_u16(packet, tsig->signed_time_high); buffer_write_u32(packet, tsig->signed_time_low); buffer_write_u16(packet, tsig->signed_time_fudge); buffer_write_u16(packet, tsig->mac_size); if(tsig->mac_size != 0) buffer_write(packet, tsig->mac_data, tsig->mac_size); buffer_write_u16(packet, tsig->original_query_id); buffer_write_u16(packet, tsig->error_code); buffer_write_u16(packet, tsig->other_size); if(tsig->other_size != 0) buffer_write(packet, tsig->other_data, tsig->other_size); buffer_write_u16_at(packet, rdlength_pos, buffer_position(packet) - rdlength_pos - sizeof(uint16_t)); } size_t tsig_reserved_space(tsig_record_type *tsig) { if (tsig->status == TSIG_NOT_PRESENT) return 0; return ( (tsig->key_name?tsig->key_name->name_size:1) /* Owner */ + sizeof(uint16_t) /* Type */ + sizeof(uint16_t) /* Class */ + sizeof(uint32_t) /* TTL */ + sizeof(uint16_t) /* RDATA length */ + (tsig->algorithm_name?tsig->algorithm_name->name_size:1) + sizeof(uint16_t) /* Signed time (high) */ + sizeof(uint32_t) /* Signed time (low) */ + sizeof(uint16_t) /* Signed time fudge */ + sizeof(uint16_t) /* MAC size */ + max_algo_digest_size /* MAC data */ + sizeof(uint16_t) /* Original query ID */ + sizeof(uint16_t) /* Error code */ + sizeof(uint16_t) /* Other size */ + tsig->other_size); /* Other data */ } void tsig_error_reply(tsig_record_type *tsig) { if(tsig->mac_data) memset(tsig->mac_data, 0, tsig->mac_size); tsig->mac_size = 0; } void tsig_finalize() { #if defined(HAVE_SSL) tsig_openssl_finalize(); #endif /* defined(HAVE_SSL) */ } nsd-4.12.0/tsig-openssl.h0000644000175000017500000000077615002373054014607 0ustar mozziemozzie/* * tsig-openssl.h -- Interface to OpenSSL for TSIG support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef TSIG_OPENSSL_H #define TSIG_OPENSSL_H #if defined(HAVE_SSL) #include "region-allocator.h" #include #include /* * Initialize OpenSSL support for TSIG. */ int tsig_openssl_init(region_type *region); void tsig_openssl_finalize(void); #endif /* defined(HAVE_SSL) */ #endif /* TSIG_OPENSSL_H */ nsd-4.12.0/tsig-openssl.c0000644000175000017500000001722615002373054014600 0ustar mozziemozzie/* * tsig-openssl.h -- Interface to OpenSSL for TSIG support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #if defined(HAVE_SSL) #ifdef HAVE_OPENSSL_CORE_NAMES_H #include #endif #include "tsig-openssl.h" #include "tsig.h" #include "util.h" static void *create_context(region_type *region); static void init_context(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key); static void update(void *context, const void *data, size_t size); static void final(void *context, uint8_t *digest, size_t *size); #ifdef HAVE_EVP_MAC_CTX_NEW struct tsig_openssl_data { /* the MAC for the algorithm, 'hmac' */ EVP_MAC* mac; /* the digest name for creating the EVP_MAC_CTX with, 'sha256' */ const char* digest; }; struct tsig_openssl_context { /* the evp mac context, if notNULL it has algo and key set. */ EVP_MAC_CTX* hmac_ctx; /* the size of destination buffers */ size_t outsize; }; static void cleanup_tsig_openssl_data(void *data) { struct tsig_openssl_data* d = (struct tsig_openssl_data*)data; EVP_MAC_free(d->mac); d->mac = NULL; } #endif static int tsig_openssl_init_algorithm(region_type* region, const char* digest, const char* name, const char* wireformat) { tsig_algorithm_type* algorithm; #ifndef HAVE_EVP_MAC_CTX_NEW const EVP_MD *hmac_algorithm; hmac_algorithm = EVP_get_digestbyname(digest); if (!hmac_algorithm) { /* skip but don't error */ return 0; } #else struct tsig_openssl_data* data; EVP_MAC_CTX* hmac_ctx; OSSL_PARAM params[3]; data = region_alloc(region, sizeof(*data)); data->digest = digest; data->mac = EVP_MAC_fetch(NULL, "hmac", NULL); if(!data->mac) { log_msg(LOG_ERR, "could not fetch MAC implementation 'hmac' with EVP_MAC_fetch"); return 0; } /* this context is created to see what size the output is */ hmac_ctx = EVP_MAC_CTX_new(data->mac); if(!hmac_ctx) { EVP_MAC_free(data->mac); return 0; } params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char*)digest, 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, "", 1); params[2] = OSSL_PARAM_construct_end(); #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS if(EVP_MAC_CTX_set_params(hmac_ctx, params) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params"); EVP_MAC_CTX_free(hmac_ctx); EVP_MAC_free(data->mac); return 0; } #else if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params"); EVP_MAC_CTX_free(hmac_ctx); EVP_MAC_free(data->mac); return 0; } #endif #endif algorithm = (tsig_algorithm_type *) region_alloc( region, sizeof(tsig_algorithm_type)); algorithm->short_name = name; algorithm->wireformat_name = dname_parse(region, wireformat); if (!algorithm->wireformat_name) { log_msg(LOG_ERR, "cannot parse %s algorithm", wireformat); #ifdef HAVE_EVP_MAC_CTX_NEW EVP_MAC_CTX_free(hmac_ctx); EVP_MAC_free(data->mac); #endif return 0; } #ifdef HAVE_EVP_MAC_CTX_GET_MAC_SIZE algorithm->maximum_digest_size = EVP_MAC_CTX_get_mac_size(hmac_ctx); #elif !defined(HAVE_EVP_MAC_CTX_NEW) algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm); #else algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx); #endif if(algorithm->maximum_digest_size < 20) algorithm->maximum_digest_size = EVP_MAX_MD_SIZE; #ifndef HAVE_EVP_MAC_CTX_NEW algorithm->data = hmac_algorithm; #else algorithm->data = data; region_add_cleanup(region, cleanup_tsig_openssl_data, data); #endif algorithm->hmac_create_context = create_context; algorithm->hmac_init_context = init_context; algorithm->hmac_update = update; algorithm->hmac_final = final; tsig_add_algorithm(algorithm); #ifdef HAVE_EVP_MAC_CTX_NEW EVP_MAC_CTX_free(hmac_ctx); #endif return 1; } int tsig_openssl_init(region_type *region) { int count = 0; #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_digests(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); #endif count += tsig_openssl_init_algorithm(region, "md5", "hmac-md5","hmac-md5.sig-alg.reg.int."); count += tsig_openssl_init_algorithm(region, "sha1", "hmac-sha1", "hmac-sha1."); count += tsig_openssl_init_algorithm(region, "sha224", "hmac-sha224", "hmac-sha224."); count += tsig_openssl_init_algorithm(region, "sha256", "hmac-sha256", "hmac-sha256."); count += tsig_openssl_init_algorithm(region, "sha384", "hmac-sha384", "hmac-sha384."); count += tsig_openssl_init_algorithm(region, "sha512", "hmac-sha512", "hmac-sha512."); return count; } static void cleanup_context(void *data) { #ifndef HAVE_EVP_MAC_CTX_NEW HMAC_CTX *context = (HMAC_CTX *) data; #ifdef HAVE_HMAC_CTX_NEW HMAC_CTX_free(context); #else HMAC_CTX_cleanup(context); free(context); #endif #else struct tsig_openssl_context* c = (struct tsig_openssl_context*)data; EVP_MAC_CTX_free(c->hmac_ctx); c->hmac_ctx = NULL; #endif } static void * create_context(region_type *region) { #ifndef HAVE_EVP_MAC_CTX_NEW #ifdef HAVE_HMAC_CTX_NEW HMAC_CTX *context = HMAC_CTX_new(); #else HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX)); #endif region_add_cleanup(region, cleanup_context, context); #ifdef HAVE_HMAC_CTX_RESET HMAC_CTX_reset(context); #else HMAC_CTX_init(context); #endif #else struct tsig_openssl_context* context = region_alloc(region, sizeof(*context)); memset(context, 0, sizeof(*context)); region_add_cleanup(region, cleanup_context, context); #endif return context; } static void init_context(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key) { #ifndef HAVE_EVP_MAC_CTX_NEW HMAC_CTX *ctx = (HMAC_CTX *) context; const EVP_MD *md = (const EVP_MD *) algorithm->data; HMAC_Init_ex(ctx, key->data, key->size, md, NULL); #else OSSL_PARAM params[3]; struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*) algorithm->data; struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; if(c->hmac_ctx) { EVP_MAC_CTX_free(c->hmac_ctx); } c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac); if(!c->hmac_ctx) { log_msg(LOG_ERR, "could not EVP_MAC_CTX_new"); return; } params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, (char*)algo_data->digest, 0); params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, key->data, key->size); params[2] = OSSL_PARAM_construct_end(); #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params"); EVP_MAC_CTX_free(c->hmac_ctx); c->hmac_ctx = NULL; return; } #else if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params"); EVP_MAC_CTX_free(c->hmac_ctx); c->hmac_ctx = NULL; return; } #endif c->outsize = algorithm->maximum_digest_size; #endif } static void update(void *context, const void *data, size_t size) { #ifndef HAVE_EVP_MAC_CTX_NEW HMAC_CTX *ctx = (HMAC_CTX *) context; HMAC_Update(ctx, (unsigned char *) data, (int) size); #else struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_update"); } #endif } static void final(void *context, uint8_t *digest, size_t *size) { #ifndef HAVE_EVP_MAC_CTX_NEW HMAC_CTX *ctx = (HMAC_CTX *) context; unsigned len = (unsigned) *size; HMAC_Final(ctx, digest, &len); *size = (size_t) len; #else struct tsig_openssl_context* c = (struct tsig_openssl_context*)context; if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) { log_msg(LOG_ERR, "could not EVP_MAC_final"); } #endif } void tsig_openssl_finalize() { #ifdef HAVE_EVP_CLEANUP EVP_cleanup(); #endif } #endif /* defined(HAVE_SSL) */ nsd-4.12.0/systemd.m40000644000175000017500000000210715002373054013727 0ustar mozziemozzie# macros for configuring systemd # Copyright 2015, Sami Kerola, CloudFlare. # BSD licensed. AC_ARG_ENABLE([systemd], [AS_HELP_STRING([--enable-systemd], [compile with systemd support])], [], [enable_systemd=no]) have_systemd=no AS_IF([test "x$enable_systemd" != xno], [ ifdef([PKG_CHECK_MODULES], [ dnl systemd v209 or newer PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [have_systemd=yes], [have_systemd=no]) dnl old systemd library AS_IF([test "x$have_systemd" != "xyes"], [ PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon], [have_systemd_daemon=yes], [have_systemd_daemon=no]) AS_IF([test "x$have_systemd_daemon" = "xyes"], [have_systemd=yes]) ]) AS_CASE([$enable_systemd:$have_systemd], [yes:no], [AC_MSG_ERROR([systemd enabled but libsystemd not found])], [*:yes], [AC_DEFINE([HAVE_SYSTEMD], [1], [Define to 1 if systemd should be used]) LIBS="$LIBS $SYSTEMD_LIBS" ] ) ], [ AC_MSG_ERROR([systemd enabled but need pkg-config to configure for it, also, run aclocal before autoconf, or run autoreconf to include pkgconfig macros]) ]) ]) nsd-4.12.0/siphash.c0000644000175000017500000001321615002373054013603 0ustar mozziemozzie/* SipHash reference C implementation Copyright (c) 2012-2016 Jean-Philippe Aumasson Copyright (c) 2012-2014 Daniel J. Bernstein To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . */ #include #include #include #include /* default: SipHash-2-4 */ #define cROUNDS 2 #define dROUNDS 4 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) #define U32TO8_LE(p, v) \ (p)[0] = (uint8_t)((v)); \ (p)[1] = (uint8_t)((v) >> 8); \ (p)[2] = (uint8_t)((v) >> 16); \ (p)[3] = (uint8_t)((v) >> 24); #define U64TO8_LE(p, v) \ U32TO8_LE((p), (uint32_t)((v))); \ U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); #define U8TO64_LE(p) \ (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) #define SIPROUND \ do { \ v0 += v1; \ v1 = ROTL(v1, 13); \ v1 ^= v0; \ v0 = ROTL(v0, 32); \ v2 += v3; \ v3 = ROTL(v3, 16); \ v3 ^= v2; \ v0 += v3; \ v3 = ROTL(v3, 21); \ v3 ^= v0; \ v2 += v1; \ v1 = ROTL(v1, 17); \ v1 ^= v2; \ v2 = ROTL(v2, 32); \ } while (0) #ifdef DEBUG #define TRACE \ do { \ printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ (uint32_t)v0); \ printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ (uint32_t)v1); \ printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ (uint32_t)v2); \ printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ (uint32_t)v3); \ } while (0) #else #define TRACE #endif int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, uint8_t *out, const size_t outlen) { uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v1 = 0x646f72616e646f6dULL; uint64_t v2 = 0x6c7967656e657261ULL; uint64_t v3 = 0x7465646279746573ULL; uint64_t k0 = U8TO64_LE(k); uint64_t k1 = U8TO64_LE(k + 8); uint64_t m; int i; const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); const int left = inlen & 7; uint64_t b = ((uint64_t)inlen) << 56; v3 ^= k1; v2 ^= k0; v1 ^= k1; v0 ^= k0; assert((outlen == 8) || (outlen == 16)); if (outlen == 16) v1 ^= 0xee; for (; in != end; in += 8) { m = U8TO64_LE(in); v3 ^= m; TRACE; for (i = 0; i < cROUNDS; ++i) SIPROUND; v0 ^= m; } switch (left) { case 7: b |= ((uint64_t)in[6]) << 48; /* fallthrough */ case 6: b |= ((uint64_t)in[5]) << 40; /* fallthrough */ case 5: b |= ((uint64_t)in[4]) << 32; /* fallthrough */ case 4: b |= ((uint64_t)in[3]) << 24; /* fallthrough */ case 3: b |= ((uint64_t)in[2]) << 16; /* fallthrough */ case 2: b |= ((uint64_t)in[1]) << 8; /* fallthrough */ case 1: b |= ((uint64_t)in[0]); break; case 0: break; } v3 ^= b; TRACE; for (i = 0; i < cROUNDS; ++i) SIPROUND; v0 ^= b; if (outlen == 16) v2 ^= 0xee; else v2 ^= 0xff; TRACE; for (i = 0; i < dROUNDS; ++i) SIPROUND; b = v0 ^ v1 ^ v2 ^ v3; U64TO8_LE(out, b); if (outlen == 8) return 0; v1 ^= 0xdd; TRACE; for (i = 0; i < dROUNDS; ++i) SIPROUND; b = v0 ^ v1 ^ v2 ^ v3; U64TO8_LE(out + 8, b); return 0; } nsd-4.12.0/simdzone/0000755000175000017500000000000015002373060013622 5ustar mozziemozziensd-4.12.0/simdzone/config.guess0000700000175000017500000014267615002373060016150 0ustar mozziemozzie#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-08-22' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nsd-4.12.0/simdzone/config.sub0000700000175000017500000010720215002373060015575 0ustar mozziemozzie#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-09-19' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \ | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- ) ;; uclinux-uclibc*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nsd-4.12.0/simdzone/config.h.in0000644000175000017500000000446015002373060015651 0ustar mozziemozzie/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the declaration of 'bswap16', and to 0 if you don't. */ #undef HAVE_DECL_BSWAP16 /* Define to 1 if you have the declaration of 'bswap32', and to 0 if you don't. */ #undef HAVE_DECL_BSWAP32 /* Define to 1 if you have the declaration of 'bswap64', and to 0 if you don't. */ #undef HAVE_DECL_BSWAP64 /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Wether or not to compile support for AVX2 */ #undef HAVE_HASWELL /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the 'realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Wether or not to compile support for SSE4.2 */ #undef HAVE_WESTMERE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Defines _XOPEN_SOURCE and _POSIX_C_SOURCE implicitly in features.h */ #ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 #endif nsd-4.12.0/simdzone/configure0000755000175000017500000045636115002373060015550 0ustar mozziemozzie#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.72 for simdzone 0.2.2. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case e in #( e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else case e in #( e) exitcode=1; echo positional parameters were not saved. ;; esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else case e in #( e) as_have_required=no ;; esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi ;; esac fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/NLnetLabs/simdzone/issues about your $0: system, including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi ;; esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' t clear :clear s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='simdzone' PACKAGE_TARNAME='simdzone' PACKAGE_VERSION='0.2.2' PACKAGE_STRING='simdzone 0.2.2' PACKAGE_BUGREPORT='https://github.com/NLnetLabs/simdzone/issues' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS HAVE_HASWELL HAVE_WESTMERE HAVE_ENDIAN_H target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build DEPFLAGS OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_westmere enable_haswell ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: '$ac_option' Try '$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # 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 simdzone 0.2.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, 'make install' will install all the files in '$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify an installation prefix other than '$ac_default_prefix' using '--prefix', for instance '--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/simdzone] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of simdzone 0.2.2:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-westmere Disable Westmere (SSE4.2) kernel --disable-haswell Disable Haswell (AVX2) kernel Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF simdzone configure 0.2.2 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac 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 simdzone $as_me 0.2.2, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See 'config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* C89 style stringification. */ #define noexpand_stringify(a) #a const char *stringified = noexpand_stringify(arbitrary+token=sequence); /* C89 style token pasting. Exercises some of the corner cases that e.g. old MSVC gets wrong, but not very hard. */ #define noexpand_concat(a,b) a##b #define expand_concat(a,b) noexpand_concat(a,b) extern int vA; extern int vbee; #define aye A #define bee B int *pvA = &expand_concat(v,aye); int *pvbee = &noexpand_concat(v,bee); /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' /* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif // See if C++-style comments work. #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Work around memory leak warnings. free (ia); // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' /* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; esac fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" ac_config_files="$ac_config_files Makefile" # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. # So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else case e in #( e) ac_file='' ;; esac fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See 'config.log' for more details" "$LINENO" 5; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) # catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will # work properly (i.e., refer to 'conftest.exe'), while it won't with # 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); if (!f) return 1; return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use '--host'. See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext \ conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default " if test "x$ac_cv_header_endian_h" = xyes then : printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/endian.h" "ac_cv_header_sys_endian_h" "$ac_includes_default " if test "x$ac_cv_header_sys_endian_h" = xyes then : printf "%s\n" "#define HAVE_SYS_ENDIAN_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else case e in #( e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; esac fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "bswap16" "ac_cv_have_decl_bswap16" " $ac_includes_default #ifdef HAVE_ENDIAN_H #include #endif #ifdef HAVE_SYS_ENDIAN_H #include #endif " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_bswap16" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_BSWAP16 $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "bswap32" "ac_cv_have_decl_bswap32" " $ac_includes_default #ifdef HAVE_ENDIAN_H #include #endif #ifdef HAVE_SYS_ENDIAN_H #include #endif " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_bswap32" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_BSWAP32 $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "bswap64" "ac_cv_have_decl_bswap64" " $ac_includes_default #ifdef HAVE_ENDIAN_H #include #endif #ifdef HAVE_SYS_ENDIAN_H #include #endif " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_bswap64" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_BSWAP64 $ac_have_decl" >>confdefs.h # Check whether --enable-westmere was given. if test ${enable_westmere+y} then : enableval=$enable_westmere; fi case "$enable_westmere" in no) enable_westmere=no ;; yes|*) enable_westmere=yes ;; esac # Check whether --enable-haswell was given. if test ${enable_haswell+y} then : enableval=$enable_haswell; fi case "$enable_haswell" in no) enable_haswell=no ;; yes|*) enable_haswell=yes ;; esac # GCC and Clang { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -MMD" >&5 printf %s "checking whether C compiler accepts -MMD... " >&6; } if test ${ax_cv_check_cflags___MMD+y} then : printf %s "(cached) " >&6 else case e in #( e) ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -MMD" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags___MMD=yes else case e in #( e) ax_cv_check_cflags___MMD=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___MMD" >&5 printf "%s\n" "$ax_cv_check_cflags___MMD" >&6; } if test "x$ax_cv_check_cflags___MMD" = xyes then : DEPFLAGS="-MMD -MP" else case e in #( e) : ;; esac fi # Oracle Developer Studio (no -MP) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -xMMD" >&5 printf %s "checking whether C compiler accepts -xMMD... " >&6; } if test ${ax_cv_check_cflags___xMMD+y} then : printf %s "(cached) " >&6 else case e in #( e) ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -xMMD" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags___xMMD=yes else case e in #( e) ax_cv_check_cflags___xMMD=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___xMMD" >&5 printf "%s\n" "$ax_cv_check_cflags___xMMD" >&6; } if test "x$ax_cv_check_cflags___xMMD" = xyes then : DEPFLAGS="-xMMD" else case e in #( e) : ;; esac fi # Figure out the canonical target architecture. # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 printf %s "checking target system type... " >&6; } if test ${ac_cv_target+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 printf "%s\n" "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- # Multiple instruction sets may be supported by a specific architecture. # e.g. x86_64 may (or may not) support any of SSE42, AVX2 and AVX-512. The # best instruction set is automatically selected at runtime, but the compiler # may or may not support generating code for an instruction set. case "$target" in *amd64*) x86_64=yes ;; *x86_64*) x86_64=yes ;; *) x86_64=no ;; esac HAVE_WESTMERE=NO HAVE_HASWELL=NO if test $x86_64 = "yes"; then ac_fn_c_check_header_compile "$LINENO" "immintrin.h" "ac_cv_header_immintrin_h" "$ac_includes_default" if test "x$ac_cv_header_immintrin_h" = xyes then : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -march=westmere" >&5 printf %s "checking whether C compiler accepts -march=westmere... " >&6; } if test ${ax_cv_check_cflags__Werror__march_westmere+y} then : printf %s "(cached) " >&6 else case e in #( e) ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -Werror -march=westmere" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags__Werror__march_westmere=yes else case e in #( e) ax_cv_check_cflags__Werror__march_westmere=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__march_westmere" >&5 printf "%s\n" "$ax_cv_check_cflags__Werror__march_westmere" >&6; } if test "x$ax_cv_check_cflags__Werror__march_westmere" = xyes then : : else case e in #( e) : ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -march=haswell" >&5 printf %s "checking whether C compiler accepts -march=haswell... " >&6; } if test ${ax_cv_check_cflags__Werror__march_haswell+y} then : printf %s "(cached) " >&6 else case e in #( e) ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -Werror -march=haswell" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags__Werror__march_haswell=yes else case e in #( e) ax_cv_check_cflags__Werror__march_haswell=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__march_haswell" >&5 printf "%s\n" "$ax_cv_check_cflags__Werror__march_haswell" >&6; } if test "x$ax_cv_check_cflags__Werror__march_haswell" = xyes then : : else case e in #( e) : ;; esac fi # Check if the arch instruction set support includes the simd instructions. if test $enable_westmere != "no" -a \ $ax_cv_check_cflags__Werror__march_westmere = "yes" -a \ $ac_cv_header_immintrin_h = "yes" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -march=westmere works" >&5 printf %s "checking whether -march=westmere works... " >&6; } BAKCFLAGS="$CFLAGS" CFLAGS="-march=westmere $CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include #include int main(int argc, char *argv[]) { (void)argv; uint64_t popcnt = _mm_popcnt_u64((uint64_t)argc); return popcnt == 11; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : printf "%s\n" "#define HAVE_WESTMERE 1" >>confdefs.h HAVE_WESTMERE=WESTMERE { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$BAKCFLAGS" fi if test $enable_haswell != "no" -a \ $ax_cv_check_cflags__Werror__march_haswell = "yes" -a \ $ac_cv_header_immintrin_h = "yes" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -march=haswell works" >&5 printf %s "checking whether -march=haswell works... " >&6; } BAKCFLAGS="$CFLAGS" CFLAGS="-march=haswell $CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include #include int main(int argc, char *argv[]) { (void)argv; int argc32x8[8] = { argc, 0, 0, 0, 0, 0, 0, 0 }; __m256i argc256 = _mm256_loadu_si256((__m256i *)argc32x8); return _mm256_testz_si256(argc256, _mm256_set1_epi8(11)); } _ACEOF if ac_fn_c_try_compile "$LINENO" then : printf "%s\n" "#define HAVE_HASWELL 1" >>confdefs.h HAVE_HASWELL=HASWELL { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$BAKCFLAGS" fi fi for ac_func in realpath do : ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" if test "x$ac_cv_func_realpath" = xyes then : printf "%s\n" "#define HAVE_REALPATH 1" >>confdefs.h else case e in #( e) as_fn_error $? "realpath is not available" "$LINENO" 5 ;; esac fi done cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # 'ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by simdzone $as_me 0.2.2, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ '$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ simdzone config.status 0.2.2 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: '$1' Try '$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: '$1' Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nsd-4.12.0/simdzone/src/0000755000175000017500000000000015002373055014415 5ustar mozziemozziensd-4.12.0/simdzone/src/zone.c0000644000175000017500000003263615002373055015546 0ustar mozziemozzie/* * zone.c -- zone parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "config.h" #include #include #include #include #include #include #include #include #include #if _WIN32 # include #else # include #endif #include "zone.h" typedef zone_parser_t parser_t; // convenience typedef zone_file_t file_t; #include "attributes.h" #include "diagnostic.h" #if _MSC_VER # define strcasecmp(s1, s2) _stricmp(s1, s2) # define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) #else #include #endif static const char not_a_file[] = ""; #include "isadetection.h" #ifndef PATH_MAX #define PATH_MAX 4096 #endif #if HAVE_HASWELL extern int32_t zone_haswell_parse(parser_t *); #endif #if HAVE_WESTMERE extern int32_t zone_westmere_parse(parser_t *); #endif extern int32_t zone_fallback_parse(parser_t *); typedef struct kernel kernel_t; struct kernel { const char *name; uint32_t instruction_set; int32_t (*parse)(parser_t *); }; static const kernel_t kernels[] = { #if HAVE_HASWELL { "haswell", AVX2, &zone_haswell_parse }, #endif #if HAVE_WESTMERE { "westmere", SSE42|PCLMULQDQ, &zone_westmere_parse }, #endif { "fallback", DEFAULT, &zone_fallback_parse } }; diagnostic_push() msvc_diagnostic_ignored(4996) static inline const kernel_t * select_kernel(void) { const char *preferred; const uint32_t supported = detect_supported_architectures(); const size_t length = sizeof(kernels)/sizeof(kernels[0]); size_t count = 0; if ((preferred = getenv("ZONE_KERNEL"))) { for (; count < length; count++) if (strcasecmp(preferred, kernels[count].name) == 0) break; if (count == length) count = 0; } for (; count < length; count++) if ((kernels[count].instruction_set & supported) == (kernels[count].instruction_set)) return &kernels[count]; return &kernels[length - 1]; } diagnostic_pop() static int32_t parse(parser_t *parser, void *user_data) { const kernel_t *kernel; kernel = select_kernel(); assert(kernel); parser->user_data = user_data; return kernel->parse(parser); } diagnostic_push() msvc_diagnostic_ignored(4996) #if _WIN32 // The Win32 API offers PathIsRelative, but it requires linking with shlwapi. // Rewriting a relative path is not too complex, unlike correct conversion of // Windows paths in general (https://googleprojectzero.blogspot.com/2016/02/). // Rooted paths, relative or not, unc and extended paths are never resolved // relative to the includer. nonnull_all static int32_t resolve_path(const char *include, char **path) { if ((*path = _fullpath(NULL, include, 0))) return 0; return (errno == ENOMEM) ? ZONE_OUT_OF_MEMORY : ZONE_NOT_A_FILE; } #else nonnull_all static int32_t resolve_path(const char *include, char **path) { char *resolved; char buffer[PATH_MAX + 1]; if (!(resolved = realpath(include, buffer))) return (errno == ENOMEM) ? ZONE_OUT_OF_MEMORY : ZONE_NOT_A_FILE; assert(resolved == buffer); size_t length = strlen(buffer); if (!(resolved = malloc(length + 1))) return ZONE_OUT_OF_MEMORY; memcpy(resolved, buffer, length + 1); *path = resolved; return 0; } #endif nonnull((1)) static void close_file( parser_t *parser, file_t *file) { assert((file->name == not_a_file) == (file->path == not_a_file)); const bool is_string = file->name == not_a_file || file->path == not_a_file; assert(!is_string || file == &parser->first); assert(!is_string || file->handle == NULL); (void)parser; #ifndef NDEBUG const bool is_stdin = file->name && file->name != not_a_file && strcmp(file->name, "-") == 0; assert(!is_stdin || (!file->handle || file->handle == stdin)); #endif if (file->buffer.data && !is_string) free(file->buffer.data); file->buffer.data = NULL; if (file->name && file->name != not_a_file) free((char *)file->name); file->name = NULL; if (file->path && file->path != not_a_file) free((char *)file->path); file->path = NULL; // stdin is not opened, it must not be closed if (file->handle && file->handle != stdin) (void)fclose(file->handle); file->handle = NULL; } nonnull_all static void initialize_file( parser_t *parser, file_t *file) { const size_t size = offsetof(file_t, fields.head); memset(file, 0, size); if (file == &parser->first) { file->includer = NULL; memcpy(file->origin.octets, parser->options.origin.octets, parser->options.origin.length); file->origin.length = parser->options.origin.length; file->last_class = parser->options.default_class; file->dollar_ttl = parser->options.default_ttl; file->last_ttl = parser->options.default_ttl; file->ttl = file->default_ttl = &file->last_ttl; } else { assert(parser->file); file->includer = parser->file; memcpy(&file->origin, &parser->file->origin, sizeof(file->origin)); // Retain class and TTL values. file->last_class = parser->file->last_class; file->dollar_ttl = parser->file->dollar_ttl; file->last_ttl = parser->file->last_ttl; // RRs appearing after the $TTL directive that do not explicitly include // a TTL value, have their TTL set to the TTL in the $TTL directive. RRs // appearing before a $TTL directive use the last explicitly stated value. if (parser->file->default_ttl == &parser->file->last_ttl) file->ttl = file->default_ttl = &file->last_ttl; else file->ttl = file->default_ttl = &file->dollar_ttl; } file->line = 1; file->name = (char *)not_a_file; file->path = (char *)not_a_file; file->handle = NULL; file->buffer.data = NULL; file->start_of_line = true; file->end_of_file = 1; file->fields.tape[0] = NULL; file->fields.head = file->fields.tail = file->fields.tape; file->delimiters.tape[0] = NULL; file->delimiters.head = file->delimiters.tail = file->delimiters.tape; file->newlines.tape[0] = 0; file->newlines.head = file->newlines.tail = file->newlines.tape; } nonnull_all static int32_t open_file( parser_t *parser, file_t *file, const char *include, size_t length) { int32_t code; const size_t size = ZONE_WINDOW_SIZE + 1 + ZONE_BLOCK_SIZE; initialize_file(parser, file); file->path = NULL; if (!(file->name = malloc(length + 1))) return ZONE_OUT_OF_MEMORY; memcpy(file->name, include, length); file->name[length] = '\0'; if (!(file->buffer.data = malloc(size))) return (void)close_file(parser, file), ZONE_OUT_OF_MEMORY; file->buffer.data[0] = '\0'; file->buffer.size = ZONE_WINDOW_SIZE; file->end_of_file = 0; file->fields.tape[0] = &file->buffer.data[0]; file->fields.tape[1] = &file->buffer.data[0]; if(file == &parser->first && strcmp(file->name, "-") == 0) { if (!(file->path = malloc(2))) return (void)close_file(parser, file), ZONE_OUT_OF_MEMORY; file->path[0] = '-'; file->path[1] = '\0'; } else { // The file is resolved relative to the working directory. The absolute // path is used to protect against recusive includes. Not for opening the // file as file descriptors for pipes and sockets the entries will be // symoblic links whose content is the file type with the inode. // See NLnetLabs/nsd#380. if ((code = resolve_path(file->name, &file->path))) return (void)close_file(parser, file), code; } if(strcmp(file->path, "-") == 0) { file->handle = stdin; return 0; } else { if ((file->handle = fopen(file->name, "rb"))) return 0; } switch (errno) { case ENOMEM: code = ZONE_OUT_OF_MEMORY; break; case EACCES: code = ZONE_NOT_PERMITTED; break; default: code = ZONE_NOT_A_FILE; break; } close_file(parser, file); return code; } diagnostic_pop() diagnostic_push() clang_diagnostic_ignored(missing-prototypes) nonnull((1)) void zone_close_file( parser_t *parser, zone_file_t *file) { if (!file) return; close_file(parser, file); free(file); } nonnull_all int32_t zone_open_file( parser_t *parser, const char *path, size_t length, zone_file_t **file) { int32_t code; if (!(*file = malloc(sizeof(**file)))) return ZONE_OUT_OF_MEMORY; if ((code = open_file(parser, *file, path, length)) == 0) return 0; free(*file); const char *reason = NULL; switch (code) { case ZONE_OUT_OF_MEMORY: reason = "out of memory"; break; case ZONE_NOT_PERMITTED: reason = "access denied"; break; case ZONE_NOT_A_FILE: reason = "no such file"; break; } assert(reason); zone_error(parser, "Cannot open %.*s, %s", (int)length, path, reason); return code; } nonnull_all void zone_close(parser_t *parser) { assert(parser); for (zone_file_t *file = parser->file, *includer; file; file = includer) { includer = file->includer; close_file(parser, file); if (file != &parser->first) free(file); } } nonnull((1,2,3)) static int32_t initialize_parser( zone_parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, void *user_data) { if (!options->accept.callback) return ZONE_BAD_PARAMETER; if (!options->default_ttl) return ZONE_BAD_PARAMETER; if (!options->secondary && options->default_ttl > INT32_MAX) return ZONE_BAD_PARAMETER; if (!options->origin.octets || !options->origin.length) return ZONE_BAD_PARAMETER; const uint8_t *root = &options->origin.octets[options->origin.length - 1]; if (root[0] != 0) return ZONE_BAD_PARAMETER; const uint8_t *label = &options->origin.octets[0]; while (label < root) { if (root - label < label[0]) return ZONE_BAD_PARAMETER; label += label[0] + 1; } if (label != root) return ZONE_BAD_PARAMETER; const size_t size = offsetof(parser_t, file); memset(parser, 0, size); parser->options = *options; parser->user_data = user_data; parser->file = &parser->first; parser->buffers.size = buffers->size; parser->buffers.owner.active = 0; parser->buffers.owner.blocks = buffers->owner; parser->buffers.rdata.active = 0; parser->buffers.rdata.blocks = buffers->rdata; parser->owner = &parser->buffers.owner.blocks[0]; parser->owner->length = 0; parser->rdata = &parser->buffers.rdata.blocks[0]; if (!parser->options.no_includes && !parser->options.include_limit) parser->options.include_limit = 10; // arbitrary, default in NSD return 0; } int32_t zone_open( zone_parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, const char *path, void *user_data) { int32_t code; if ((code = initialize_parser(parser, options, buffers, user_data)) < 0) return code; if ((code = open_file(parser, &parser->first, path, strlen(path))) == 0) return 0; const char *reason = NULL; switch (code) { case ZONE_OUT_OF_MEMORY: reason = "out of memory"; break; case ZONE_NOT_PERMITTED: reason = "access denied"; break; case ZONE_NOT_A_FILE: reason = "no such file"; break; } assert(reason); zone_error(parser, "Cannot open %s, %s", path, reason); return code; } diagnostic_pop() int32_t zone_parse( zone_parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, const char *path, void *user_data) { int32_t code; if ((code = zone_open(parser, options, buffers, path, user_data)) < 0) return code; code = parse(parser, user_data); zone_close(parser); return code; } int32_t zone_parse_string( parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, const char *string, size_t length, void *user_data) { int32_t code; if ((code = initialize_parser(parser, options, buffers, user_data)) < 0) return code; if (!length || string[length] != '\0') return ZONE_BAD_PARAMETER; initialize_file(parser, parser->file); parser->file->buffer.data = (char *)string; parser->file->buffer.size = length; parser->file->buffer.length = length; parser->file->fields.tape[0] = &string[length]; parser->file->fields.tape[1] = &string[length]; assert(parser->file->end_of_file == 1); code = parse(parser, user_data); zone_close(parser); return code; } zone_nonnull((1,5)) static void print_message( zone_parser_t *parser, uint32_t priority, const char *file, size_t line, const char *message, void *user_data) { (void)parser; (void)user_data; assert(parser->file); FILE *output = priority == ZONE_INFO ? stdout : stderr; if (file) fprintf(output, "%s:%zu: %s\n", file, line, message); else fprintf(output, "%s\n", message); } void zone_vlog( zone_parser_t *parser, uint32_t priority, const char *format, va_list arguments); void zone_vlog( zone_parser_t *parser, uint32_t priority, const char *format, va_list arguments) { char message[2048]; int length; zone_log_t callback = print_message; if (!(priority & ~parser->options.log.mask)) return; length = vsnprintf(message, sizeof(message), format, arguments); assert(length >= 0); if ((size_t)length >= sizeof(message)) memcpy(message+(sizeof(message) - 4), "...", 3); if (parser->options.log.callback) callback = parser->options.log.callback; assert(parser->file); const char *file = parser->file->name; const size_t line = parser->file->line; callback(parser, priority, file, line, message, parser->user_data); } void zone_log( zone_parser_t *parser, uint32_t priority, const char *format, ...) { va_list arguments; va_start(arguments, format); zone_vlog(parser, priority, format, arguments); va_end(arguments); } nsd-4.12.0/simdzone/src/westmere/0000755000175000017500000000000015002373055016250 5ustar mozziemozziensd-4.12.0/simdzone/src/westmere/type.h0000644000175000017500000001452115002373055017405 0ustar mozziemozzie/* * type.h -- SSE4.1 RRTYPE parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TYPE_H #define TYPE_H #define V(code) { &(types[0].name), 0 } #define T(code) { &(types[code].name), 1 } #define C(code) { &(classes[code].name), 2 } // map hash to type or class descriptor (generated using hash.c) static const struct { const mnemonic_t *mnemonic; int32_t code; } types_and_classes[256] = { V(0), V(0), V(0), V(0), V(0), V(0), T(34), V(0), V(0), V(0), T(30), V(0), V(0), T(57), V(0), T(16), V(0), V(0), T(56), T(14), T(12), V(0), V(0), T(13), T(61), V(0), T(105), V(0), V(0), V(0), T(32), T(258), V(0), T(107), T(47), V(0), V(0), V(0), T(17), V(0), T(257), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(65), V(0), V(0), T(18), V(0), T(1), V(0), T(263), V(0), V(0), V(0), V(0), T(51), V(0), V(0), T(106), T(3), V(0), V(0), T(31), V(0), V(0), V(0), V(0), V(0), T(50), T(44), T(104), T(10), V(0), V(0), V(0), V(0), V(0), T(55), V(0), T(28), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(39), T(35), V(0), V(0), T(5), T(29), T(262), V(0), V(0), T(109), V(0), T(264), V(0), V(0), V(0), V(0), V(0), V(0), T(21), V(0), V(0), V(0), V(0), V(0), V(0), T(37), C(1), T(58), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), C(3), V(0), T(52), T(11), T(20), V(0), T(261), V(0), V(0), V(0), T(48), V(0), V(0), V(0), T(25), C(2), T(43), V(0), V(0), C(4), T(60), V(0), V(0), T(7), T(2), V(0), V(0), T(46), T(22), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(64), V(0), T(260), V(0), V(0), V(0), V(0), T(38), V(0), V(0), T(259), T(59), V(0), V(0), V(0), T(42), T(36), T(8), T(15), V(0), T(26), T(27), T(6), V(0), T(99), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(53), T(9), T(63), T(33), V(0), T(271), T(270), V(0), T(40), V(0), V(0), T(24), T(19), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(108), V(0), V(0), V(0), T(62), V(0), V(0), V(0), V(0), V(0), T(66), T(4), V(0), V(0), V(0), T(256), V(0), T(49), V(0), V(0), V(0), V(0), V(0), T(45), V(0), V(0), T(23), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) }; #undef V #undef T #undef C nonnull_all static really_inline int32_t scan_generic_type( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { if (scan_int16(data + 4, length - 4, code) == 0) return -1; if (*code <= 258) *mnemonic = &types[*code].name; else if (*code == 32769) *mnemonic = &types[259].name; else *mnemonic = &types[0].name; return 1; } nonnull_all static really_inline int32_t scan_generic_class( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { if (scan_int16(data + 5, length - 5, code) == 0) return -1; if (*code <= 4) *mnemonic = &classes[*code].name; else *mnemonic = &classes[0].name; return 2; } #define TYPE (0x45505954llu) #define TYPE_MASK (0xffffffffllu) #define CLASS (0x5353414c43llu) #define CLASS_MASK (0xffffffffffllu) static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static really_inline uint8_t hash(uint64_t prefix) { uint32_t value = (uint32_t)((prefix >> 32) ^ prefix); // magic value is generated using hash.c, rerun when adding types return (uint8_t)((value * 3537259401ull) >> 32); } nonnull_all static really_inline int32_t scan_type_or_class( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { __m128i input = _mm_loadu_si128((const __m128i *)data); const __m128i letter_mask = _mm_srli_epi32(_mm_and_si128(input, _mm_set1_epi8(0x40)), 1); // convert to upper case input = _mm_andnot_si128(letter_mask, input); // sanitize input const __m128i zero_mask = _mm_loadu_si128((const __m128i *)&zero_masks[32 - (length & 0x1f)]); input = _mm_and_si128(input, zero_mask); // input is now sanitized and upper case const uint64_t prefix = (uint64_t)_mm_cvtsi128_si64(input); const uint8_t index = hash(prefix); *code = (uint16_t)types_and_classes[index].mnemonic->value; *mnemonic = types_and_classes[index].mnemonic; const __m128i compar = _mm_loadu_si128((const __m128i *)(*mnemonic)->key.data); const __m128i xorthem = _mm_xor_si128(compar, input); if (likely(_mm_test_all_zeros(xorthem, xorthem))) return types_and_classes[index].code; else if ((prefix & TYPE_MASK) == TYPE) return scan_generic_type(data, length, code, mnemonic); else if ((prefix & CLASS_MASK) == CLASS) return scan_generic_class(data, length, code, mnemonic); return 0; } nonnull_all static really_inline int32_t scan_type( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { __m128i input = _mm_loadu_si128((const __m128i *)data); const __m128i letter_mask = _mm_srli_epi32(_mm_and_si128(input, _mm_set1_epi8(0x40)), 1); // convert to upper case input = _mm_andnot_si128(letter_mask, input); // sanitize input const __m128i zero_mask = _mm_loadu_si128((const __m128i *)&zero_masks[32 - (length & 0x1f)]); input = _mm_and_si128(input, zero_mask); // input is now sanitized and upper case const uint64_t prefix = (uint64_t)_mm_cvtsi128_si64(input); const uint8_t index = hash(prefix); *code = (uint16_t)types_and_classes[index].mnemonic->value; *mnemonic = types_and_classes[index].mnemonic; const __m128i compar = _mm_loadu_si128((const __m128i *)(*mnemonic)->key.data); const __m128i xorthem = _mm_xor_si128(compar, input); // FIXME: make sure length matches too! if (likely(_mm_test_all_zeros(xorthem, xorthem))) return types_and_classes[index].code == 1; else if ((prefix & TYPE_MASK) == TYPE) return scan_generic_type(data, length, code, mnemonic); return 0; } #undef TYPE #undef TYPE_MASK #undef CLASS #undef CLASS_MASK #endif // TYPE_H nsd-4.12.0/simdzone/src/westmere/time.h0000644000175000017500000001241315002373055017360 0ustar mozziemozzie/* * ip4.h -- SSE 4.1 parser for time stamps * https://lemire.me/blog/2023/07/01/parsing-time-stamps-faster-with-simd-instructions/ * * Copyright (c) 2023. Daniel Lemire * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef SSE_TIME_H #define SSE_TIME_H static const int mdays_minus_one[] = {30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30}; static const int mdays_cumulative[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; /* The 32-bit timestamp spans from year 1970 to 2106. Therefore, the only special case for leap years is 2100. We use that to produce fast functions. */ static inline uint32_t is_leap_year(uint32_t year) { return (year % 4 == 0) & (year != 2100); } static inline uint32_t leap_days(uint32_t year) { --year; return (year/4 - 1970/4) - (year >= 2100); } static bool sse_parse_time(const char *date_string, uint32_t *time_in_second) { // We load the block of digits. We subtract 0x30 (the code point value of the // character '0'), and all bytes values should be between 0 and 9, // inclusively. We know that some character must be smaller that 9, for // example, we cannot have more than 59 seconds and never 60 seconds, in the // time stamp string. So one character must be between 0 and 5. Similarly, we // start the hours at 00 and end at 23, so one character must be between 0 // and 2. We do a saturating subtraction of the maximum: the result of such a // subtraction should be zero if the value is no larger. We then use a special // instruction to multiply one byte by 10, and sum it up with the next byte, // getting a 16-bit value. We then repeat the same approach as before, // checking that the result is not too large. // // We compute the month the good old ways, as an integer in [0,11], we // check for overflows later. uint64_t mo = (uint64_t)((date_string[4]-0x30)*10 + (date_string[5]-0x30) - 1); __m128i v = _mm_loadu_si128((const __m128i *)date_string); // loaded YYYYMMDDHHmmSS..... v = _mm_xor_si128(v, _mm_set1_epi8(0x30)); // W can use _mm_sub_epi8 or _mm_xor_si128 for the subtraction above. // subtracting by 0x30 (or '0'), turns all values into a byte value between 0 // and 9 if the initial input was made of digits. __m128i limit = _mm_setr_epi8(9, 9, 9, 9, 1, 9, 3, 9, 2, 9, 5, 9, 5, 9, -1, -1); // credit @aqrit // overflows are still possible, if hours are in the range 24 to 29 // of if days are in the range 32 to 39 // or if months are in the range 12 to 19. __m128i abide_by_limits = _mm_subs_epu8(v, limit); // must be all zero #if defined __SUNPRO_C __m128i byteflip = _mm_setr_epi64((__m64){0x0607040502030001ULL}, (__m64){0x0e0f0c0d0a0b0809ULL}); #else __m128i byteflip = _mm_setr_epi64((__m64)0x0607040502030001ULL, (__m64)0x0e0f0c0d0a0b0809ULL); #endif __m128i little_endian = _mm_shuffle_epi8(v, byteflip); __m128i limit16 = _mm_setr_epi16(0x0909, 0x0909, 0x0102, 0x0301, 0x0203, 0x0509, 0x0509, -1); __m128i abide_by_limits16 = _mm_subs_epu16(little_endian, limit16); // must be all zero __m128i combined_limits = _mm_or_si128(abide_by_limits16, abide_by_limits); // must be all zero if (!_mm_test_all_zeros(combined_limits, combined_limits)) { return false; } // 0x000000SS0mmm0HHH`00DD00MM00YY00YY ////////////////////////////////////////////////////// // pmaddubsw has a high latency (e.g., 5 cycles) and is // likely a performance bottleneck. ///////////////////////////////////////////////////// const __m128i weights = _mm_setr_epi8( // Y Y Y Y m m d d H H M M S S - - 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 0, 0); v = _mm_maddubs_epi16(v, weights); uint64_t hi = (uint64_t)_mm_extract_epi64(v, 1); uint64_t seconds = (hi * 0x0384000F00004000) >> 46; uint64_t lo = (uint64_t)_mm_extract_epi64(v, 0); uint64_t yr = (lo * 0x64000100000000) >> 48; // We compute the day (starting at zero). We implicitly // check for overflows later. uint64_t dy = (uint64_t)_mm_extract_epi8(v, 6) - 1; bool is_leap_yr = (bool)is_leap_year((uint32_t)yr); if(yr < 1970 || mo > 11) { return false; } // unlikely branch if (dy > (uint64_t)mdays_minus_one[mo]) { // unlikely branch if (mo == 1 && is_leap_yr) { if (dy != 29 - 1) { return false; } } else { return false; } } uint64_t days = 365 * (yr - 1970) + (uint64_t)leap_days((uint32_t)yr); days += (uint64_t)mdays_cumulative[mo]; days += is_leap_yr & (mo > 1); days += dy; uint64_t time_in_second64 = seconds + days * 60 * 60 * 24; *time_in_second = (uint32_t)time_in_second64; return true; } nonnull_all static really_inline int32_t parse_time( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint32_t time; if (unlikely(token->length != 14)) return parse_int32(parser, type, field, rdata, token); if (!sse_parse_time(token->data, &time)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); time = htobe32(time); memcpy(rdata->octets, &time, sizeof(time)); rdata->octets += sizeof(time); return 0; } #endif // TIME_H nsd-4.12.0/simdzone/src/westmere/simd.h0000644000175000017500000001062215002373055017356 0ustar mozziemozzie/* * simd.h -- SIMD abstractions targeting SSE4.2 * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef SIMD_H #define SIMD_H #include #include #define SIMD_8X_SIZE (16) typedef uint8_t simd_table_t[SIMD_8X_SIZE]; #define SIMD_TABLE(v00, v01, v02, v03, v04, v05, v06, v07, \ v08, v09, v0a, v0b, v0c, v0d, v0e, v0f) \ { \ v00, v01, v02, v03, v04, v05, v06, v07, \ v08, v09, v0a, v0b, v0c, v0d, v0e, v0f \ } typedef struct { __m128i chunks[1]; } simd_8x_t; typedef simd_8x_t simd_8x16_t; typedef struct { __m128i chunks[2]; } simd_8x32_t; typedef struct { __m128i chunks[4]; } simd_8x64_t; nonnull_all static really_inline void simd_loadu_8x(simd_8x_t *simd, const uint8_t *address) { simd->chunks[0] = _mm_loadu_si128((const __m128i *)address); } nonnull_all static really_inline void simd_storeu_8x(uint8_t *address, const simd_8x_t *simd) { _mm_storeu_si128((__m128i *)address, simd->chunks[0]); } nonnull_all static really_inline uint64_t simd_find_8x(const simd_8x_t *simd, char key) { const __m128i k = _mm_set1_epi8(key); const __m128i r = _mm_cmpeq_epi8(simd->chunks[0], k); return (uint16_t)_mm_movemask_epi8(r); } nonnull_all static really_inline uint64_t simd_find_any_8x( const simd_8x_t *simd, const simd_table_t table) { const __m128i t = _mm_loadu_si128((const __m128i *)table); const __m128i r = _mm_cmpeq_epi8( _mm_shuffle_epi8(t, simd->chunks[0]), simd->chunks[0]); return (uint16_t)_mm_movemask_epi8(r); } #define simd_loadu_8x16(simd, address) simd_loadu_8x(simd, address) #define simd_find_8x16(simd, key) simd_find_8x(simd, key) nonnull_all static really_inline void simd_loadu_8x32(simd_8x32_t *simd, const char *address) { simd->chunks[0] = _mm_loadu_si128((const __m128i *)(address)); simd->chunks[1] = _mm_loadu_si128((const __m128i *)(address+16)); } nonnull_all static really_inline void simd_storeu_8x32(uint8_t *address, const simd_8x32_t *simd) { _mm_storeu_si128((__m128i *)(address), simd->chunks[0]); _mm_storeu_si128((__m128i *)(address+16), simd->chunks[1]); } nonnull_all static really_inline uint64_t simd_find_8x32(const simd_8x32_t *simd, char key) { const __m128i k = _mm_set1_epi8(key); const __m128i r0 = _mm_cmpeq_epi8(simd->chunks[0], k); const __m128i r1 = _mm_cmpeq_epi8(simd->chunks[1], k); const uint32_t m0 = (uint16_t)_mm_movemask_epi8(r0); const uint32_t m1 = (uint16_t)_mm_movemask_epi8(r1); return m0 | (m1 << 16); } nonnull_all static really_inline void simd_loadu_8x64(simd_8x64_t *simd, const uint8_t *address) { simd->chunks[0] = _mm_loadu_si128((const __m128i *)(address)); simd->chunks[1] = _mm_loadu_si128((const __m128i *)(address+16)); simd->chunks[2] = _mm_loadu_si128((const __m128i *)(address+32)); simd->chunks[3] = _mm_loadu_si128((const __m128i *)(address+48)); } nonnull_all static really_inline uint64_t simd_find_8x64(const simd_8x64_t *simd, char key) { const __m128i k = _mm_set1_epi8(key); const __m128i r0 = _mm_cmpeq_epi8(simd->chunks[0], k); const __m128i r1 = _mm_cmpeq_epi8(simd->chunks[1], k); const __m128i r2 = _mm_cmpeq_epi8(simd->chunks[2], k); const __m128i r3 = _mm_cmpeq_epi8(simd->chunks[3], k); const uint64_t m0 = (uint16_t)_mm_movemask_epi8(r0); const uint64_t m1 = (uint16_t)_mm_movemask_epi8(r1); const uint64_t m2 = (uint16_t)_mm_movemask_epi8(r2); const uint64_t m3 = (uint16_t)_mm_movemask_epi8(r3); return m0 | (m1 << 16) | (m2 << 32) | (m3 << 48); } nonnull_all static really_inline uint64_t simd_find_any_8x64( const simd_8x64_t *simd, const simd_table_t table) { const __m128i t = _mm_loadu_si128((const __m128i *)table); const __m128i r0 = _mm_cmpeq_epi8( _mm_shuffle_epi8(t, simd->chunks[0]), simd->chunks[0]); const __m128i r1 = _mm_cmpeq_epi8( _mm_shuffle_epi8(t, simd->chunks[1]), simd->chunks[1]); const __m128i r2 = _mm_cmpeq_epi8( _mm_shuffle_epi8(t, simd->chunks[2]), simd->chunks[2]); const __m128i r3 = _mm_cmpeq_epi8( _mm_shuffle_epi8(t, simd->chunks[3]), simd->chunks[3]); const uint64_t m0 = (uint16_t)_mm_movemask_epi8(r0); const uint64_t m1 = (uint16_t)_mm_movemask_epi8(r1); const uint64_t m2 = (uint16_t)_mm_movemask_epi8(r2); const uint64_t m3 = (uint16_t)_mm_movemask_epi8(r3); return m0 | (m1 << 16) | (m2 << 32) | (m3 << 48); } #endif // SIMD_H nsd-4.12.0/simdzone/src/westmere/parser.c0000644000175000017500000000236415002373055017715 0ustar mozziemozzie/* * parser.c -- SSE4.2 specific compilation target for (DNS) zone file parser * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause. * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "westmere/simd.h" #include "generic/endian.h" #include "westmere/bits.h" #include "generic/parser.h" #include "generic/scanner.h" #include "generic/number.h" #include "generic/ttl.h" #include "westmere/time.h" #include "westmere/ip4.h" #include "generic/ip6.h" #include "generic/text.h" #include "generic/name.h" #include "generic/base16.h" #include "westmere/base32.h" #include "generic/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" #include "generic/ilnp64.h" #include "generic/eui.h" #include "generic/nsap.h" #include "generic/wks.h" #include "generic/loc.h" #include "generic/gpos.h" #include "generic/apl.h" #include "generic/svcb.h" #include "generic/cert.h" #include "generic/atma.h" #include "generic/algorithm.h" #include "generic/types.h" #include "westmere/type.h" #include "generic/format.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_westmere_parse(parser_t *parser) { return parse(parser); } diagnostic_pop() nsd-4.12.0/simdzone/src/westmere/ip4.h0000644000175000017500000002431115002373055017116 0ustar mozziemozzie/* * ip4.h -- SSE 4.1 parser for IPv4 addresses * https://lemire.me/blog/2023/06/08/parsing-ip-addresses-crazily-fast/ * * Copyright (c) 2023. Daniel Lemire * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef IP4_H #define IP4_H static const uint8_t patterns_id[256] = { 38, 65, 255, 56, 73, 255, 255, 255, 255, 255, 255, 3, 255, 255, 6, 255, 255, 9, 255, 27, 255, 12, 30, 255, 255, 255, 255, 15, 255, 33, 255, 255, 255, 255, 18, 36, 255, 255, 255, 54, 21, 255, 39, 255, 255, 57, 255, 255, 255, 255, 255, 255, 255, 255, 24, 42, 255, 255, 255, 60, 255, 255, 255, 255, 255, 255, 255, 255, 45, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 48, 53, 255, 255, 66, 71, 255, 255, 16, 255, 34, 255, 255, 255, 255, 255, 255, 255, 52, 255, 255, 22, 70, 40, 255, 255, 58, 51, 255, 255, 69, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 255, 255, 255, 255, 255, 255, 11, 29, 46, 255, 255, 64, 255, 255, 72, 0, 77, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 76, 255, 255, 255, 255, 255, 255, 255, 75, 255, 80, 255, 255, 255, 26, 255, 44, 255, 7, 62, 255, 255, 25, 255, 43, 13, 31, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 19, 37, 255, 255, 50, 55, 79, 68, 255, 255, 255, 255, 49, 255, 255, 67, 255, 255, 255, 255, 17, 255, 35, 78, 255, 4, 255, 255, 255, 255, 255, 255, 10, 23, 28, 41, 255, 255, 59, 255, 255, 255, 8, 255, 255, 255, 255, 255, 1, 14, 32, 255, 255, 255, 255, 255, 255, 255, 255, 74, 255, 47, 20, }; static const uint8_t patterns[81][16] = { {0, 128, 2, 128, 4, 128, 6, 128, 128, 128, 128, 128, 128, 128, 128, 128}, {0, 128, 2, 128, 4, 128, 7, 6, 128, 128, 128, 128, 128, 128, 128, 6}, {0, 128, 2, 128, 4, 128, 8, 7, 128, 128, 128, 128, 128, 128, 6, 6}, {0, 128, 2, 128, 5, 4, 7, 128, 128, 128, 128, 128, 128, 4, 128, 128}, {0, 128, 2, 128, 5, 4, 8, 7, 128, 128, 128, 128, 128, 4, 128, 7}, {0, 128, 2, 128, 5, 4, 9, 8, 128, 128, 128, 128, 128, 4, 7, 7}, {0, 128, 2, 128, 6, 5, 8, 128, 128, 128, 128, 128, 4, 4, 128, 128}, {0, 128, 2, 128, 6, 5, 9, 8, 128, 128, 128, 128, 4, 4, 128, 8}, {0, 128, 2, 128, 6, 5, 10, 9, 128, 128, 128, 128, 4, 4, 8, 8}, {0, 128, 3, 2, 5, 128, 7, 128, 128, 128, 128, 2, 128, 128, 128, 128}, {0, 128, 3, 2, 5, 128, 8, 7, 128, 128, 128, 2, 128, 128, 128, 7}, {0, 128, 3, 2, 5, 128, 9, 8, 128, 128, 128, 2, 128, 128, 7, 7}, {0, 128, 3, 2, 6, 5, 8, 128, 128, 128, 128, 2, 128, 5, 128, 128}, {0, 128, 3, 2, 6, 5, 9, 8, 128, 128, 128, 2, 128, 5, 128, 8}, {0, 128, 3, 2, 6, 5, 10, 9, 128, 128, 128, 2, 128, 5, 8, 8}, {0, 128, 3, 2, 7, 6, 9, 128, 128, 128, 128, 2, 5, 5, 128, 128}, {0, 128, 3, 2, 7, 6, 10, 9, 128, 128, 128, 2, 5, 5, 128, 9}, {0, 128, 3, 2, 7, 6, 11, 10, 128, 128, 128, 2, 5, 5, 9, 9}, {0, 128, 4, 3, 6, 128, 8, 128, 128, 128, 2, 2, 128, 128, 128, 128}, {0, 128, 4, 3, 6, 128, 9, 8, 128, 128, 2, 2, 128, 128, 128, 8}, {0, 128, 4, 3, 6, 128, 10, 9, 128, 128, 2, 2, 128, 128, 8, 8}, {0, 128, 4, 3, 7, 6, 9, 128, 128, 128, 2, 2, 128, 6, 128, 128}, {0, 128, 4, 3, 7, 6, 10, 9, 128, 128, 2, 2, 128, 6, 128, 9}, {0, 128, 4, 3, 7, 6, 11, 10, 128, 128, 2, 2, 128, 6, 9, 9}, {0, 128, 4, 3, 8, 7, 10, 128, 128, 128, 2, 2, 6, 6, 128, 128}, {0, 128, 4, 3, 8, 7, 11, 10, 128, 128, 2, 2, 6, 6, 128, 10}, {0, 128, 4, 3, 8, 7, 12, 11, 128, 128, 2, 2, 6, 6, 10, 10}, {1, 0, 3, 128, 5, 128, 7, 128, 128, 0, 128, 128, 128, 128, 128, 128}, {1, 0, 3, 128, 5, 128, 8, 7, 128, 0, 128, 128, 128, 128, 128, 7}, {1, 0, 3, 128, 5, 128, 9, 8, 128, 0, 128, 128, 128, 128, 7, 7}, {1, 0, 3, 128, 6, 5, 8, 128, 128, 0, 128, 128, 128, 5, 128, 128}, {1, 0, 3, 128, 6, 5, 9, 8, 128, 0, 128, 128, 128, 5, 128, 8}, {1, 0, 3, 128, 6, 5, 10, 9, 128, 0, 128, 128, 128, 5, 8, 8}, {1, 0, 3, 128, 7, 6, 9, 128, 128, 0, 128, 128, 5, 5, 128, 128}, {1, 0, 3, 128, 7, 6, 10, 9, 128, 0, 128, 128, 5, 5, 128, 9}, {1, 0, 3, 128, 7, 6, 11, 10, 128, 0, 128, 128, 5, 5, 9, 9}, {1, 0, 4, 3, 6, 128, 8, 128, 128, 0, 128, 3, 128, 128, 128, 128}, {1, 0, 4, 3, 6, 128, 9, 8, 128, 0, 128, 3, 128, 128, 128, 8}, {1, 0, 4, 3, 6, 128, 10, 9, 128, 0, 128, 3, 128, 128, 8, 8}, {1, 0, 4, 3, 7, 6, 9, 128, 128, 0, 128, 3, 128, 6, 128, 128}, {1, 0, 4, 3, 7, 6, 10, 9, 128, 0, 128, 3, 128, 6, 128, 9}, {1, 0, 4, 3, 7, 6, 11, 10, 128, 0, 128, 3, 128, 6, 9, 9}, {1, 0, 4, 3, 8, 7, 10, 128, 128, 0, 128, 3, 6, 6, 128, 128}, {1, 0, 4, 3, 8, 7, 11, 10, 128, 0, 128, 3, 6, 6, 128, 10}, {1, 0, 4, 3, 8, 7, 12, 11, 128, 0, 128, 3, 6, 6, 10, 10}, {1, 0, 5, 4, 7, 128, 9, 128, 128, 0, 3, 3, 128, 128, 128, 128}, {1, 0, 5, 4, 7, 128, 10, 9, 128, 0, 3, 3, 128, 128, 128, 9}, {1, 0, 5, 4, 7, 128, 11, 10, 128, 0, 3, 3, 128, 128, 9, 9}, {1, 0, 5, 4, 8, 7, 10, 128, 128, 0, 3, 3, 128, 7, 128, 128}, {1, 0, 5, 4, 8, 7, 11, 10, 128, 0, 3, 3, 128, 7, 128, 10}, {1, 0, 5, 4, 8, 7, 12, 11, 128, 0, 3, 3, 128, 7, 10, 10}, {1, 0, 5, 4, 9, 8, 11, 128, 128, 0, 3, 3, 7, 7, 128, 128}, {1, 0, 5, 4, 9, 8, 12, 11, 128, 0, 3, 3, 7, 7, 128, 11}, {1, 0, 5, 4, 9, 8, 13, 12, 128, 0, 3, 3, 7, 7, 11, 11}, {2, 1, 4, 128, 6, 128, 8, 128, 0, 0, 128, 128, 128, 128, 128, 128}, {2, 1, 4, 128, 6, 128, 9, 8, 0, 0, 128, 128, 128, 128, 128, 8}, {2, 1, 4, 128, 6, 128, 10, 9, 0, 0, 128, 128, 128, 128, 8, 8}, {2, 1, 4, 128, 7, 6, 9, 128, 0, 0, 128, 128, 128, 6, 128, 128}, {2, 1, 4, 128, 7, 6, 10, 9, 0, 0, 128, 128, 128, 6, 128, 9}, {2, 1, 4, 128, 7, 6, 11, 10, 0, 0, 128, 128, 128, 6, 9, 9}, {2, 1, 4, 128, 8, 7, 10, 128, 0, 0, 128, 128, 6, 6, 128, 128}, {2, 1, 4, 128, 8, 7, 11, 10, 0, 0, 128, 128, 6, 6, 128, 10}, {2, 1, 4, 128, 8, 7, 12, 11, 0, 0, 128, 128, 6, 6, 10, 10}, {2, 1, 5, 4, 7, 128, 9, 128, 0, 0, 128, 4, 128, 128, 128, 128}, {2, 1, 5, 4, 7, 128, 10, 9, 0, 0, 128, 4, 128, 128, 128, 9}, {2, 1, 5, 4, 7, 128, 11, 10, 0, 0, 128, 4, 128, 128, 9, 9}, {2, 1, 5, 4, 8, 7, 10, 128, 0, 0, 128, 4, 128, 7, 128, 128}, {2, 1, 5, 4, 8, 7, 11, 10, 0, 0, 128, 4, 128, 7, 128, 10}, {2, 1, 5, 4, 8, 7, 12, 11, 0, 0, 128, 4, 128, 7, 10, 10}, {2, 1, 5, 4, 9, 8, 11, 128, 0, 0, 128, 4, 7, 7, 128, 128}, {2, 1, 5, 4, 9, 8, 12, 11, 0, 0, 128, 4, 7, 7, 128, 11}, {2, 1, 5, 4, 9, 8, 13, 12, 0, 0, 128, 4, 7, 7, 11, 11}, {2, 1, 6, 5, 8, 128, 10, 128, 0, 0, 4, 4, 128, 128, 128, 128}, {2, 1, 6, 5, 8, 128, 11, 10, 0, 0, 4, 4, 128, 128, 128, 10}, {2, 1, 6, 5, 8, 128, 12, 11, 0, 0, 4, 4, 128, 128, 10, 10}, {2, 1, 6, 5, 9, 8, 11, 128, 0, 0, 4, 4, 128, 8, 128, 128}, {2, 1, 6, 5, 9, 8, 12, 11, 0, 0, 4, 4, 128, 8, 128, 11}, {2, 1, 6, 5, 9, 8, 13, 12, 0, 0, 4, 4, 128, 8, 11, 11}, {2, 1, 6, 5, 10, 9, 12, 128, 0, 0, 4, 4, 8, 8, 128, 128}, {2, 1, 6, 5, 10, 9, 13, 12, 0, 0, 4, 4, 8, 8, 128, 12}, {2, 1, 6, 5, 10, 9, 14, 13, 0, 0, 4, 4, 8, 8, 12, 12}, }; // convert IPv4 from text to binary form. // // ipv4_string points to a character string containing an IPv4 network address in dotted-decimal format // "ddd.ddd.ddd.ddd" of length ipv4_string_length (the string does not have to be null terminated), // where ddd is a decimal number of up to three digits in the range 0 to 255. // The address is converted to a 32-bit integer (destination) (in network byte order). // // Important: the function will systematically read 16 bytes at the provided address (ipv4_string). We infer // the network address size in bytes by looking for a sequence of dots and decimal digits. // // returns 1 on success (network address was successfully converted). // // This function assumes that the processor supports SSE 4.1 instructions or better. That's true of most // processors in operation today (June 2023). static inline int sse_inet_aton(const char* ipv4_string, uint8_t* destination, size_t* restrict ipv4_string_length) { __m128i v = _mm_loadu_si128((const __m128i *)ipv4_string); __m128i is_dot = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x2E)); uint32_t dot_mask = (uint32_t)_mm_movemask_epi8(is_dot); // set non-digits to 0x80..0x89, set digits to 0x00..0x09 const __m128i saturation_distance = _mm_set1_epi8(0x76); // 0x7F - 9 v = _mm_xor_si128(v, _mm_set1_epi8(0x30)); // ascii '0' v = _mm_adds_epu8(v, saturation_distance); uint32_t non_digit_mask = (uint32_t)_mm_movemask_epi8(v); v = _mm_subs_epi8(v, saturation_distance); uint32_t bad_mask = dot_mask ^ non_digit_mask; uint32_t clip_mask = bad_mask ^ (bad_mask - 1); uint32_t partition_mask = non_digit_mask & clip_mask; const uint32_t length = (uint32_t)count_ones(clip_mask) - 1; uint32_t hash_key = (partition_mask * 0x00CF7800) >> 24; uint8_t hash_id = patterns_id[hash_key]; if (hash_id >= 81) return 0; const uint8_t* const pattern_ptr = &patterns[hash_id][0]; __m128i shuf = _mm_loadu_si128((const __m128i *)pattern_ptr); v = _mm_shuffle_epi8(v, shuf); const __m128i mul_weights = _mm_set_epi8(0,100, 0,100, 0,100, 0,100, 10,1, 10,1, 10,1, 10,1); __m128i acc = _mm_maddubs_epi16(mul_weights, v); __m128i swapped = _mm_shuffle_epi32(acc, _MM_SHUFFLE(1,0,3,2)); acc = _mm_adds_epu16(acc, swapped); // check `v` for leading zeros in each partition, ignore lanes if partition has only one digit // if hibyte of `acc` then bad_char or overflow __m128i check_lz = _mm_xor_si128(_mm_cmpeq_epi8(_mm_setzero_si128(), v), shuf); __m128i check_of = _mm_adds_epu16(_mm_set1_epi16(0x7F00), acc); __m128i checks = _mm_or_si128(check_lz, check_of); uint32_t check_mask = (uint32_t)_mm_movemask_epi8(checks); check_mask &= 0x0000AA00; // the only lanes wanted // pack and we are done! uint32_t address = (uint32_t)_mm_cvtsi128_si32(_mm_packus_epi16(acc, acc)); *ipv4_string_length = length; memcpy(destination, &address, 4); return (int)(length + check_mask - pattern_ptr[6]); } nonnull_all static really_inline int32_t scan_ip4(const char *text, uint8_t *wire) { size_t len; if (sse_inet_aton(text, wire, &len) != 1) return 0; return (int32_t)len; } nonnull_all static really_inline int32_t parse_ip4( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { // Note that this assumes that reading up to token->data + 16 is safe (i.e., we do not cross a page). if ((size_t)scan_ip4(token->data, rdata->octets) != token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets += 4; return 0; } #endif // IP4_H nsd-4.12.0/simdzone/src/westmere/bits.h0000644000175000017500000000327115002373055017365 0ustar mozziemozzie/* * bits.h -- Westmere specific implementation of bit manipulation instructions * * Copyright (c) 2018-2022 The simdjson authors * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BITS_H #define BITS_H #include #include #include static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { #if has_builtin(__builtin_uaddll_overflow) return __builtin_uaddll_overflow(value1, value2, (unsigned long long *)result); #else *result = value1 + value2; return *result < value1; #endif } static inline uint64_t count_ones(uint64_t input_num) { return (uint64_t)_mm_popcnt_u64(input_num); } no_sanitize_undefined static inline uint64_t trailing_zeroes(uint64_t mask) { #if has_builtin(__builtin_ctzll) return (uint64_t)__builtin_ctzll(mask); #else uint64_t result; asm("bsfq %[mask], %[result]" : [result] "=r" (result) : [mask] "mr" (mask)); return result; #endif } // result might be undefined when input_num is zero static inline uint64_t clear_lowest_bit(uint64_t input_num) { return input_num & (input_num-1); } static inline uint64_t leading_zeroes(uint64_t mask) { #if has_builtin(__builtin_clzll) return (uint64_t)__builtin_clzll(mask); #else uint64_t result; asm("bsrq %[mask], %[result]" : [result] "=r" (result) : [mask] "mr" (mask)); return 63 ^ (int)result; #endif } static inline uint64_t prefix_xor(const uint64_t bitmask) { __m128i all_ones = _mm_set1_epi8('\xFF'); __m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, (long long)bitmask), all_ones, 0); return (uint64_t)_mm_cvtsi128_si64(result); } #endif // BITS_H nsd-4.12.0/simdzone/src/westmere/bench.c0000644000175000017500000000124615002373055017476 0ustar mozziemozzie/* * bench.c -- SSE4.2 compilation target for benchmark function(s) * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "westmere/simd.h" #include "westmere/bits.h" #include "generic/parser.h" #include "generic/scanner.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_bench_westmere_lex(zone_parser_t *parser, size_t *tokens) { token_t token; (*tokens) = 0; take(parser, &token); while (token.code > 0) { (*tokens)++; take(parser, &token); } return token.code ? -1 : 0; } diagnostic_pop() nsd-4.12.0/simdzone/src/westmere/base32.h0000644000175000017500000000557615002373055017515 0ustar mozziemozzie/* * base32.h -- Fast Base32 decoder * * Copyright (c) 2023, Daniel Lemire and @aqrit. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef BASE32_H #define BASE32_H #include #include ////////////////////////// /// Source: Wojciech MuĹ‚a, Daniel Lemire, Faster Base64 Encoding and Decoding Using AVX2 Instructions, /// ACM Transactions on the Web 12 (3), 2018 /// https://arxiv.org/abs/1704.00605 ////////////////////////// static size_t base32hex_sse(uint8_t *dst, const uint8_t *src) { static int8_t zero_masks[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; bool valid = true; const __m128i delta_check = _mm_setr_epi8(-16, -32, -48, 70, -65, 41, -97, 9, 0, 0, 0, 0, 0, 0, 0, 0); const __m128i delta_rebase = _mm_setr_epi8(0, 0, 0, -48, -55, -55, -87, -87, 0, 0, 0, 0, 0, 0, 0, 0); const uint8_t *srcinit = src; do { __m128i v = _mm_loadu_si128((__m128i *)src); __m128i hash_key = _mm_and_si128(_mm_srli_epi32(v, 4), _mm_set1_epi8(0x0F)); __m128i check = _mm_add_epi8(_mm_shuffle_epi8(delta_check, hash_key), v); v = _mm_add_epi8(v, _mm_shuffle_epi8(delta_rebase, hash_key)); unsigned int m = (unsigned)_mm_movemask_epi8(check); if (m) { int length = (int)trailing_zeroes(m); if (length == 0) { break; } src += length; __m128i zero_mask = _mm_loadu_si128((__m128i *)(zero_masks + 16 - length)); v = _mm_andnot_si128(zero_mask, v); valid = false; } else { // common case src += 16; } v = _mm_maddubs_epi16(v, _mm_set1_epi32(0x01200120)); v = _mm_madd_epi16( v, _mm_set_epi32(0x00010400, 0x00104000, 0x00010400, 0x00104000)); // ...00000000`0000eeee`efffffgg`ggghhhhh`00000000`aaaaabbb`bbcccccd`dddd0000 v = _mm_or_si128(v, _mm_srli_epi64(v, 48)); v = _mm_shuffle_epi8( v, _mm_set_epi8(0, 0, 0, 0, 0, 0, 12, 13, 8, 9, 10, 4, 5, 0, 1, 2)); /* decoded 10 bytes... but write 16 cause why not? */ _mm_storeu_si128((__m128i *)dst, v); dst += 10; } while (valid); return (size_t)(src - srcinit); } nonnull_all static really_inline int32_t parse_base32( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { size_t length = (token->length * 5) / 8; if (length > 255 || (uintptr_t)rdata->limit - (uintptr_t)rdata->octets < (length + 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); size_t decoded = base32hex_sse(rdata->octets+1, (const uint8_t*)token->data); if (decoded != token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets = (uint8_t)length; rdata->octets += 1 + length; return 0; } #endif // BASE32_H nsd-4.12.0/simdzone/src/isadetection.h0000644000175000017500000002117315002373055017245 0ustar mozziemozzie/* * isadetection.h -- detect supported instruction set(s) * * Slightly modified version of isadetection.h in simdjson. * * Copyright (c) 2024 NLnet Labs (Jeroen Koekkoek) * Copyright (c) 2020- simdjson (Daniel Lemire, * Geoff Langdale, * John Keiser) * Copyright (c) 2016- Facebook, Inc (Adam Paszke) * Copyright (c) 2014- Facebook, Inc (Soumith Chintala) * Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) * Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) * Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) * Copyright (c) 2011-2013 NYU (Clement Farabet) * Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, * Leon Bottou, * Iain Melvin, * Jason Weston) * Copyright (c) 2006 Idiap Research Institute (Samy Bengio) * Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, * Samy Bengio, * Johnny Mariethoz) * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the names of simdjson, Facebook, Deepmind Technologies, NYU, * NEC Laboratories America and IDIAP Research Institute nor the names of * its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef ISADETECTION_H #define ISADETECTION_H #include #include #include #if defined(_MSC_VER) #include #include #elif defined(HAVE_CPUID) #include #endif enum instruction_set { DEFAULT = 0x0, NEON = 0x1, AVX2 = 0x4, SSE42 = 0x8, PCLMULQDQ = 0x10, BMI1 = 0x20, BMI2 = 0x40, ALTIVEC = 0x80, AVX512F = 0x100, AVX512DQ = 0x200, AVX512IFMA = 0x400, AVX512PF = 0x800, AVX512ER = 0x1000, AVX512CD = 0x2000, AVX512BW = 0x4000, AVX512VL = 0x8000, AVX512VBMI2 = 0x10000 }; #if defined(__PPC64__) static inline uint32_t detect_supported_architectures(void) { return ALTIVEC; } #elif defined(__arm__) || defined(__aarch64__) // incl. armel, armhf, arm64 #if defined(__ARM_NEON) static inline uint32_t detect_supported_architectures(void) { return NEON; } #else // ARM without NEON static inline uint32_t detect_supported_architectures(void) { return DEFAULT; } #endif #elif defined(__x86_64__) || defined(_M_AMD64) // x64 // Can be found on Intel ISA Reference for CPUID static const uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7 static const uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7 static const uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7 static const uint32_t cpuid_avx512f_bit = 1 << 16; ///< @private bit 16 of EBX for EAX=0x7 static const uint32_t cpuid_avx512dq_bit = 1 << 17; ///< @private bit 17 of EBX for EAX=0x7 static const uint32_t cpuid_avx512ifma_bit = 1 << 21; ///< @private bit 21 of EBX for EAX=0x7 static const uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX for EAX=0x7 static const uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7 static const uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7 static const uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7 static const uint32_t cpuid_avx512vl_bit = 1U << 31; ///< @private bit 31 of EBX for EAX=0x7 static const uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7 static const uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1 static const uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1 static const uint32_t cpuid_have_xgetbv_bit = 1 << 27; ///< @private bit 27 of ECX for EAX=0x1 static const uint32_t cpuid_have_avx_bit = 1 << 28; ///< @private bit 28 of ECX for EAX=0x1 static inline void cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { #if defined(_MSC_VER) int cpu_info[4]; __cpuid(cpu_info, *eax); *eax = cpu_info[0]; *ebx = cpu_info[1]; *ecx = cpu_info[2]; *edx = cpu_info[3]; #elif defined(HAVE_CPUID) uint32_t level = *eax; __get_cpuid(level, eax, ebx, ecx, edx); #else uint32_t a = *eax, b, c = *ecx, d; asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); *eax = a; *ebx = b; *ecx = c; *edx = d; #endif } static inline uint64_t xgetbv(uint32_t ecx) { #if defined(_MSC_VER) return _xgetbv(ecx); #else uint32_t a, c = ecx, d; asm volatile("xgetbv\n\t" : "=d"(d), "=a"(a) : "c"(c)); uint64_t xcr0 = ((uint64_t)d << 32) | (uint64_t)a; return xcr0; #endif } static inline uint32_t detect_supported_architectures(void) { uint32_t eax, ebx, ecx, edx; uint32_t host_isa = 0x0, host_avx_isa = 0x0; // ECX for EAX=0x7 eax = 0x7; ecx = 0x0; cpuid(&eax, &ebx, &ecx, &edx); if (ebx & cpuid_bmi1_bit) { host_isa |= BMI1; } if (ebx & cpuid_bmi2_bit) { host_isa |= BMI2; } if (ebx & cpuid_avx2_bit) { host_avx_isa |= AVX2; } if (ebx & cpuid_avx512f_bit) { host_avx_isa |= AVX512F; } if (ebx & cpuid_avx512dq_bit) { host_avx_isa |= AVX512DQ; } if (ebx & cpuid_avx512ifma_bit) { host_avx_isa |= AVX512IFMA; } if (ebx & cpuid_avx512pf_bit) { host_avx_isa |= AVX512PF; } if (ebx & cpuid_avx512er_bit) { host_avx_isa |= AVX512ER; } if (ebx & cpuid_avx512cd_bit) { host_avx_isa |= AVX512CD; } if (ebx & cpuid_avx512bw_bit) { host_avx_isa |= AVX512BW; } if (ebx & cpuid_avx512vl_bit) { host_avx_isa |= AVX512VL; } if (ecx & cpuid_avx512vbmi2_bit) { host_avx_isa |= AVX512VBMI2; } bool have_avx = false, have_xgetbv = false; // EBX for EAX=0x1 eax = 0x1; cpuid(&eax, &ebx, &ecx, &edx); if (ecx & cpuid_sse42_bit) { host_isa |= SSE42; } if (ecx & cpuid_pclmulqdq_bit) { host_isa |= PCLMULQDQ; } // Correct detection of AVX2 support requires more than checking the CPUID // bit. Peter Cordes provides an excellent answer on Stack Overflow // (https://stackoverflow.com/a/34071400) quoting the article Introduction // to Intel Advanced Vector Extensions (search Wayback Machine). // // 1. Verify that the operating system supports XGETBV using // CPUID.1:ECX.OSXSAVE bit 27 = 1. // 2. Verify the processor supports the AVX instruction extensions using: // CPUID.1:ECX bit 28 = 1. // 3. Issue XGETBV, and verify that the feature-enabled mask at bits 1 and 2 // are 11b (XMM state and YMM state enabled by the operating system). // Determine if the CPU supports AVX have_avx = (ecx & cpuid_have_avx_bit) != 0; // Determine if the Operating System supports XGETBV have_xgetbv = (ecx & cpuid_have_xgetbv_bit) != 0; if (have_avx && have_xgetbv) { uint64_t xcr0 = xgetbv(0x0); if ((xcr0 & 0x6) == 0x6) host_isa |= host_avx_isa; } return host_isa; } #else // fallback static inline uint32_t detect_supported_architectures(void) { return DEFAULT; } #endif // end SIMD extension detection code #endif // ISADETECTION_H nsd-4.12.0/simdzone/src/haswell/0000755000175000017500000000000015002373055016054 5ustar mozziemozziensd-4.12.0/simdzone/src/haswell/simd.h0000644000175000017500000000704515002373055017167 0ustar mozziemozzie/* * haswell.h -- SIMD abstractions targeting AVX2 * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SIMD_H #define SIMD_H #include #include #define SIMD_8X_SIZE (32) typedef uint8_t simd_table_t[SIMD_8X_SIZE]; #define SIMD_TABLE(v00, v01, v02, v03, v04, v05, v06, v07, \ v08, v09, v0a, v0b, v0c, v0d, v0e, v0f) \ { \ v00, v01, v02, v03, v04, v05, v06, v07, \ v08, v09, v0a, v0b, v0c, v0d, v0e, v0f, \ v00, v01, v02, v03, v04, v05, v06, v07, \ v08, v09, v0a, v0b, v0c, v0d, v0e, v0f \ } typedef struct { __m256i chunks[1]; } simd_8x_t; typedef struct { __m128i chunks[1]; } simd_8x16_t; typedef simd_8x_t simd_8x32_t; typedef struct { __m256i chunks[2]; } simd_8x64_t; nonnull_all static really_inline void simd_loadu_8x(simd_8x_t *simd, const void *address) { simd->chunks[0] = _mm256_loadu_si256((const __m256i *)(address)); } nonnull_all static really_inline void simd_storeu_8x(void *address, simd_8x_t *simd) { _mm256_storeu_si256((__m256i *)address, simd->chunks[0]); } nonnull_all static really_inline uint64_t simd_find_8x(const simd_8x_t *simd, char key) { const __m256i k = _mm256_set1_epi8(key); const __m256i r = _mm256_cmpeq_epi8(simd->chunks[0], k); return (uint32_t)_mm256_movemask_epi8(r); } nonnull_all static really_inline uint64_t simd_find_any_8x( const simd_8x_t *simd, const simd_table_t table) { const __m256i t = _mm256_loadu_si256((const __m256i *)table); const __m256i r = _mm256_cmpeq_epi8( _mm256_shuffle_epi8(t, simd->chunks[0]), simd->chunks[0]); return (uint32_t)_mm256_movemask_epi8(r); } nonnull_all static really_inline void simd_loadu_8x16(simd_8x16_t *simd, const uint8_t *address) { simd->chunks[0] = _mm_loadu_si128((const __m128i *)address); } nonnull_all static really_inline uint64_t simd_find_8x16(const simd_8x16_t *simd, char key) { const __m128i k = _mm_set1_epi8(key); const __m128i r = _mm_cmpeq_epi8(simd->chunks[0], k); const uint64_t m = (uint16_t)_mm_movemask_epi8(r); return m; } #define simd_loadu_8x32(simd, address) simd_loadu_8x(simd, address) #define simd_storeu_8x32(address, simd) simd_storeu_8x(address, simd) #define simd_find_8x32(simd, key) simd_find_8x(simd, key) nonnull_all static really_inline void simd_loadu_8x64(simd_8x64_t *simd, const uint8_t *address) { simd->chunks[0] = _mm256_loadu_si256((const __m256i *)(address)); simd->chunks[1] = _mm256_loadu_si256((const __m256i *)(address+32)); } nonnull_all static really_inline uint64_t simd_find_8x64(const simd_8x64_t *simd, char key) { const __m256i k = _mm256_set1_epi8(key); const __m256i r0 = _mm256_cmpeq_epi8(simd->chunks[0], k); const __m256i r1 = _mm256_cmpeq_epi8(simd->chunks[1], k); const uint64_t m0 = (uint32_t)_mm256_movemask_epi8(r0); const uint64_t m1 = (uint32_t)_mm256_movemask_epi8(r1); return m0 | (m1 << 32); } nonnull_all static really_inline uint64_t simd_find_any_8x64( const simd_8x64_t *simd, const simd_table_t table) { const __m256i t = _mm256_loadu_si256((const __m256i *)table); const __m256i r0 = _mm256_cmpeq_epi8( _mm256_shuffle_epi8(t, simd->chunks[0]), simd->chunks[0]); const __m256i r1 = _mm256_cmpeq_epi8( _mm256_shuffle_epi8(t, simd->chunks[1]), simd->chunks[1]); const uint64_t m0 = (uint32_t)_mm256_movemask_epi8(r0); const uint64_t m1 = (uint32_t)_mm256_movemask_epi8(r1); return m0 | (m1 << 32); } #endif // SIMD_H nsd-4.12.0/simdzone/src/haswell/parser.c0000644000175000017500000000235615002373055017522 0ustar mozziemozzie/* * parser.c -- AVX2 specific compilation target for (DNS) zone file parser * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause. * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "haswell/simd.h" #include "generic/endian.h" #include "haswell/bits.h" #include "generic/parser.h" #include "generic/scanner.h" #include "generic/number.h" #include "generic/ttl.h" #include "westmere/time.h" #include "westmere/ip4.h" #include "generic/ip6.h" #include "generic/text.h" #include "generic/name.h" #include "generic/base16.h" #include "haswell/base32.h" #include "generic/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" #include "generic/ilnp64.h" #include "generic/eui.h" #include "generic/nsap.h" #include "generic/wks.h" #include "generic/loc.h" #include "generic/gpos.h" #include "generic/apl.h" #include "generic/svcb.h" #include "generic/cert.h" #include "generic/atma.h" #include "generic/algorithm.h" #include "generic/types.h" #include "westmere/type.h" #include "generic/format.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_haswell_parse(parser_t *parser) { return parse(parser); } diagnostic_pop() nsd-4.12.0/simdzone/src/haswell/bits.h0000644000175000017500000000340115002373055017164 0ustar mozziemozzie/* * bits.h -- Haswell specific implementation of bit manipulation instructions * * Copyright (c) 2018-2023 The simdjson authors * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BITS_H #define BITS_H #include #include #include static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) { #if has_builtin(__builtin_uaddll_overflow) return __builtin_uaddll_overflow(value1, value2, (unsigned long long *)result); #else *result = value1 + value2; return *result < value1; #endif } static inline uint64_t count_ones(uint64_t bits) { return (uint64_t)_mm_popcnt_u64(bits); } no_sanitize_undefined static inline uint64_t trailing_zeroes(uint64_t bits) { return (uint64_t)_tzcnt_u64(bits); } // result might be undefined when bits is zero static inline uint64_t clear_lowest_bit(uint64_t bits) { return bits & (bits - 1); } static inline uint64_t leading_zeroes(uint64_t bits) { return (uint64_t)_lzcnt_u64(bits); } static inline uint64_t prefix_xor(const uint64_t bitmask) { __m128i all_ones = _mm_set1_epi8('\xFF'); __m128i mask = _mm_set_epi64x(0ULL, (long long)bitmask); #if defined __SUNPRO_C // Oracle Developer Studio has issues generating vpclmulqdq // Oracle Solaris and Intel assembler use the opposite order for source and // destination operands. See x86 Assemble Language Reference Manual. __asm volatile ("vpclmulqdq $0,%[all_ones],%[mask],%[mask]" : [mask] "+x" (mask) : [all_ones] "x" (all_ones)); #else // There should be no such thing with a processor supporting avx2 // but not clmul. mask = _mm_clmulepi64_si128(mask, all_ones, 0); #endif return (uint64_t)_mm_cvtsi128_si64(mask); } #endif // BITS_H nsd-4.12.0/simdzone/src/haswell/bench.c0000644000175000017500000000124115002373055017275 0ustar mozziemozzie/* * bench.c -- AVX2 compilation target for benchmark function(s) * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "haswell/simd.h" #include "haswell/bits.h" #include "generic/parser.h" #include "generic/scanner.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_bench_haswell_lex(zone_parser_t *parser, size_t *tokens) { token_t token; (*tokens) = 0; take(parser, &token); while (token.code > 0) { (*tokens)++; take(parser, &token); } return token.code ? -1 : 0; } diagnostic_pop() nsd-4.12.0/simdzone/src/haswell/base32.h0000644000175000017500000000657015002373055017314 0ustar mozziemozzie/* * base32.h -- Fast Base32 decoder * * Copyright (c) 2023, Daniel Lemire and @aqrit. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef BASE32_H #define BASE32_H #include ////////////////////////// /// Source: Wojciech MuĹ‚a, Daniel Lemire, Faster Base64 Encoding and Decoding Using AVX2 Instructions, /// ACM Transactions on the Web 12 (3), 2018 /// https://arxiv.org/abs/1704.00605 ////////////////////////// static size_t base32hex_avx(uint8_t *dst, const uint8_t *src) { static int8_t zero_masks256[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; bool valid = true; const __m256i delta_check = _mm256_setr_epi8( -16, -32, -48, 70, -65, 41, -97, 9, 0, 0, 0, 0, 0, 0, 0, 0, -16, -32, -48, 70, -65, 41, -97, 9, 0, 0, 0, 0, 0, 0, 0, 0); const __m256i delta_rebase = _mm256_setr_epi8( 0, 0, 0, -48, -55, -55, -87, -87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -48, -55, -55, -87, -87, 0, 0, 0, 0, 0, 0, 0, 0); const uint8_t *srcinit = src; do { __m256i v = _mm256_loadu_si256((__m256i *)src); __m256i hash_key = _mm256_and_si256(_mm256_srli_epi32(v, 4), _mm256_set1_epi8(0x0F)); __m256i check = _mm256_add_epi8(_mm256_shuffle_epi8(delta_check, hash_key), v); v = _mm256_add_epi8(v, _mm256_shuffle_epi8(delta_rebase, hash_key)); unsigned int m = (unsigned)_mm256_movemask_epi8(check); if (m) { int length = (int)trailing_zeroes(m); if (length == 0) { break; } src += length; __m256i zero_mask = _mm256_loadu_si256((__m256i *)(zero_masks256 + 32 - length)); v = _mm256_andnot_si256(zero_mask, v); valid = false; } else { // common case src += 32; } v = _mm256_maddubs_epi16(v, _mm256_set1_epi32(0x01200120)); v = _mm256_madd_epi16( v, _mm256_set_epi32(0x00010400, 0x00104000, 0x00010400, 0x00104000, 0x00010400, 0x00104000, 0x00010400, 0x00104000)); // ...00000000`0000eeee`efffffgg`ggghhhhh`00000000`aaaaabbb`bbcccccd`dddd0000 v = _mm256_or_si256(v, _mm256_srli_epi64(v, 48)); v = _mm256_shuffle_epi8( v, _mm256_set_epi8(0, 0, 0, 0, 0, 0, 12, 13, 8, 9, 10, 4, 5, 0, 1, 2, 0, 0, 0, 0, 0, 0, 12, 13, 8, 9, 10, 4, 5, 0, 1, 2)); // 5. store bytes _mm_storeu_si128((__m128i *)dst, _mm256_castsi256_si128(v)); dst += 10; _mm_storeu_si128((__m128i *)dst, _mm256_extractf128_si256(v, 1)); dst += 10; } while (valid); return (size_t)(src - srcinit); } nonnull_all static really_inline int32_t parse_base32( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { size_t length = (token->length * 5) / 8; if (length > 255 || (uintptr_t)rdata->limit - (uintptr_t)rdata->octets < (length + 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); size_t decoded = base32hex_avx(rdata->octets+1, (const uint8_t*)token->data); if (decoded != token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets = (uint8_t)length; rdata->octets += 1 + length; return 0; } #endif // BASE32_H nsd-4.12.0/simdzone/src/generic/0000755000175000017500000000000015002373055016031 5ustar mozziemozziensd-4.12.0/simdzone/src/generic/wks.h0000644000175000017500000001764415002373055017022 0ustar mozziemozzie/* * wks.c -- Well-Known Services (WKS) RDATA parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef WKS_H #define WKS_H // RFC1035 section 3.4.2: // The purpose of WKS RRs is to provide availability information for servers // for TCP and UDP. // // NSD and BIND use getprotobyname, which reads /etc/protocols (optimizations // may be in place for TCP and UDP). Note that BIND passes the protocol to // getservbyname for TCP and UDP only, NULL otherwise, which means any // protocol matches. Unfortunately, getprotobyname is NOT thread-safe. // getprotobyname_r exist on most BSDs and Linux, but not Windows. // The list of known protocols and services also differs between operating // systems and no list covers all IANA (links below) registered protocols // and services, which may cause compatibility issues. Furthermore, even // getprotobyname_r and getservbyname_r are marked locale, meaning the locale // object is read without any form of synchronization, which may be an issue // for a library. // // https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml // https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml // // https://www.gnu.org/software/libc/manual/html_node/Protocols-Database.html // https://www.gnu.org/software/libc/manual/html_node/Services-Database.html // https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html // https://www.gnu.org/software/libc/manual/html_node/Other-Safety-Remarks.html // // WKS RRs are rarely used and a document to deprecate the RRTYPE (among // others) has been drafted (WKS removed from the second draft). // // https://datatracker.ietf.org/doc/html/draft-sury-deprecate-obsolete-resource-records-00 // https://mailarchive.ietf.org/arch/msg/dnsop/YCVvXuM8HbJLF2SoXyDqyOGao34/ // // // WKS RRs have been said to be deprecated in an informational document (NOT // a standard), although it wrongly claims WKS RRs are in fact deprecated. // // RFC1912 section 2.6.1 (informational): // WKS records are deprecated in [RFC 1123]. They serve no known useful // function, except internally among LISP machines. Don't use them. // // https://datatracker.ietf.org/doc/html/rfc1912 // // RFC1123 section 2.2 (standard): // An application SHOULD NOT rely on the ability to locate a WKS record // containing an accurate listing of all services at a particular host // address, since the WKS RR type is not often used by Internet sites. // To confirm that a service is present, simply attempt to use it. // // https://datatracker.ietf.org/doc/html/rfc1123 // // RFC1127 section 2 (informational): // WKS Records Detracted [AS 2.2, 5.2.12, 6.1.3.6] // Recommend against using WKS records from DNS. // // https://datatracker.ietf.org/doc/html/rfc1127 // // // Rather than supporting any protocol registered by IANA, support a small // subset of mnemonics (TCP and UDP) as well as numeric values and add // support (or remove it entirely) for additional protocols on demand. #if BYTE_ORDER == LITTLE_ENDIAN # define TCP (0x0000000000706374llu) # define UDP (0x0000000000706475llu) #elif BYTE_ORDER == BIG_ENDIAN # define TCP (0x7463700000000000llu) # define UDP (0x7564700000000000llu) #else # error "byte order unknown" #endif static really_inline int32_t scan_protocol( const char *name, size_t length, uint8_t *protocol) { static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint64_t key; uint64_t mask; const int8_t *zero_mask = &zero_masks[32 - (length & 0x1f)]; memcpy(&mask, zero_mask, 8); memcpy(&key, name, sizeof(key)); // safe, input is padded key |= (key & 0x4040404040404040) >> 1; // convert to lower case key &= mask; if (key == TCP) return (void)(*protocol = 6), 1; else if (key == UDP) return (void)(*protocol = 17), 1; else return scan_int8(name, length, protocol); } typedef struct service service_t; struct service { struct { const char name[16]; size_t length; } key; uint16_t port; }; #define UNKNOWN_SERVICE() { { "", 0 }, 0 } #define SERVICE(name, port) { { name, sizeof(name) - 1 }, port } static const service_t services[64] = { UNKNOWN_SERVICE(), SERVICE("snmptrap", 162), SERVICE("pop3s", 995), SERVICE("pop3", 110), SERVICE("ldaps", 636), SERVICE("domain", 53), SERVICE("nntps", 563), SERVICE("nntp", 119), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("ftps-data", 989), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("imaps", 993), SERVICE("imap", 143), SERVICE("time", 37), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("kerberos", 88), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("ftp", 21), SERVICE("ntp", 123), SERVICE("whoispp", 63), SERVICE("ssh", 22), UNKNOWN_SERVICE(), SERVICE("nicname", 43), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("ptp-general", 320), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("domain-s", 853), SERVICE("ftp-data", 20), SERVICE("ftps", 990), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("snmp", 161), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), UNKNOWN_SERVICE(), SERVICE("bgmp", 264), SERVICE("echo", 7), UNKNOWN_SERVICE(), SERVICE("nnsp", 433), SERVICE("submission", 587), // submissions cannot be distinguished from submission by hash value because // the shared prefix is too long. include length to generate a unique key SERVICE("submissions", 465), UNKNOWN_SERVICE(), SERVICE("ptp-event", 319), UNKNOWN_SERVICE(), SERVICE("npp", 92), UNKNOWN_SERVICE(), SERVICE("https", 443), SERVICE("http", 80), UNKNOWN_SERVICE(), SERVICE("telnet", 23), SERVICE("tcpmux", 1), UNKNOWN_SERVICE(), SERVICE("lmtp", 24), SERVICE("smtp", 25) }; #undef SERVICE #undef UNKNOWN_SERVICE // magic (139898079) generated using wks-hash.c static really_inline uint8_t service_hash(uint64_t input, size_t length) { // le64toh is required for big endian, no-op on little endian input = le64toh(input); uint32_t input32 = (uint32_t)((input >> 32) ^ input); return (((input32 * 139898079llu) >> 32) + length) & 0x3f; } nonnull((1,4)) static really_inline int32_t scan_service( const char *data, size_t length, int32_t protocol, uint16_t *port) { uint8_t digit = (uint8_t)*data - '0'; static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; (void)protocol; // all supported services map to tcp and udp if (digit > 9) { uint64_t input0, input1; static const uint64_t upper_mask = 0xdfdfdfdfdfdfdfdfllu; static const uint64_t letter_mask = 0x4040404040404040llu; memcpy(&input0, data, 8); memcpy(&input1, data+8, 8); // convert to upper case, unconditionally transforms digits (0x30-0x39) // and dash (0x2d), but does not introduce clashes uint64_t key = input0 & upper_mask; // zero out non-relevant bytes uint64_t zero_mask0, zero_mask1; const int8_t *zero_mask = &zero_masks[32 - (length & 0xf)]; memcpy(&zero_mask0, zero_mask, 8); memcpy(&zero_mask1, zero_mask+8, 8); uint8_t index = service_hash(key & zero_mask0, length); assert(index < 64); input0 |= (input0 & letter_mask) >> 1; input0 &= zero_mask0; input1 |= (input1 & letter_mask) >> 1; input1 &= zero_mask1; uint64_t name0, name1; memcpy(&name0, services[index].key.name, 8); memcpy(&name1, services[index].key.name+8, 8); *port = services[index].port; return (input0 == name0) & (input1 == name1) & (services[index].key.length == length); } return scan_int16(data, length, port); } #endif // WKS_H nsd-4.12.0/simdzone/src/generic/types.h0000644000175000017500000034346215002373055017362 0ustar mozziemozzie/* * types.h * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TYPES_H #define TYPES_H nonnull_all static really_inline int32_t scan_type_or_class( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic); nonnull_all static really_inline int32_t parse_type( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token); nonnull_all static really_inline int32_t parse_name( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token); nonnull_all static really_inline int32_t parse_string( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token); nonnull_all static really_inline int32_t parse_text( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token); #define FIELDS(fields) \ { (sizeof(fields)/sizeof(fields[0])), fields } #define FIELD(name) \ { { { name, sizeof(name) - 1 } } } #define CLASS(name, code) \ { { { name, sizeof(name) - 1 }, code } } #define UNKNOWN_CLASS(code) \ { { { "", 0 }, code } } #define TYPE(name, code, _class, fields, check, parse) \ { { { name, sizeof(name) - 1 }, code }, _class, false, false, fields, check, parse } #define UNKNOWN_TYPE(code) \ { { { "", 0 }, code }, 0, false, false, { 0, NULL }, check_generic_rr, parse_unknown_rdata } nonnull((1,2,3,4)) static really_inline int32_t check_bytes( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length, const size_t size) { (void)data; if (length < size) SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); return (int32_t)size; } #define check_int8(...) check_bytes(__VA_ARGS__, sizeof(uint8_t)) #define check_int16(...) check_bytes(__VA_ARGS__, sizeof(uint16_t)) #define check_int32(...) check_bytes(__VA_ARGS__, sizeof(uint32_t)) #define check_int64(...) check_bytes(__VA_ARGS__, sizeof(uint64_t)) #define check_ip4(...) check_bytes(__VA_ARGS__, 4) #define check_ip6(...) check_bytes(__VA_ARGS__, 16) #define check_ilnp64(...) check_bytes(__VA_ARGS__, sizeof(uint64_t)) nonnull((1,2,3,4)) static really_inline int32_t check_ttl( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { uint32_t number; if (length < sizeof(number)) SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); memcpy(&number, data, sizeof(number)); number = be32toh(number); if (number > INT32_MAX) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return 4; } zone_nonnull((1,2,3,4)) static really_inline int32_t check_name( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { int32_t label = 0, count = 0; while (count < (int32_t)length) { label = data[count]; count += 1 + label; if (!label) break; } if (!count || count > (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return count; } zone_nonnull((1,2,3,4)) static really_inline int32_t check_string( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { int32_t count; if (!length || (count = 1 + (int32_t)data[0]) > (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return count; } zone_nonnull((1,2,3,4)) static really_inline int32_t check_nsec( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const uint8_t *data, const size_t length) { int32_t count = 0; int32_t last_window = -1; while ((count + 2) < (int32_t)length) { const int32_t window = (int32_t)data[0]; const int32_t blocks = (int32_t)data[1]; if (window <= last_window) SYNTAX_ERROR(parser, "Invalid %s in %s, windows are out-of-order", NAME(field), NAME(type)); if (!blocks || blocks > 32) SYNTAX_ERROR(parser, "Invalid %s in %s, blocks are out-of-bounds", NAME(field), NAME(type)); count += 2 + blocks; last_window = window; } if (count != (int32_t)length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return count; } zone_nonnull((1)) static really_inline int32_t check(size_t *length, int32_t count) { if (count < 0) return count; *length += (size_t)count; return 0; } nonnull_all static really_inline void adjust_line_count(file_t *file) { file->line += file->span; file->span = 0; } nonnull_all static really_inline int32_t accept_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { (void)type; assert(rdata->octets <= rdata->limit); assert(rdata->octets >= parser->rdata->octets); size_t length = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; assert(length <= UINT16_MAX); assert(parser->owner->length <= UINT8_MAX); int32_t code = parser->options.accept.callback( parser, &(zone_name_t){ (uint8_t)parser->owner->length, parser->owner->octets }, parser->file->last_type, parser->file->last_class, *parser->file->ttl, (uint16_t)length, parser->rdata->octets, parser->user_data); adjust_line_count(parser->file); return code; } nonnull_all static int32_t check_a_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { assert(rdata->octets >= parser->rdata->octets); if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets == 4) return accept_rr(parser, type, rdata); SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } nonnull_all static int32_t parse_a_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_ip4(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_ns_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_name(parser, type, &f[0], o, n))) < 0) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_ns_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_soa_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_name(parser, type, &f[0], o, n))) || (r = check(&c, check_name(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int32(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_ttl(parser, type, &f[3], o+c, n-c))) || (r = check(&c, check_ttl(parser, type, &f[4], o+c, n-c))) || (r = check(&c, check_ttl(parser, type, &f[5], o+c, n-c))) || (r = check(&c, check_ttl(parser, type, &f[6], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_soa_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int32(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_ttl(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if ((code = parse_ttl(parser, type, &fields[4], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if ((code = parse_ttl(parser, type, &fields[5], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[6], token)) < 0) return code; if ((code = parse_ttl(parser, type, &fields[6], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_wks_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_ip4(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[0], o+c, n-c)))) return r; // any bit may, or may not, be set. confirm the bitmap does not exceed the // maximum number of ports if (n > 8192 + 5) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_wks_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_ip4(parser, type, &fields[0], rdata, token) < 0)) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; uint8_t protocol; if (!scan_protocol(token->data, token->length, &protocol)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(type)); *rdata->octets++ = protocol; uint8_t *bitmap = rdata->octets; int32_t highest_port = -1; take(parser, token); while (is_contiguous(token)) { uint16_t port; if (!scan_service(token->data, token->length, protocol, &port)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&type->rdata.fields[2]), NAME(type)); if (port > highest_port) { // ensure newly used octets are zeroed out before use size_t offset = highest_port < 0 ? 0 : (size_t)highest_port / 8 + 1; size_t length = (size_t)port / 8 + 1; memset(bitmap + offset, 0, length - offset); highest_port = port; } // bits are counted from left to right, so bit 0 is the left most bit bitmap[port / 8] |= (1 << (7 - port % 8)); take(parser, token); } rdata->octets += (size_t)highest_port / 8 + 1; if (have_delimiter(parser, type, token) < 0) return token->code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_hinfo_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n))) || (r = check(&c, check_string(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_hinfo_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous_or_quoted(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_minfo_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_name(parser, type, &f[0], o, n))) || (r = check(&c, check_name(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_minfo_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_mx_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_name(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_mx_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_txt_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n)))) return r; while (c < n) if ((r = check(&c, check_string(parser, type, &f[0], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_txt_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; while (is_contiguous_or_quoted(token)) { if ((code = parse_string(parser, type, &fields[0], rdata, token)) < 0) return code; take(parser, token); } if ((code = have_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_x25_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_x25_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous_or_quoted(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_isdn_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n)))) return r; // subaddress is optional if (c < n && (r = check(&c, check_string(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_isdn_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous_or_quoted(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[0], rdata, token)) < 0) return code; // subaddress is optional take(parser, token); if (is_contiguous_or_quoted(token)) { if ((code = parse_string(parser, type, &fields[1], rdata, token)) < 0) return code; take(parser, token); } if ((code = have_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_rt_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_name(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_rt_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nsap_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { if (rdata->octets == parser->rdata->octets) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nsap_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_nsap(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nsap_ptr_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } { // RFC1706 section 6 // A domain name is generated from an NSAP by reversing the hex nibbles of // the NSAP, treating each nibble as a separate subdomain, and appending // the top-level subdomain name "NSAP.INT" to it. For example, the domain // name used in the reverse lookup for the NSAP // // 47.0005.80.005a00.0000.0001.e133.ffffff000162.00 // // would appear as // // 0.0.2.6.1.0.0.0.f.f.f.f.f.f.3.3.1.e.1.0.0.0.0.0.0.0.0.0.a.5.0.0. // 0.8.5.0.0.0.7.4.NSAP.INT. size_t i = 0; const size_t n = parser->file->owner.length; const uint8_t *o = parser->file->owner.octets; for (; i < n; i += 2) if (o[i] != 1 || (base16_table_dec_32bit_d1[o[i+1]] > 0xff)) break; const uint8_t nsap_int[] = { 4, 'n', 's', 'a', 'p', 3, 'i', 'n', 't', 0 }; if (strncasecmp((const char *)o + i, (const char *)nsap_int, 9) != 0 || !i || i + 10 != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nsap_ptr_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous_or_quoted(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; // RFC1706 section 6 states each nibble is treated as a separate subdomain return check_nsap_ptr_rr(parser, type, rdata); } nonnull_all static int32_t check_key_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { #if 0 int32_t r; size_t c = 0; const size_t n = parser->rdata->length; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; // // FIXME: implement (RFC2065) // // FIXME: verify the flag, algorithm and protocol combination is valid // FIXME: verify the key is valid for type(3)+algorithm(1) // // The combination is of course subject to secondary checks! // #endif (void)type; return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_key_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base64_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; return check_key_rr(parser, type, rdata); } nonnull_all static int32_t check_px_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_name(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_name(parser, type, &f[2], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_px_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_gpos_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_string(parser, type, &f[0], o, n))) || (r = check(&c, check_string(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_string(parser, type, &f[2], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); return accept_rr(parser, type, rdata); } static int32_t parse_gpos_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_latitude(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_longitude(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_altitude(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_aaaa_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_ip6(parser, type, &f[0], o, n)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_aaaa_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_ip6(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_loc_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets != 16) SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); return accept_rr(parser, type, rdata); // FIXME: check validity of latitude, longitude and latitude? } nonnull_all static int32_t parse_loc_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; uint32_t degrees, minutes, seconds; uint32_t latitude, longitude, altitude; const rdata_info_t *fields = type->rdata.fields; static const uint8_t defaults[4] = { 0x00, 0x12, 0x16, 0x13 }; // RFC1876 section 3: // If omitted, minutes and seconds default to zero, size defaults to 1m, // horizontal precision defaults to 10000m, and vertical precision defaults // to 10m. memcpy(rdata->octets, &defaults, sizeof(defaults)); // latitude if ((code = have_contiguous(parser, type, &fields[4], token)) < 0) return code; if (scan_degrees(token->data, token->length, °rees) == -1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[4]), NAME(type)); if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if (scan_minutes(token->data, token->length, &minutes) == -1) goto north_south; // minutes default to zero degrees += minutes; if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if (scan_seconds(token->data, token->length, &seconds) == -1) goto north_south; // seconds default to zero degrees += seconds; if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; north_south: if (token->data[0] == 'N') latitude = htobe32((1u<<31) + degrees); else if (token->data[0] == 'S') latitude = htobe32((1u<<31) - degrees); else SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[4]), NAME(type)); memcpy(&rdata->octets[4], &latitude, sizeof(latitude)); // longitude if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if (scan_degrees(token->data, token->length, °rees) == -1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[5]), NAME(type)); if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if (scan_minutes(token->data, token->length, &minutes) == -1) goto east_west; // minutes default to zero degrees += minutes; if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if (scan_seconds(token->data, token->length, &seconds) == -1) goto east_west; // seconds default to zero degrees += seconds; if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; east_west: if (token->data[0] == 'E') longitude = htobe32((1u<<31) + degrees); else if (token->data[0] == 'W') longitude = htobe32((1u<<31) - degrees); else SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[5]), NAME(type)); memcpy(&rdata->octets[8], &longitude, sizeof(longitude)); // altitude if ((code = take_contiguous(parser, type, &fields[6], token)) < 0) return code; if (scan_altitude(token->data, token->length, &altitude) == -1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[6]), NAME(type)); altitude = htobe32(altitude); memcpy(&rdata->octets[12], &altitude, sizeof(altitude)); // size take(parser, token); if (!is_contiguous(token)) goto skip_optional; if (scan_precision(token->data, token->length, &rdata->octets[1])) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(type)); // horizontal precision take(parser, token); if (!is_contiguous(token)) goto skip_optional; if (scan_precision(token->data, token->length, &rdata->octets[2])) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[2]), NAME(type)); // vertical precision take(parser, token); if (!is_contiguous(token)) goto skip_optional; if (scan_precision(token->data, token->length, &rdata->octets[3])) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(type)); take(parser, token); skip_optional: if ((code = have_delimiter(parser, type, token)) < 0) return code; rdata->octets += 16; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nxt_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_name(parser, type, &f[0], o+c, n-c)))) return r; return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nxt_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[0], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_nxt(parser, type, &fields[1], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_eid_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets <= 0) SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_eid_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = parse_base16_sequence(parser, type, &fields[1], rdata, token)) < 0) return code; return check_eid_rr(parser, type, rdata); } nonnull_all static int32_t check_srv_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int16(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int16(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_name(parser, type, &f[3], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_srv_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_atma_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { assert(rdata->octets >= parser->rdata->octets); if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets > 2) return accept_rr(parser, type, rdata); SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } nonnull_all static int32_t parse_atma_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_atma(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_naptr_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: implement actual checks (void)type; return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_naptr_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[4], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[4], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[5], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_cert_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: implement actual checks (void)type; assert(rdata->octets >= parser->rdata->octets); if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets < 6) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_cert_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_certificate_type(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_algorithm(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base64_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_sink_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: implement actual checks (void)type; assert(rdata->octets >= parser->rdata->octets); if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets < 3) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_sink_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base64_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_apl_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: check correctness of fields and total length return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_apl_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; // RDATA section for APL consists of zero or more fields while (is_contiguous(token)) { int32_t length; const size_t size = (uintptr_t)rdata->limit - (uintptr_t)rdata->octets; if ((length = scan_apl(token->data, token->length, rdata->octets, size)) < 0) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(type)); assert(length == 8 /* ipv4 */ || length == 20 /* ipv6 */); rdata->octets += (size_t)length; take(parser, token); } if ((code = have_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_ds_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; const uint8_t digest_algorithm = parser->rdata->octets[3]; if ((digest_algorithm & 0x7) == digest_algorithm) { // https://www.iana.org/assignments/ds-rr-types static const uint8_t digest_sizes[8] = { 0, // 0: Reserved 20, // 1: SHA-1 32, // 2: SHA-256 32, // 3: GOST R 34.11-94 48, // 4: SHA-384 48, // 5: GOST R 34.10-2012 48, // 6: SM3 0 // 7: Unassigned }; const uint8_t digest_size = digest_sizes[ digest_algorithm ]; if (digest_size && n - 4 != digest_size) SEMANTIC_ERROR(parser, "Invalid digest in %s", NAME(type)); } if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_ds_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_algorithm(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if (!(token->length == 1 && (char)*token->data == '0') && (code = parse_base16_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; const uint8_t digest_algorithm = parser->rdata->octets[3]; if ((digest_algorithm & 0x7) == digest_algorithm) { // https://www.iana.org/assignments/ds-rr-types static const uint8_t digest_sizes[8] = { 0, // 0: Reserved 20, // 1: SHA-1 32, // 2: SHA-256 32, // 3: GOST R 34.11-94 48, // 4: SHA-384 48, // 5: GOST R 34.10-2012 48, // 6: SM3 0 // 7: Unassigned }; const uint8_t digest_size = digest_sizes[ digest_algorithm ]; size_t length = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; if (digest_size && length - 4 != digest_size) SEMANTIC_ERROR(parser, "Invalid digest in %s", NAME(type)); } return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_sshfp_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c)))) return r; // https://www.iana.org/assignments/dns-sshfp-rr-parameters if (c == n) SYNTAX_ERROR(parser, "Missing %s in %s", NAME((&f[n!=0])), NAME(type)); else if (o[1] == 1 && (n - c) != 20) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", "SHA1", NAME(type)); else if (o[1] == 2 && (n - c) != 32) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", "SHA256", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_sshfp_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; const uint8_t *fingerprint_type = rdata->octets; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; const uint8_t *fingerprint = rdata->octets; take(parser, token); if ((code = parse_base16_sequence(parser, type, &fields[2], rdata, token)) < 0) return code; // https://www.iana.org/assignments/dns-sshfp-rr-parameters size_t fingerprint_size = (uintptr_t)rdata->octets - (uintptr_t)fingerprint; if (unlikely(*fingerprint_type == 1 && fingerprint_size != 20)) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", "SHA1", NAME(type)); if (unlikely(*fingerprint_type == 2 && fingerprint_size != 32)) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", "SHA256", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_ipseckey_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata); nonnull_all static int32_t parse_ipseckey_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token); diagnostic_push() gcc_diagnostic_ignored(missing-field-initializers) clang_diagnostic_ignored(missing-field-initializers) static const rdata_info_t ipseckey_ipv4_rdata_fields[] = { FIELD("precedence"), FIELD("gateway type"), FIELD("algorithm"), FIELD("gateway"), FIELD("public key") }; static const type_info_t ipseckey_ipv4[] = { TYPE("IPSECKEY", ZONE_TYPE_IPSECKEY, ZONE_CLASS_IN, FIELDS(ipseckey_ipv4_rdata_fields), check_ipseckey_rr, parse_ipseckey_rdata), }; static const rdata_info_t ipseckey_ipv6_rdata_fields[] = { FIELD("precedence"), FIELD("gateway type"), FIELD("algorithm"), FIELD("gateway"), FIELD("public key") }; static const type_info_t ipseckey_ipv6[] = { TYPE("IPSECKEY", ZONE_TYPE_IPSECKEY, ZONE_CLASS_IN, FIELDS(ipseckey_ipv6_rdata_fields), check_ipseckey_rr, parse_ipseckey_rdata), }; diagnostic_pop() nonnull_all static int32_t check_ipseckey_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const type_info_t *t = type; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; switch (parser->rdata->octets[1]) { case 1: /* IPv4 address */ t = (const type_info_t *)ipseckey_ipv4; f = ipseckey_ipv4_rdata_fields; if ((r = check(&c, check_ip4(parser, t, &f[3], o+c, n-c))) < 0) return r; break; case 2: /* IPv6 address */ t = (const type_info_t *)ipseckey_ipv6; f = ipseckey_ipv6_rdata_fields; if ((r = check(&c, check_ip6(parser, t, &f[3], o+c, n-c))) < 0) return r; break; case 0: /* no gateway */ break; case 3: /* domain name */ if ((r = check(&c, check_name(parser, t, &f[3], o+c, n-c))) < 0) return r; break; default: SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } switch (parser->rdata->octets[2]) { case 0: if (c < n) SYNTAX_ERROR(parser, "Trailing data in %s", NAME(t)); break; default: if (c >= n) SYNTAX_ERROR(parser, "Missing %s in %s", NAME(&f[4]), NAME(t)); break; } return accept_rr(parser, t, rdata); } nonnull_all static int32_t parse_ipseckey_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; uint8_t *octets = rdata->octets; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; switch (octets[1]) { case 0: /* no gateway */ if (token->length != 1 || token->data[0] != '.') SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(type)); break; case 1: /* IPv4 address */ type = (const type_info_t *)ipseckey_ipv4; fields = type->rdata.fields; if ((code = parse_ip4(parser, type, &fields[3], rdata, token)) < 0) return code; break; case 2: /* IPv6 address */ type = (const type_info_t *)ipseckey_ipv6; fields = type->rdata.fields; if ((code = parse_ip6(parser, type, &fields[3], rdata, token)) < 0) return code; break; case 3: /* domain name */ if ((code = parse_name(parser, type, &fields[3], rdata, token)) < 0) return code; break; default: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(type)); } take(parser, token); switch (octets[2]) { case 0: if ((code = have_delimiter(parser, type, token)) < 0) return code; break; default: if ((code = parse_base64_sequence(parser, type, &fields[4], rdata, token)) < 0) return code; break; } return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_rrsig_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_ttl(parser, type, &f[3], o+c, n-c))) || (r = check(&c, check_int32(parser, type, &f[4], o+c, n-c))) || (r = check(&c, check_int32(parser, type, &f[5], o+c, n-c))) || (r = check(&c, check_int16(parser, type, &f[6], o+c, n-c))) || (r = check(&c, check_name(parser, type, &f[7], o+c, n-c)))) return r; if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_rrsig_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_type(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_algorithm(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_ttl(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if ((code = parse_time(parser, type, &fields[4], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[5], token)) < 0) return code; if ((code = parse_time(parser, type, &fields[5], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[6], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[6], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[7], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[7], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base64_sequence(parser, type, &fields[8], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nsec_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_name(parser, type, &f[0], o, n))) || (r = check(&c, check_nsec(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nsec_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[0], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_nsec(parser, type, &fields[1], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_dnskey_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_dnskey_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_algorithm(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if (!(token->length == 1 && (char)*token->data == '0') && (code = parse_base64_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_dhcid_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // RFC4701 section 3.1: // 2-octet identifier type, 1-octet digest type, followed by one or more // octets representing the actual identifier if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets < 4) SEMANTIC_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_dhcid_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = parse_base64_sequence(parser, type, &fields[0], rdata, token)) < 0) return code; return check_dhcid_rr(parser, type, rdata); } nonnull_all static int32_t check_nsec3_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int16(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_string(parser, type, &f[3], o+c, n-c))) || (r = check(&c, check_string(parser, type, &f[4], o+c, n-c))) || (r = check(&c, check_nsec(parser, type, &f[5], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nsec3_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_salt(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if ((code = parse_base32(parser, type, &fields[4], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_nsec(parser, type, &fields[5], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nsec3param_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int16(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_string(parser, type, &f[3], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nsec3param_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_salt(parser, type, &fields[3], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_tlsa_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; if (c >= n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_tlsa_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base16_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_hip_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: verify field lengths etc return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_hip_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; uint8_t *octets = rdata->octets; // reserve octet for HIT length rdata->octets += 1; // PK algorithm if ((code = have_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; // reserve octets for PK length rdata->octets += 2; // HIT if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_base16(parser, type, &fields[3], rdata, token)) < 0) return code; if ((rdata->octets - octets) > 255 + 4) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(type)); uint8_t hit_length = (uint8_t)((rdata->octets - octets) - 4); octets[0] = hit_length; // Public Key if ((code = take_contiguous(parser, type, &fields[4], token)) < 0) return code; if ((code = parse_base64(parser, type, &fields[4], rdata, token)) < 0) return code; uint16_t pk_length = htobe16((uint16_t)(((rdata->octets - octets) - hit_length) - 4)); memcpy(&octets[2], &pk_length, sizeof(pk_length)); take(parser, token); while (is_contiguous(token)) { if ((code = parse_name(parser, type, &fields[5], rdata, token)) < 0) return code; take(parser, token); } if ((code = have_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_openpgpkey_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // FIXME: as the RDATA contains a digest, it is likely we can make this // check stricter, at least, for known algorithms if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets < 4) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_openpgpkey_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = parse_base64_sequence(parser, type, &fields[0], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_csync_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int32(parser, type, &f[0], o, n))) || (r = check(&c, check_int16(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_nsec(parser, type, &f[2], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_csync_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int32(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[1], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_nsec(parser, type, &fields[2], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_zonemd_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int32(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; const uint8_t digest_algorithm = parser->rdata->octets[5]; if ((digest_algorithm & 0x3) == digest_algorithm) { // https://www.iana.org/assignments/dns-parameters#zonemd-hash-algorithms static const uint8_t digest_sizes[4] = { 0, // 0: Reserved 48, // 1: SHA-384 64, // 2: SHA-512 0 // 3: Unassigned }; const uint8_t digest_size = digest_sizes[ digest_algorithm ]; if (digest_size && n - 6 != digest_size) SEMANTIC_ERROR(parser, "Invalid digest in %s", NAME(type)); } return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_zonemd_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int32(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_base16_sequence(parser, type, &fields[3], rdata, token)) < 0) return code; const uint8_t digest_algorithm = parser->rdata->octets[5]; if ((digest_algorithm & 0x3) == digest_algorithm) { // https://www.iana.org/assignments/dns-parameters#zonemd-hash-algorithms static const uint8_t digest_sizes[4] = { 0, // 0: Reserved 48, // 1: SHA-384 64, // 2: SHA-512 0 // 3: Unassigned }; const uint8_t digest_size = digest_sizes[ digest_algorithm ]; size_t length = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; if (digest_size && length - 6 != digest_size) SEMANTIC_ERROR(parser, "Invalid digest in %s", NAME(type)); } return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_svcb_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // // FIXME: implement checking parameters etc // // - check if all keys in mandatory exist // - check if at least keys and key lengths are valid // // FIXME: implement reordering parameters in strict (primary) mode // FIXME: note that when reordering or checking, rdata may not actually // contain valid parameters // return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_svcb_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_svc_params(parser, type, &fields[2], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_https_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { // // FIXME: incorporate fixes mentioned in check_svcb_rr // return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_https_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[1], rdata, token)) < 0) return code; take(parser, token); if ((code = parse_svc_params(parser, type, &fields[2], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_dsync_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int16(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_name(parser, type, &f[3], o+c, n-c)))) return r; const uint8_t dsync_scheme = o[2]; uint16_t dsync_type; memcpy(&dsync_type, o, sizeof(dsync_type)); dsync_type = be16toh(dsync_type); if (dsync_scheme == 1 && dsync_type != ZONE_TYPE_CDS && dsync_type != ZONE_TYPE_CSYNC) SEMANTIC_ERROR(parser, "Wrong type for scheme 1 in %s", NAME(type)); if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_dsync_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_type(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_name(parser, type, &fields[3], rdata, token)) < 0) return code; const uint8_t dsync_scheme = parser->rdata->octets[2]; uint16_t dsync_type; memcpy(&dsync_type, parser->rdata->octets, sizeof(dsync_type)); dsync_type = be16toh(dsync_type); if (dsync_scheme == 1 && dsync_type != ZONE_TYPE_CDS && dsync_type != ZONE_TYPE_CSYNC) SEMANTIC_ERROR(parser, "Wrong type for scheme 1 in %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_nid_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_ilnp64(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_nid_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_ilnp64(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_l32_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_ip4(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_l32_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_ip4(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_l64_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_ilnp64(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_l64_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_ilnp64(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_eui48_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets != 6) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_eui48_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_eui48(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_eui64_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { if ((uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets != 8) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_eui64_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_eui64(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_uri_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int16(parser, type, &f[0], o, n))) || (r = check(&c, check_int16(parser, type, &f[1], o+c, n-c)))) return r; if (c >= n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_uri_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int16(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_quoted(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_text(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_caa_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[1], o+c, n-c)))) return r; if (c >= n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_caa_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_caa_tag(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_text(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_doa_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int32(parser, type, &f[0], o, n))) || (r = check(&c, check_int32(parser, type, &f[1], o+c, n-c))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c))) || (r = check(&c, check_string(parser, type, &f[3], o+c, n-c)))) return r; if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_doa_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int32(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if ((code = parse_int32(parser, type, &fields[1], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; if ((code = take_quoted_or_contiguous(parser, type, &fields[3], token)) < 0) return code; if ((code = parse_string(parser, type, &fields[3], rdata, token)) < 0) return code; take(parser, token); if (!(token->length == 1 && ((char)*token->data == '0' || (char)*token->data == '-')) && (code = parse_base64_sequence(parser, type, &fields[4], rdata, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_amtrelay_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata); nonnull_all static int32_t parse_amtrelay_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token); diagnostic_push() gcc_diagnostic_ignored(missing-field-initializers) clang_diagnostic_ignored(missing-field-initializers) static const rdata_info_t amtrelay_ipv4_rdata_fields[] = { FIELD("precedence"), FIELD("discovery optional"), FIELD("type"), FIELD("relay") }; static const type_info_t amtrelay_ipv4[] = { TYPE("AMTRELAY", ZONE_TYPE_AMTRELAY, ZONE_CLASS_IN, FIELDS(amtrelay_ipv4_rdata_fields), check_amtrelay_rr, parse_amtrelay_rdata), }; static const rdata_info_t amtrelay_ipv6_rdata_fields[] = { FIELD("precedence"), FIELD("discovery optional"), FIELD("type"), FIELD("relay") }; static const type_info_t amtrelay_ipv6[] = { TYPE("AMTRELAY", ZONE_TYPE_AMTRELAY, ZONE_CLASS_IN, FIELDS(amtrelay_ipv6_rdata_fields), check_amtrelay_rr, parse_amtrelay_rdata), }; diagnostic_pop() nonnull_all static int32_t check_amtrelay_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const type_info_t *t = type; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int8(parser, type, &f[0], o, n))) || (r = check(&c, check_int8(parser, type, &f[2], o+c, n-c)))) return r; switch (parser->rdata->octets[1] & 0x7f) { case 1: /* IPv4 address */ t = (const type_info_t *)amtrelay_ipv4; f = amtrelay_ipv4_rdata_fields; if ((r = check(&c, check_ip4(parser, t, &f[3], o+c, n-c))) < 0) return r; break; case 2: /* IPv6 address */ t = (const type_info_t *)amtrelay_ipv6; f = amtrelay_ipv6_rdata_fields; if ((r = check(&c, check_ip6(parser, t, &f[3], o+c, n-c))) < 0) return r; break; case 0: /* no gateway */ break; case 3: /* domain name */ if ((r = check(&c, check_name(parser, t, &f[3], o+c, n-c))) < 0) return r; break; default: SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); } if (c < n) SYNTAX_ERROR(parser, "Trailing data in %s", NAME(t)); return accept_rr(parser, t, rdata); } nonnull_all static int32_t parse_amtrelay_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; uint8_t *octets = rdata->octets; uint8_t D; if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_contiguous(parser, type, &fields[1], token)) < 0) return code; if (token->length != 1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(type)); switch((char)*token->data) { case '0': D = 0x00; break; case '1': D = 0x80; break; default : SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(type)); } if ((code = take_contiguous(parser, type, &fields[2], token)) < 0) return code; if ((code = parse_int8(parser, type, &fields[2], rdata, token)) < 0) return code; if (octets[1]) { if ((code = take_contiguous(parser, type, &fields[3], token)) < 0) return code; switch (octets[1]) { case 1: /* IPv4 address */ type = (const type_info_t *)amtrelay_ipv4; fields = type->rdata.fields; if ((code = parse_ip4(parser, type, &fields[3], rdata, token)) < 0) return code; break; case 2: /* IPv6 address */ type = (const type_info_t *)amtrelay_ipv6; fields = type->rdata.fields; if ((code = parse_ip6(parser, type, &fields[3], rdata, token)) < 0) return code; break; case 3: /* domain name */ if ((code = parse_name(parser, type, &fields[3], rdata, token)) < 0) return code; break; default: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(type)); } } octets[1] |= D; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_ipn_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { int32_t r; size_t c = 0; const size_t n = (uintptr_t)rdata->octets - (uintptr_t)parser->rdata->octets; const uint8_t *o = parser->rdata->octets; const rdata_info_t *f = type->rdata.fields; if ((r = check(&c, check_int64(parser, type, &f[0], o, n)))) return r; if (c > n) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_ipn_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; const rdata_info_t *fields = type->rdata.fields; token_t left, right; /* draft-johnson-dns-ipn-cla-07 Section 3.1. IPN: * Presentation format for these resource records are either a 64 bit * unsigned decimal integer, or two 32 bit unsigned decimal integers * delimited by a period with the most significant 32 bits first and least * significant 32 bits last. */ if ((code = have_contiguous(parser, type, &fields[0], token)) < 0) return code; if (!(right.data = memchr(token->data, '.', token->length))) { if ((code = parse_int64(parser, type, &fields[0], rdata, token)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } left.code = token->code; left.data = token->data; left.length = (size_t)(right.data - token->data); right.code = token->code; right.data += 1; right.length = token->length - left.length - 1; if ((code = parse_int32(parser, type, &fields[0], rdata, &left)) < 0) return code; if ((code = parse_int32(parser, type, &fields[0], rdata, &right)) < 0) return code; if ((code = take_delimiter(parser, type, token)) < 0) return code; return accept_rr(parser, type, rdata); } nonnull_all static int32_t check_generic_rr( parser_t *parser, const type_info_t *type, const rdata_t *rdata) { return accept_rr(parser, type, rdata); } nonnull_all static int32_t parse_generic_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { int32_t code; uint16_t rdlength; static const rdata_info_t fields[] = { FIELD("rdlength"), FIELD("rdata") }; // discard '\#' if ((code = take_contiguous(parser, type, &fields[0], token)) < 0) return code; if (!scan_int16(token->data, token->length, &rdlength)) SYNTAX_ERROR(parser, "Invalid RDLENGTH in %s", NAME(type)); take(parser, token); if (is_contiguous(token)) { struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 }; do { size_t length = token->length + 1 / 2; if (length > (uintptr_t)rdata->limit - (uintptr_t)rdata->octets) SYNTAX_ERROR(parser, "Invalid RDATA in %s", NAME(type)); if (!base16_stream_decode(&state, token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid RDATA in %s", NAME(type)); rdata->octets += length; take(parser, token); } while (is_contiguous(token)); if (state.bytes) *rdata->octets++ = state.carry; } if ((code = have_delimiter(parser, type, token)) < 0) return code; if (rdata->octets - parser->rdata->octets != rdlength) SYNTAX_ERROR(parser, "Invalid RDATA in %s", NAME(type)); return type->check(parser, type, rdata); } nonnull_all static int32_t parse_unknown_rdata( parser_t *parser, const type_info_t *type, rdata_t *rdata, token_t *token) { (void)type; (void)rdata; (void)token; SYNTAX_ERROR(parser, "Unknown record type"); } diagnostic_push() gcc_diagnostic_ignored(missing-field-initializers) clang_diagnostic_ignored(missing-field-initializers) static const class_info_t classes[] = { UNKNOWN_CLASS(0), CLASS("IN", ZONE_CLASS_IN), CLASS("CS", ZONE_CLASS_CS), CLASS("CH", ZONE_CLASS_CH), CLASS("HS", ZONE_CLASS_HS) }; static const rdata_info_t a_rdata_fields[] = { FIELD("address") }; static const rdata_info_t ns_rdata_fields[] = { FIELD("host") }; static const rdata_info_t md_rdata_fields[] = { FIELD("madname") }; static const rdata_info_t mf_rdata_fields[] = { FIELD("madname") }; static const rdata_info_t cname_rdata_fields[] = { FIELD("host") }; static const rdata_info_t soa_rdata_fields[] = { FIELD("primary"), FIELD("mailbox"), FIELD("serial"), FIELD("refresh"), FIELD("retry"), FIELD("expire"), FIELD("minimum") }; static const rdata_info_t mb_rdata_fields[] = { FIELD("madname") }; static const rdata_info_t mg_rdata_fields[] = { FIELD("mgmname") }; static const rdata_info_t mr_rdata_fields[] = { FIELD("newname") }; static const rdata_info_t ptr_rdata_fields[] = { FIELD("ptrdname") }; static const rdata_info_t hinfo_rdata_fields[] = { FIELD("cpu"), FIELD("os") }; static const rdata_info_t minfo_rdata_fields[] = { FIELD("rmailbx"), FIELD("emailbx") }; static const rdata_info_t null_rdata_fields[] = { FIELD("anything") }; static const rdata_info_t wks_rdata_fields[] = { FIELD("address"), FIELD("protocol"), FIELD("bitmap") }; static const rdata_info_t mx_rdata_fields[] = { FIELD("priority"), FIELD("hostname") }; static const rdata_info_t txt_rdata_fields[] = { FIELD("text") }; static const rdata_info_t rp_rdata_fields[] = { FIELD("mailbox"), FIELD("text") }; static const rdata_info_t afsdb_rdata_fields[] = { FIELD("subtype"), FIELD("hostname") }; static const rdata_info_t x25_rdata_fields[] = { FIELD("address") }; static const rdata_info_t isdn_rdata_fields[] = { FIELD("address"), FIELD("subaddress") }; static const rdata_info_t rt_rdata_fields[] = { FIELD("preference"), FIELD("hostname") }; static const rdata_info_t nsap_rdata_fields[] = { FIELD("address") }; static const rdata_info_t nsap_ptr_rdata_fields[] = { FIELD("hostname") }; static const rdata_info_t key_rdata_fields[] = { FIELD("flags"), FIELD("protocol"), FIELD("algorithm"), FIELD("publickey") }; static const rdata_info_t px_rdata_fields[] = { FIELD("preference"), FIELD("map822"), FIELD("mapx400") }; static const rdata_info_t gpos_rdata_fields[] = { FIELD("latitude"), FIELD("longitude"), FIELD("altitude") }; static const rdata_info_t aaaa_rdata_fields[] = { FIELD("address") }; static const rdata_info_t loc_rdata_fields[] = { FIELD("version"), FIELD("size"), FIELD("horizontal precision"), FIELD("vertical precision"), FIELD("latitude"), FIELD("longitude"), FIELD("altitude") }; static const rdata_info_t nxt_rdata_fields[] = { FIELD("next domain name"), FIELD("type bit map") }; static const rdata_info_t eid_rdata_fields[] = { FIELD("end point identifier") }; static const rdata_info_t nimloc_rdata_fields[] = { FIELD("nimrod locator") }; static const rdata_info_t srv_rdata_fields[] = { FIELD("priority"), FIELD("weight"), FIELD("port"), FIELD("target") }; static const rdata_info_t atma_rdata_fields[] = { FIELD("address") }; static const rdata_info_t naptr_rdata_fields[] = { FIELD("order"), FIELD("preference"), FIELD("flags"), FIELD("services"), FIELD("regex"), FIELD("replacement"), }; static const rdata_info_t kx_rdata_fields[] = { FIELD("preference"), FIELD("exchanger") }; static const rdata_info_t sig_rdata_fields[] = { FIELD("sigtype"), FIELD("algorithm"), FIELD("labels"), FIELD("origttl"), FIELD("expire"), FIELD("inception"), FIELD("keytag"), FIELD("signer"), FIELD("signature") }; static const rdata_info_t cert_rdata_fields[] = { FIELD("type"), FIELD("key tag"), FIELD("algorithm"), FIELD("certificate") }; static const rdata_info_t dname_rdata_fields[] = { FIELD("source") }; static const rdata_info_t sink_rdata_fields[] = { FIELD("coding"), FIELD("subcoding"), FIELD("data") }; static const rdata_info_t apl_rdata_fields[] = { FIELD("prefix") }; static const rdata_info_t ds_rdata_fields[] = { FIELD("keytag"), FIELD("algorithm"), FIELD("digtype"), FIELD("digest") }; static const rdata_info_t sshfp_rdata_fields[] = { FIELD("algorithm"), FIELD("ftype"), FIELD("fingerprint") }; // IPSECKEY is different because the rdata depends on the algorithm static const rdata_info_t ipseckey_rdata_fields[] = { FIELD("precedence"), FIELD("gateway type"), FIELD("algorithm"), FIELD("gateway"), FIELD("public key") }; static const rdata_info_t rrsig_rdata_fields[] = { FIELD("rrtype"), FIELD("algorithm"), FIELD("labels"), FIELD("origttl"), FIELD("expire"), FIELD("inception"), FIELD("keytag"), FIELD("signer"), FIELD("signature") }; static const rdata_info_t nsec_rdata_fields[] = { FIELD("next"), FIELD("types") }; static const rdata_info_t dnskey_rdata_fields[] = { FIELD("flags"), FIELD("protocol"), FIELD("algorithm"), FIELD("publickey") }; static const rdata_info_t dhcid_rdata_fields[] = { FIELD("dhcpinfo") }; static const rdata_info_t nsec3_rdata_fields[] = { FIELD("algorithm"), FIELD("flags"), FIELD("iterations"), FIELD("salt"), FIELD("next"), FIELD("types") }; static const rdata_info_t nsec3param_rdata_fields[] = { FIELD("algorithm"), FIELD("flags"), FIELD("iterations"), FIELD("salt") }; static const rdata_info_t tlsa_rdata_fields[] = { FIELD("usage"), FIELD("selector"), FIELD("matching type"), FIELD("certificate association data") }; static const rdata_info_t smimea_rdata_fields[] = { FIELD("usage"), FIELD("selector"), FIELD("matching type"), FIELD("certificate association data") }; static const rdata_info_t cds_rdata_fields[] = { FIELD("keytag"), FIELD("algorithm"), FIELD("digtype"), FIELD("digest") }; static const rdata_info_t cdnskey_rdata_fields[] = { FIELD("flags"), FIELD("protocol"), FIELD("algorithm"), FIELD("publickey") }; static const rdata_info_t hip_rdata_fields[] = { FIELD("HIT length"), FIELD("PK algorithm"), FIELD("PK length"), FIELD("HIT"), FIELD("Public Key"), FIELD("Rendezvous Servers") }; // https://www.iana.org/assignments/dns-parameters/NINFO/ninfo-completed-template static const rdata_info_t ninfo_rdata_fields[] = { FIELD("text") }; // https://www.iana.org/assignments/dns-parameters/RKEY/rkey-completed-template static const rdata_info_t rkey_rdata_fields[] = { FIELD("flags"), FIELD("protocol"), FIELD("algorithm"), FIELD("publickey") }; // https://www.iana.org/assignments/dns-parameters/TALINK/talink-completed-template static const rdata_info_t talink_rdata_fields[] = { FIELD("start or previous"), FIELD("end or next") }; static const rdata_info_t openpgpkey_rdata_fields[] = { FIELD("key") }; static const rdata_info_t csync_rdata_fields[] = { FIELD("serial"), FIELD("flags"), FIELD("types") }; static const rdata_info_t zonemd_rdata_fields[] = { FIELD("serial"), FIELD("scheme"), FIELD("algorithm"), FIELD("digest"), }; static const rdata_info_t svcb_rdata_fields[] = { FIELD("priority"), FIELD("target"), FIELD("params") }; static const rdata_info_t https_rdata_fields[] = { FIELD("priority"), FIELD("target"), FIELD("params") }; static const rdata_info_t dsync_rdata_fields[] = { FIELD("rrtype"), FIELD("scheme"), FIELD("port"), FIELD("target") }; static const rdata_info_t spf_rdata_fields[] = { FIELD("text") }; static const rdata_info_t nid_rdata_fields[] = { FIELD("preference"), FIELD("nodeid") }; // RFC6742 specifies the syntax for the locator is compatible with the syntax // for IPv4 addresses, but then proceeds to provide an example with leading // zeroes. The example is corrected in the errata. static const rdata_info_t l32_rdata_fields[] = { FIELD("preference"), FIELD("locator") }; static const rdata_info_t l64_rdata_fields[] = { FIELD("preference"), FIELD("locator") }; static const rdata_info_t lp_rdata_fields[] = { FIELD("preference"), FIELD("pointer") }; static const rdata_info_t eui48_rdata_fields[] = { FIELD("address") }; static const rdata_info_t eui64_rdata_fields[] = { FIELD("address") }; static const rdata_info_t uri_rdata_fields[] = { FIELD("priority"), FIELD("weight"), FIELD("target") }; static const rdata_info_t caa_rdata_fields[] = { FIELD("flags"), FIELD("tag"), FIELD("value") }; // https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template static const rdata_info_t avc_rdata_fields[] = { FIELD("text") }; // draft-durand-doa-over-dns-02 static const rdata_info_t doa_rdata_fields[] = { FIELD("enterprise"), FIELD("type"), FIELD("location"), FIELD("media type"), FIELD("data") }; // RFC 8777 // AMTRELAY is different because the rdata depends on the type static const rdata_info_t amtrelay_rdata_fields[] = { FIELD("precedence"), FIELD("discovery optional"), FIELD("type"), FIELD("relay"), }; // RFC 9606 static const rdata_info_t resinfo_rdata_fields[] = { FIELD("text") }; // https://www.iana.org/assignments/dns-parameters/WALLET/wallet-completed-template static const rdata_info_t wallet_rdata_fields[] = { FIELD("text") }; // https://www.iana.org/assignments/dns-parameters/CLA/cla-completed-template static const rdata_info_t cla_rdata_fields[] = { FIELD("text") }; // https://www.iana.org/assignments/dns-parameters/IPN/ipn-completed-template // and https://datatracker.ietf.org/doc/draft-johnson-dns-ipn-cla/07/ static const rdata_info_t ipn_rdata_fields[] = { FIELD("CBHE Node Number") }; static const rdata_info_t ta_rdata_fields[] = { FIELD("key"), FIELD("algorithm"), FIELD("type"), FIELD("digest") }; static const rdata_info_t dlv_rdata_fields[] = { FIELD("key"), FIELD("algorithm"), FIELD("type"), FIELD("digest") }; // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml static const type_info_t types[] = { UNKNOWN_TYPE(0), TYPE("A", ZONE_TYPE_A, ZONE_CLASS_ANY, FIELDS(a_rdata_fields), check_a_rr, parse_a_rdata), TYPE("NS", ZONE_TYPE_NS, ZONE_CLASS_ANY, FIELDS(ns_rdata_fields), check_ns_rr, parse_ns_rdata), TYPE("MD", ZONE_TYPE_MD, ZONE_CLASS_ANY, FIELDS(md_rdata_fields), // obsolete check_ns_rr, parse_ns_rdata), TYPE("MF", ZONE_TYPE_MF, ZONE_CLASS_ANY, FIELDS(mf_rdata_fields), // obsolete check_ns_rr, parse_ns_rdata), TYPE("CNAME", ZONE_TYPE_CNAME, ZONE_CLASS_ANY, FIELDS(cname_rdata_fields), check_ns_rr, parse_ns_rdata), TYPE("SOA", ZONE_TYPE_SOA, ZONE_CLASS_ANY, FIELDS(soa_rdata_fields), check_soa_rr, parse_soa_rdata), TYPE("MB", ZONE_TYPE_MB, ZONE_CLASS_ANY, FIELDS(mb_rdata_fields), // experimental check_ns_rr, parse_ns_rdata), TYPE("MG", ZONE_TYPE_MG, ZONE_CLASS_ANY, FIELDS(mg_rdata_fields), // experimental check_ns_rr, parse_ns_rdata), TYPE("MR", ZONE_TYPE_MR, ZONE_CLASS_ANY, FIELDS(mr_rdata_fields), // experimental check_ns_rr, parse_ns_rdata), TYPE("NULL", ZONE_TYPE_NULL, ZONE_CLASS_ANY, FIELDS(null_rdata_fields), // experimetal check_generic_rr, parse_unknown_rdata), TYPE("WKS", ZONE_TYPE_WKS, ZONE_CLASS_IN, FIELDS(wks_rdata_fields), check_wks_rr, parse_wks_rdata), TYPE("PTR", ZONE_TYPE_PTR, ZONE_CLASS_ANY, FIELDS(ptr_rdata_fields), check_ns_rr, parse_ns_rdata), TYPE("HINFO", ZONE_TYPE_HINFO, ZONE_CLASS_ANY, FIELDS(hinfo_rdata_fields), check_hinfo_rr, parse_hinfo_rdata), TYPE("MINFO", ZONE_TYPE_MINFO, ZONE_CLASS_ANY, FIELDS(minfo_rdata_fields), check_minfo_rr, parse_minfo_rdata), TYPE("MX", ZONE_TYPE_MX, ZONE_CLASS_ANY, FIELDS(mx_rdata_fields), check_mx_rr, parse_mx_rdata), TYPE("TXT", ZONE_TYPE_TXT, ZONE_CLASS_ANY, FIELDS(txt_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("RP", ZONE_TYPE_RP, ZONE_CLASS_ANY, FIELDS(rp_rdata_fields), check_minfo_rr, parse_minfo_rdata), TYPE("AFSDB", ZONE_TYPE_AFSDB, ZONE_CLASS_ANY, FIELDS(afsdb_rdata_fields), check_mx_rr, parse_mx_rdata), TYPE("X25", ZONE_TYPE_X25, ZONE_CLASS_ANY, FIELDS(x25_rdata_fields), check_x25_rr, parse_x25_rdata), TYPE("ISDN", ZONE_TYPE_ISDN, ZONE_CLASS_ANY, FIELDS(isdn_rdata_fields), check_isdn_rr, parse_isdn_rdata), TYPE("RT", ZONE_TYPE_RT, ZONE_CLASS_ANY, FIELDS(rt_rdata_fields), check_rt_rr, parse_rt_rdata), TYPE("NSAP", ZONE_TYPE_NSAP, ZONE_CLASS_IN, FIELDS(nsap_rdata_fields), check_nsap_rr, parse_nsap_rdata), TYPE("NSAP-PTR", ZONE_TYPE_NSAP_PTR, ZONE_CLASS_IN, FIELDS(nsap_ptr_rdata_fields), check_nsap_ptr_rr, parse_nsap_ptr_rdata), TYPE("SIG", ZONE_TYPE_SIG, ZONE_CLASS_ANY, FIELDS(sig_rdata_fields), check_rrsig_rr, parse_rrsig_rdata), TYPE("KEY", ZONE_TYPE_KEY, ZONE_CLASS_ANY, FIELDS(key_rdata_fields), check_key_rr, parse_key_rdata), TYPE("PX", ZONE_TYPE_PX, ZONE_CLASS_IN, FIELDS(px_rdata_fields), check_px_rr, parse_px_rdata), TYPE("GPOS", ZONE_TYPE_GPOS, ZONE_CLASS_ANY, FIELDS(gpos_rdata_fields), check_gpos_rr, parse_gpos_rdata), TYPE("AAAA", ZONE_TYPE_AAAA, ZONE_CLASS_IN, FIELDS(aaaa_rdata_fields), check_aaaa_rr, parse_aaaa_rdata), TYPE("LOC", ZONE_TYPE_LOC, ZONE_CLASS_ANY, FIELDS(loc_rdata_fields), check_loc_rr, parse_loc_rdata), TYPE("NXT", ZONE_TYPE_NXT, ZONE_CLASS_ANY, FIELDS(nxt_rdata_fields), // obsolete check_nxt_rr, parse_nxt_rdata), TYPE("EID", ZONE_TYPE_EID, ZONE_CLASS_IN, FIELDS(eid_rdata_fields), check_eid_rr, parse_eid_rdata), TYPE("NIMLOC", ZONE_TYPE_NIMLOC, ZONE_CLASS_IN, FIELDS(nimloc_rdata_fields), check_eid_rr, parse_eid_rdata), TYPE("SRV", ZONE_TYPE_SRV, ZONE_CLASS_IN, FIELDS(srv_rdata_fields), check_srv_rr, parse_srv_rdata), TYPE("ATMA", ZONE_TYPE_ATMA, ZONE_CLASS_IN, FIELDS(atma_rdata_fields), check_atma_rr, parse_atma_rdata), TYPE("NAPTR", ZONE_TYPE_NAPTR, ZONE_CLASS_IN, FIELDS(naptr_rdata_fields), check_naptr_rr, parse_naptr_rdata), TYPE("KX", ZONE_TYPE_KX, ZONE_CLASS_IN, FIELDS(kx_rdata_fields), check_mx_rr, parse_mx_rdata), TYPE("CERT", ZONE_TYPE_CERT, ZONE_CLASS_ANY, FIELDS(cert_rdata_fields), check_cert_rr, parse_cert_rdata), UNKNOWN_TYPE(38), TYPE("DNAME", ZONE_TYPE_DNAME, ZONE_CLASS_ANY, FIELDS(dname_rdata_fields), check_ns_rr, parse_ns_rdata), TYPE("SINK", ZONE_TYPE_SINK, ZONE_CLASS_ANY, FIELDS(sink_rdata_fields), check_sink_rr, parse_sink_rdata), UNKNOWN_TYPE(41), TYPE("APL", ZONE_TYPE_APL, ZONE_CLASS_IN, FIELDS(apl_rdata_fields), check_apl_rr, parse_apl_rdata), TYPE("DS", ZONE_TYPE_DS, ZONE_CLASS_ANY, FIELDS(ds_rdata_fields), check_ds_rr, parse_ds_rdata), TYPE("SSHFP", ZONE_TYPE_SSHFP, ZONE_CLASS_ANY, FIELDS(sshfp_rdata_fields), check_sshfp_rr, parse_sshfp_rdata), TYPE("IPSECKEY", ZONE_TYPE_IPSECKEY, ZONE_CLASS_IN, FIELDS(ipseckey_rdata_fields), check_ipseckey_rr, parse_ipseckey_rdata), TYPE("RRSIG", ZONE_TYPE_RRSIG, ZONE_CLASS_ANY, FIELDS(rrsig_rdata_fields), check_rrsig_rr, parse_rrsig_rdata), TYPE("NSEC", ZONE_TYPE_NSEC, ZONE_CLASS_ANY, FIELDS(nsec_rdata_fields), check_nsec_rr, parse_nsec_rdata), TYPE("DNSKEY", ZONE_TYPE_DNSKEY, ZONE_CLASS_ANY, FIELDS(dnskey_rdata_fields), check_dnskey_rr, parse_dnskey_rdata), TYPE("DHCID", ZONE_TYPE_DHCID, ZONE_CLASS_IN, FIELDS(dhcid_rdata_fields), check_dhcid_rr, parse_dhcid_rdata), TYPE("NSEC3", ZONE_TYPE_NSEC3, ZONE_CLASS_ANY, FIELDS(nsec3_rdata_fields), check_nsec3_rr, parse_nsec3_rdata), TYPE("NSEC3PARAM", ZONE_TYPE_NSEC3PARAM, ZONE_CLASS_ANY, FIELDS(nsec3param_rdata_fields), check_nsec3param_rr, parse_nsec3param_rdata), TYPE("TLSA", ZONE_TYPE_TLSA, ZONE_CLASS_ANY, FIELDS(tlsa_rdata_fields), check_tlsa_rr, parse_tlsa_rdata), TYPE("SMIMEA", ZONE_TYPE_SMIMEA, ZONE_CLASS_ANY, FIELDS(smimea_rdata_fields), check_tlsa_rr, parse_tlsa_rdata), UNKNOWN_TYPE(54), TYPE("HIP", ZONE_TYPE_HIP, ZONE_CLASS_ANY, FIELDS(hip_rdata_fields), check_hip_rr, parse_hip_rdata), TYPE("NINFO", ZONE_TYPE_NINFO, ZONE_CLASS_ANY, FIELDS(ninfo_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("RKEY", ZONE_TYPE_RKEY, ZONE_CLASS_ANY, FIELDS(rkey_rdata_fields), check_dnskey_rr, parse_dnskey_rdata), TYPE("TALINK", ZONE_TYPE_TALINK, ZONE_CLASS_ANY, FIELDS(talink_rdata_fields), check_minfo_rr, parse_minfo_rdata), TYPE("CDS", ZONE_TYPE_CDS, ZONE_CLASS_ANY, FIELDS(cds_rdata_fields), check_ds_rr, parse_ds_rdata), TYPE("CDNSKEY", ZONE_TYPE_CDNSKEY, ZONE_CLASS_ANY, FIELDS(cdnskey_rdata_fields), check_dnskey_rr, parse_dnskey_rdata), TYPE("OPENPGPKEY", ZONE_TYPE_OPENPGPKEY, ZONE_CLASS_ANY, FIELDS(openpgpkey_rdata_fields), check_openpgpkey_rr, parse_openpgpkey_rdata), TYPE("CSYNC", ZONE_TYPE_CSYNC, ZONE_CLASS_ANY, FIELDS(csync_rdata_fields), check_csync_rr, parse_csync_rdata), TYPE("ZONEMD", ZONE_TYPE_ZONEMD, ZONE_CLASS_ANY, FIELDS(zonemd_rdata_fields), check_zonemd_rr, parse_zonemd_rdata), TYPE("SVCB", ZONE_TYPE_SVCB, ZONE_CLASS_IN, FIELDS(svcb_rdata_fields), check_svcb_rr, parse_svcb_rdata), TYPE("HTTPS", ZONE_TYPE_HTTPS, ZONE_CLASS_IN, FIELDS(https_rdata_fields), check_https_rr, parse_https_rdata), TYPE("DSYNC", ZONE_TYPE_DSYNC, ZONE_CLASS_ANY, FIELDS(dsync_rdata_fields), check_dsync_rr, parse_dsync_rdata), UNKNOWN_TYPE(67), UNKNOWN_TYPE(68), UNKNOWN_TYPE(69), UNKNOWN_TYPE(70), UNKNOWN_TYPE(71), UNKNOWN_TYPE(72), UNKNOWN_TYPE(73), UNKNOWN_TYPE(74), UNKNOWN_TYPE(75), UNKNOWN_TYPE(76), UNKNOWN_TYPE(77), UNKNOWN_TYPE(78), UNKNOWN_TYPE(79), UNKNOWN_TYPE(80), UNKNOWN_TYPE(81), UNKNOWN_TYPE(82), UNKNOWN_TYPE(83), UNKNOWN_TYPE(84), UNKNOWN_TYPE(85), UNKNOWN_TYPE(86), UNKNOWN_TYPE(87), UNKNOWN_TYPE(88), UNKNOWN_TYPE(89), UNKNOWN_TYPE(90), UNKNOWN_TYPE(91), UNKNOWN_TYPE(92), UNKNOWN_TYPE(93), UNKNOWN_TYPE(94), UNKNOWN_TYPE(95), UNKNOWN_TYPE(96), UNKNOWN_TYPE(97), UNKNOWN_TYPE(98), TYPE("SPF", ZONE_TYPE_SPF, ZONE_CLASS_ANY, FIELDS(spf_rdata_fields), // obsolete check_txt_rr, parse_txt_rdata), UNKNOWN_TYPE(100), UNKNOWN_TYPE(101), UNKNOWN_TYPE(102), UNKNOWN_TYPE(103), TYPE("NID", ZONE_TYPE_NID, ZONE_CLASS_ANY, FIELDS(nid_rdata_fields), check_nid_rr, parse_nid_rdata), TYPE("L32", ZONE_TYPE_L32, ZONE_CLASS_ANY, FIELDS(l32_rdata_fields), check_l32_rr, parse_l32_rdata), TYPE("L64", ZONE_TYPE_L64, ZONE_CLASS_ANY, FIELDS(l64_rdata_fields), check_l64_rr, parse_l64_rdata), TYPE("LP", ZONE_TYPE_LP, ZONE_CLASS_ANY, FIELDS(lp_rdata_fields), check_mx_rr, parse_mx_rdata), TYPE("EUI48", ZONE_TYPE_EUI48, ZONE_CLASS_ANY, FIELDS(eui48_rdata_fields), check_eui48_rr, parse_eui48_rdata), TYPE("EUI64", ZONE_TYPE_EUI64, ZONE_CLASS_ANY, FIELDS(eui64_rdata_fields), check_eui64_rr, parse_eui64_rdata), UNKNOWN_TYPE(110), UNKNOWN_TYPE(111), UNKNOWN_TYPE(112), UNKNOWN_TYPE(113), UNKNOWN_TYPE(114), UNKNOWN_TYPE(115), UNKNOWN_TYPE(116), UNKNOWN_TYPE(117), UNKNOWN_TYPE(118), UNKNOWN_TYPE(119), UNKNOWN_TYPE(120), UNKNOWN_TYPE(121), UNKNOWN_TYPE(122), UNKNOWN_TYPE(123), UNKNOWN_TYPE(124), UNKNOWN_TYPE(125), UNKNOWN_TYPE(126), UNKNOWN_TYPE(127), UNKNOWN_TYPE(128), UNKNOWN_TYPE(129), UNKNOWN_TYPE(130), UNKNOWN_TYPE(131), UNKNOWN_TYPE(132), UNKNOWN_TYPE(133), UNKNOWN_TYPE(134), UNKNOWN_TYPE(135), UNKNOWN_TYPE(136), UNKNOWN_TYPE(137), UNKNOWN_TYPE(138), UNKNOWN_TYPE(139), UNKNOWN_TYPE(140), UNKNOWN_TYPE(141), UNKNOWN_TYPE(142), UNKNOWN_TYPE(143), UNKNOWN_TYPE(144), UNKNOWN_TYPE(145), UNKNOWN_TYPE(146), UNKNOWN_TYPE(147), UNKNOWN_TYPE(148), UNKNOWN_TYPE(149), UNKNOWN_TYPE(150), UNKNOWN_TYPE(151), UNKNOWN_TYPE(152), UNKNOWN_TYPE(153), UNKNOWN_TYPE(154), UNKNOWN_TYPE(155), UNKNOWN_TYPE(156), UNKNOWN_TYPE(157), UNKNOWN_TYPE(158), UNKNOWN_TYPE(159), UNKNOWN_TYPE(160), UNKNOWN_TYPE(161), UNKNOWN_TYPE(162), UNKNOWN_TYPE(163), UNKNOWN_TYPE(164), UNKNOWN_TYPE(165), UNKNOWN_TYPE(166), UNKNOWN_TYPE(167), UNKNOWN_TYPE(168), UNKNOWN_TYPE(169), UNKNOWN_TYPE(170), UNKNOWN_TYPE(171), UNKNOWN_TYPE(172), UNKNOWN_TYPE(173), UNKNOWN_TYPE(174), UNKNOWN_TYPE(175), UNKNOWN_TYPE(176), UNKNOWN_TYPE(177), UNKNOWN_TYPE(178), UNKNOWN_TYPE(179), UNKNOWN_TYPE(180), UNKNOWN_TYPE(181), UNKNOWN_TYPE(182), UNKNOWN_TYPE(183), UNKNOWN_TYPE(184), UNKNOWN_TYPE(185), UNKNOWN_TYPE(186), UNKNOWN_TYPE(187), UNKNOWN_TYPE(188), UNKNOWN_TYPE(189), UNKNOWN_TYPE(190), UNKNOWN_TYPE(191), UNKNOWN_TYPE(192), UNKNOWN_TYPE(193), UNKNOWN_TYPE(194), UNKNOWN_TYPE(195), UNKNOWN_TYPE(196), UNKNOWN_TYPE(197), UNKNOWN_TYPE(198), UNKNOWN_TYPE(199), UNKNOWN_TYPE(200), UNKNOWN_TYPE(201), UNKNOWN_TYPE(202), UNKNOWN_TYPE(203), UNKNOWN_TYPE(204), UNKNOWN_TYPE(205), UNKNOWN_TYPE(206), UNKNOWN_TYPE(207), UNKNOWN_TYPE(208), UNKNOWN_TYPE(209), UNKNOWN_TYPE(210), UNKNOWN_TYPE(211), UNKNOWN_TYPE(212), UNKNOWN_TYPE(213), UNKNOWN_TYPE(214), UNKNOWN_TYPE(215), UNKNOWN_TYPE(216), UNKNOWN_TYPE(217), UNKNOWN_TYPE(218), UNKNOWN_TYPE(219), UNKNOWN_TYPE(220), UNKNOWN_TYPE(221), UNKNOWN_TYPE(222), UNKNOWN_TYPE(223), UNKNOWN_TYPE(224), UNKNOWN_TYPE(225), UNKNOWN_TYPE(226), UNKNOWN_TYPE(227), UNKNOWN_TYPE(228), UNKNOWN_TYPE(229), UNKNOWN_TYPE(230), UNKNOWN_TYPE(231), UNKNOWN_TYPE(232), UNKNOWN_TYPE(233), UNKNOWN_TYPE(234), UNKNOWN_TYPE(235), UNKNOWN_TYPE(236), UNKNOWN_TYPE(237), UNKNOWN_TYPE(238), UNKNOWN_TYPE(239), UNKNOWN_TYPE(240), UNKNOWN_TYPE(241), UNKNOWN_TYPE(242), UNKNOWN_TYPE(243), UNKNOWN_TYPE(244), UNKNOWN_TYPE(245), UNKNOWN_TYPE(246), UNKNOWN_TYPE(247), UNKNOWN_TYPE(248), UNKNOWN_TYPE(249), UNKNOWN_TYPE(250), UNKNOWN_TYPE(251), UNKNOWN_TYPE(252), UNKNOWN_TYPE(253), UNKNOWN_TYPE(254), UNKNOWN_TYPE(255), TYPE("URI", ZONE_TYPE_URI, ZONE_CLASS_ANY, FIELDS(uri_rdata_fields), check_uri_rr, parse_uri_rdata), TYPE("CAA", ZONE_TYPE_CAA, ZONE_CLASS_ANY, FIELDS(caa_rdata_fields), check_caa_rr, parse_caa_rdata), TYPE("AVC", ZONE_TYPE_AVC, ZONE_CLASS_ANY, FIELDS(avc_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("DOA", ZONE_TYPE_DOA, ZONE_CLASS_ANY, FIELDS(doa_rdata_fields), check_doa_rr, parse_doa_rdata), TYPE("AMTRELAY", ZONE_TYPE_AMTRELAY, ZONE_CLASS_ANY, FIELDS(amtrelay_rdata_fields), check_amtrelay_rr, parse_amtrelay_rdata), TYPE("RESINFO", ZONE_TYPE_RESINFO, ZONE_CLASS_ANY, FIELDS(resinfo_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("WALLET", ZONE_TYPE_WALLET, ZONE_CLASS_ANY, FIELDS(wallet_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("CLA", ZONE_TYPE_CLA, ZONE_CLASS_ANY, FIELDS(cla_rdata_fields), check_txt_rr, parse_txt_rdata), TYPE("IPN", ZONE_TYPE_IPN, ZONE_CLASS_ANY, FIELDS(ipn_rdata_fields), check_ipn_rr, parse_ipn_rdata), UNKNOWN_TYPE(265), UNKNOWN_TYPE(266), UNKNOWN_TYPE(267), UNKNOWN_TYPE(268), UNKNOWN_TYPE(269), /* Map 32768 in hash.c to 270 */ TYPE("TA", ZONE_TYPE_TA, ZONE_CLASS_ANY, FIELDS(ta_rdata_fields), // obsolete check_ds_rr, parse_ds_rdata), /* Map 32769 in hash.c to 271 */ TYPE("DLV", ZONE_TYPE_DLV, ZONE_CLASS_ANY, FIELDS(dlv_rdata_fields), // obsolete check_ds_rr, parse_ds_rdata) }; #undef UNKNOWN_CLASS #undef CLASS #undef UNKNOWN_TYPE #undef TYPE diagnostic_pop() #endif // TYPES_H nsd-4.12.0/simdzone/src/generic/type.h0000644000175000017500000001526215002373055017171 0ustar mozziemozzie/* * type.h -- RRTYPE parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TYPE_H #define TYPE_H #define V(code) { &(types[0].name), 0 } #define T(code) { &(types[code].name), 1 } #define C(code) { &(classes[code].name), 2 } // map hash to type or class descriptor (generated using hash.c) static const struct { const mnemonic_t *mnemonic; int32_t code; } types_and_classes[256] = { V(0), V(0), V(0), V(0), V(0), V(0), T(34), V(0), V(0), V(0), T(30), V(0), V(0), T(57), V(0), T(16), V(0), V(0), T(56), T(14), T(12), V(0), V(0), T(13), T(61), V(0), T(105), V(0), V(0), V(0), T(32), T(258), V(0), T(107), T(47), V(0), V(0), V(0), T(17), V(0), T(257), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(65), V(0), V(0), T(18), V(0), T(1), V(0), T(263), V(0), V(0), V(0), V(0), T(51), V(0), V(0), T(106), T(3), V(0), V(0), T(31), V(0), V(0), V(0), V(0), V(0), T(50), T(44), T(104), T(10), V(0), V(0), V(0), V(0), V(0), T(55), V(0), T(28), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(39), T(35), V(0), V(0), T(5), T(29), T(262), V(0), V(0), T(109), V(0), T(264), V(0), V(0), V(0), V(0), V(0), V(0), T(21), V(0), V(0), V(0), V(0), V(0), V(0), T(37), C(1), T(58), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), C(3), V(0), T(52), T(11), T(20), V(0), T(261), V(0), V(0), V(0), T(48), V(0), V(0), V(0), T(25), C(2), T(43), V(0), V(0), C(4), T(60), V(0), V(0), T(7), T(2), V(0), V(0), T(46), T(22), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(64), V(0), T(260), V(0), V(0), V(0), V(0), T(38), V(0), V(0), T(259), T(59), V(0), V(0), V(0), T(42), T(36), T(8), T(15), V(0), T(26), T(27), T(6), V(0), T(99), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(53), T(9), T(63), T(33), V(0), T(271), T(270), V(0), T(40), V(0), V(0), T(24), T(19), V(0), V(0), V(0), V(0), V(0), V(0), V(0), T(108), V(0), V(0), V(0), T(62), V(0), V(0), V(0), V(0), V(0), T(66), T(4), V(0), V(0), V(0), T(256), V(0), T(49), V(0), V(0), V(0), V(0), V(0), T(45), V(0), V(0), T(23), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) }; #undef V #undef T #undef C nonnull_all static really_inline int32_t scan_generic_type( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { if (scan_int16(data + 4, length - 4, code) == 0) return -1; if (*code <= 258) *mnemonic = &types[*code].name; else if (*code == 32769) *mnemonic = &types[259].name; else *mnemonic = &types[0].name; return 1; } nonnull_all static really_inline int32_t scan_generic_class( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { if (scan_int16(data + 5, length - 5, code) == 0) return -1; if (*code <= 4) *mnemonic = &classes[*code].name; else *mnemonic = &classes[0].name; return 2; } #if BYTE_ORDER == LITTLE_ENDIAN # define TYPE (0x45505954llu) # define TYPE_MASK (0xffffffffllu) # define CLASS (0x5353414c43llu) # define CLASS_MASK (0xffffffffffllu) #else # define TYPE (0x5459504500000000llu) # define TYPE_MASK (0xffffffff00000000llu) # define CLASS (0x434c415353000000llu) # define CLASS_MASK (0xffffffffff000000llu) #endif static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static really_inline uint8_t hash(uint64_t prefix) { prefix = le64toh(prefix); uint32_t value = (uint32_t)((prefix >> 32) ^ prefix); // magic value is generated using hash.c, rerun when adding types return (uint8_t)((value * 3537259401ull) >> 32); } nonnull_all static really_inline int32_t scan_type_or_class( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { uint64_t input0, input1; static const uint64_t letter_mask = 0x4040404040404040llu; // safe, input is padded memcpy(&input0, data, 8); memcpy(&input1, data + 8, 8); // convert to upper case input0 = input0 & ~((input0 & letter_mask) >> 1); input1 = input1 & ~((input1 & letter_mask) >> 1); length &= 0x1f; const uint8_t *zero_mask = (const uint8_t *)&zero_masks[32 - (length & 0x1f)]; uint64_t zero_mask0, zero_mask1; // sanitize input memcpy(&zero_mask0, zero_mask, 8); memcpy(&zero_mask1, zero_mask + 8, 8); input0 &= zero_mask0; input1 &= zero_mask1; const uint8_t index = hash(input0); *code = (uint16_t)types_and_classes[index].mnemonic->value; *mnemonic = types_and_classes[index].mnemonic; uint64_t name0, name1; memcpy(&name0, (*mnemonic)->key.data, 8); memcpy(&name1, (*mnemonic)->key.data + 8, 8); if (likely(((input0 ^ name0) | (input1 ^ name1)) == 0) && *code) return types_and_classes[index].code; else if ((input0 & TYPE_MASK) == TYPE) return scan_generic_type(data, length, code, mnemonic); else if ((input0 & CLASS_MASK) == CLASS) return scan_generic_class(data, length, code, mnemonic); return 0; } nonnull_all static really_inline int32_t scan_type( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic) { uint64_t input0, input1; static const uint64_t letter_mask = 0x4040404040404040llu; // safe, input is padded memcpy(&input0, data, 8); memcpy(&input1, data + 8, 8); // convert to upper case input0 = input0 & ~((input0 & letter_mask) >> 1); input1 = input1 & ~((input1 & letter_mask) >> 1); length &= 0x1f; const uint8_t *zero_mask = (const uint8_t *)&zero_masks[32 - (length & 0x1f)]; uint64_t zero_mask0, zero_mask1; // sanitize input memcpy(&zero_mask0, zero_mask, 8); memcpy(&zero_mask1, zero_mask + 8, 8); input0 &= zero_mask0; input1 &= zero_mask1; const uint8_t index = hash(input0); *code = (uint16_t)types_and_classes[index].mnemonic->value; *mnemonic = types_and_classes[index].mnemonic; uint64_t name0, name1; memcpy(&name0, (*mnemonic)->key.data, 8); memcpy(&name1, (*mnemonic)->key.data + 8, 8); if (likely(((input0 ^ name0) | (input1 ^ name1)) == 0) && *code) return types_and_classes[index].code; else if ((input0 & TYPE_MASK) == TYPE) return scan_generic_type(data, length, code, mnemonic); return 0; } #undef TYPE #undef TYPE_MASK #undef CLASS #undef CLASS_MASK #endif // TYPE_H nsd-4.12.0/simdzone/src/generic/ttl.h0000644000175000017500000000724515002373055017015 0ustar mozziemozzie/* * ttl.h -- Time to Live (TTL) parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TTL_H #define TTL_H // [sS] = 1, [mM] = 60, [hH] = 60*60, [dD] = 24*60*60, [wW] = 7*24*60*60 static const uint32_t ttl_units[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x0f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0x1f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20 - 0x2f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30 - 0x3f 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, // 0x40 - 0x4f 0, 0, 0, 1, 0, 0, 0, 604800, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0xf5 0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0, // 0x60 - 0x6f 0, 0, 0, 1, 0, 0, 0, 604800, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0x7f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0x8f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0 - 0xcf 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0 - 0xdf 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0 - 0xef 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xf0 - 0xff }; nonnull_all static really_inline int32_t scan_ttl( const char *data, size_t length, bool allow_units, uint32_t *ttl) { if (scan_int32(data, length, ttl)) return 1; if (!allow_units) return 0; uint64_t sum = 0, number = (uint8_t)data[0] - '0'; // ttls must start with a number. e.g. 1h not h1 if (number > 9) return 0; uint64_t unit = 0, last_unit = 0; enum { NUMBER, UNIT } state = NUMBER; for (size_t count = 1; count < length; count++) { const uint64_t digit = (uint8_t)data[count] - '0'; if (state == NUMBER) { if (digit < 10) { number = number * 10 + digit; if (number > UINT32_MAX) return 0; } else if (!(unit = ttl_units[ (uint8_t)data[count] ])) { return 0; // units must not be repeated e.g. 1m1m } else if (unit == last_unit) { return 0; // greater units must precede smaller units. e.g. 1m1s, not 1s1m } else if (unit < last_unit) { return 0; } else { if (UINT32_MAX / unit < number) return 0; number *= unit; if (UINT32_MAX - sum < number) return 0; last_unit = unit; sum += number; number = 0; state = UNIT; } } else if (state == UNIT) { // units must be followed by a number. e.g. 1h30m, not 1hh if (digit > 9) return 0; // units must not be followed by a number if smallest unit, // i.e. seconds, was previously specified if (last_unit == 1) return 0; number = digit; state = NUMBER; } } if (UINT32_MAX - sum < number) return 0; sum += number; *ttl = (uint32_t)sum; return 1; } nonnull_all static really_inline int32_t parse_ttl( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint32_t ttl; if (!scan_ttl(token->data, token->length, parser->options.pretty_ttls, &ttl)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); // FIXME: comment RFC2308 msb if (ttl & (1u << 31)) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); ttl = htobe32(ttl); memcpy(rdata->octets, &ttl, sizeof(ttl)); rdata->octets += 4; return 0; } #endif // TTL_H nsd-4.12.0/simdzone/src/generic/time.h0000644000175000017500000000470415002373055017145 0ustar mozziemozzie/* * time.h -- timestamp parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TIME_H #define TIME_H /* number of days per month (except for February in leap years) */ static const uint8_t days_in_month[13] = { 0 /* no --month */, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static const uint16_t days_to_month[13] = { 0 /* no --month */, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; static uint64_t is_leap_year(uint64_t year) { return (year % 4 == 0) & ((year % 100 != 0) | (year % 400 == 0)); } static uint64_t leap_days(uint64_t y1, uint64_t y2) { --y1; --y2; return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); } nonnull_all static really_inline int32_t parse_time( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { if (token->length != 14) return parse_int32(parser, type, field, rdata, token); uint64_t d[14]; // YYYYmmddHHMMSS const char *p = token->data; for (int i = 0; i < 14; i++) { d[i] = (uint8_t)p[i] - '0'; if (d[i] > 9) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } // code adapted from Python 2.4.1 sources (Lib/calendar.py) const uint64_t year = (d[0] * 1000) + (d[1] * 100) + (d[2] * 10) + d[3]; const uint64_t mon = (d[4] * 10) + d[5]; const uint64_t mday = (d[6] * 10) + d[7]; const uint64_t hour = (d[8] * 10) + d[9]; const uint64_t min = (d[10] * 10) + d[11]; const uint64_t sec = (d[12] * 10) + d[13]; if (year < 1970) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); uint64_t leap_year = is_leap_year(year); uint64_t days = 365 * (year - 1970) + leap_days(1970, year); if (!mon || mon > 12) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); if (!mday || mday > days_in_month[mon] + (leap_year & (mon == 2))) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); if (hour > 23 || min > 59 || sec > 59) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); days += days_to_month[mon]; days += (mon > 2) & leap_year; days += mday - 1; const uint64_t hours = days * 24 + hour; const uint64_t minutes = hours * 60 + min; const uint64_t seconds = minutes * 60 + sec; uint32_t time = htobe32((uint32_t)seconds); memcpy(rdata->octets, &time, sizeof(time)); rdata->octets += 4; return 0; } #endif // TIME_H nsd-4.12.0/simdzone/src/generic/text.h0000644000175000017500000000436515002373055017176 0ustar mozziemozzie/* * text.h -- string parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TEXT_H #define TEXT_H nonnull_all static really_inline uint32_t unescape(const char *text, uint8_t *wire) { uint8_t d[3]; uint32_t o; if ((d[0] = (uint8_t)text[1] - '0') > 9) { o = (uint8_t)text[1]; *wire = (uint8_t)o; return 2u; } else { d[1] = (uint8_t)text[2] - '0'; d[2] = (uint8_t)text[3] - '0'; o = d[0] * 100 + d[1] * 10 + d[2]; *wire = (uint8_t)o; return (o > 255 || d[1] > 9 || d[2] > 9) ? 0 : 4u; } } typedef struct string_block string_block_t; struct string_block { uint64_t backslashes; }; nonnull_all static really_inline void copy_string_block( string_block_t *block, const char *text, uint8_t *wire) { simd_8x32_t input; simd_loadu_8x32(&input, text); simd_storeu_8x32(wire, &input); block->backslashes = simd_find_8x32(&input, '\\'); } nonnull_all static really_inline int32_t scan_string( const char *data, size_t length, uint8_t *octets, const uint8_t *limit) { const char *text = data; uint8_t *wire = octets; string_block_t block; copy_string_block(&block, text, octets); uint64_t count = 32; if (length < 32) count = length; uint64_t mask = (1llu << count) - 1u; // check for escape sequences if (unlikely(block.backslashes & mask)) goto escaped; if (length < 32) return (int32_t)count; text += count; wire += count; length -= count; do { copy_string_block(&block, text, wire); count = 32; if (length < 32) count = length; mask = (1llu << count) - 1u; // check for escape sequences if (unlikely(block.backslashes & mask)) { escaped: block.backslashes &= -block.backslashes; mask = block.backslashes - 1; count = count_ones(mask); const uint32_t octet = unescape(text+count, wire+count); if (!octet) return -1; text += count + octet; wire += count + 1; length -= count + octet; } else { text += count; wire += count; length -= count; } } while (length && wire < limit); if (length || (wire > limit)) return -1; assert(!length); return (int32_t)(wire - octets); } #endif // TEXT_H nsd-4.12.0/simdzone/src/generic/svcb.h0000644000175000017500000010146515002373055017146 0ustar mozziemozzie/* * svcb.h -- svcb (RFC9460) parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef SVCB_H #define SVCB_H #include // RFC9460 section 7.1: // The "alpn" and "no-default-alpn" SvcParamKeys together indicate the set // of Application-Layer Protocol Negotiation (ALPN) protocol identifiers // [ALPN] and associated transport protocols supported by this service // endpoint (the "SVCB ALPN set"). // // RFC9460 section 7.1.1: // ALPNs are identified by their registered "Identification Sequence" // (alpn-id), which is a sequence of 1-255 octets. For "alpn", the // presentation value SHALL be a comma-separated list (Appendix A.1) of // one or more alpn-ids. Zone-file implementations MAY disallow the "," // and "\" characters in ALPN IDs instead of implementing the value-list // escaping procedure, relying on the opaque key format (e.g., key=\002h2) // in the event that these characters are needed. // // Application-Layer Protocol Negotiation (ALPN) protocol identifiers are // maintained by IANA: // // https://www.iana.org/assignments/tls-extensiontype-values#alpn-protocol-ids // // RFC9460 section 7.1.1: // For "alpn", the presentation value SHALL be a comma-separated list // (Appendix A.1) of one or more alpn-ids. Zone-file implementations MAY // disallow the "," and "\" characters in ALPN IDs instead of implementing // the value-list escaping procedure, relying on the opaque key format // (e.g., key1=\002h2) in the event that these characters are needed. // // RFC9460 appendix A.1: // A value-list parser that splits on "," and prohibits items containing // "\\" is sufficient to comply with all requirements in this document. // // RFC9460 appendix A.1: // Decoding of value-lists happens after character-string decoding. // // // // RFC9460 (somewhat incorrectly) states that an SvcParamValue is a // character-string. An SvcParamValue is just that, an SvcParamValue. The // presentation format is not a context-free format like JSON. Tokens can be // identified, not classified, by syntax. // // Context-free languages (e.g. C, JSON) classify a token as a string if it is // quoted, an identifier or keyword if it is a contiguous set of characters, // etc. Unescaping is done by the scanner because the token is classified // during that stage. The presentation format defines basic syntax to identify // tokens, but as the format is NOT context-free and intentionally extensible, // the token is classified by the parser. Conversion of domain names from text // format to wire format is a prime example. // // Example: // "foo. NS bar\." defines "bar\." as a relative domain. The "\" (backslash) // is important because it signals that the trailing dot does not serve as a // label separator. // // Note that RFC9460 is contradicts itself by stating that the value-list // escaping procedure may rely on the opaque key format (e.g., key1=\002h2) // in the event that these characters are needed. Escaping using \DDD, if // SvcParamValue is indeed to be interpreted as a string, would produce // 0x03 0x02 0x68 0x32 in wire format. // // IETF mailing list discussion on this topic: // https://mailarchive.ietf.org/arch/msg/dnsop/SXnlsE1B8gmlDjn4HtOo1lwtqAI/ // // // BIND disallows any escape sequences in port, ipv4hint, etc. Regular // (single stage) escaping rules are applied to dohpath. Special (two stage) // escaping rules apply for alpn. // // Knot disallows escape sequences in port, ipv4hint, etc. kzonecheck 3.3.4 // does not to accept dohpath. Special (two stage) escaping rules apply for // alpn. nonnull_all static int32_t parse_alpn( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { assert(rdata->octets < rdata->limit); (void)field; (void)key; (void)param; uint8_t *comma = rdata->octets++; const char *data = token->data, *limit = token->data + token->length; while (data < limit && rdata->octets < rdata->limit) { *rdata->octets = (uint8_t)*data; if (unlikely(*rdata->octets == '\\')) { uint32_t length; if (!(length = unescape(data, rdata->octets))) SYNTAX_ERROR(parser, "Invalid alpn in %s", NAME(type)); data += length; // second level escape processing if (*rdata->octets == '\\') { assert(length); if (*data == '\\') { if (!(length = unescape(data, rdata->octets))) SYNTAX_ERROR(parser, "Invalid alpn in %s", NAME(type)); data += length; } else { *rdata->octets = (uint8_t)*data; data++; } rdata->octets++; continue; } } else { data++; } if (*rdata->octets == ',') { assert(comma < rdata->octets); const size_t length = ((uintptr_t)rdata->octets - (uintptr_t)comma) - 1; if (!length || length > 255) SYNTAX_ERROR(parser, "Invalid alpn in %s", NAME(type)); *comma = (uint8_t)length; comma = rdata->octets; } rdata->octets++; } if (data != limit || rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid alpn in %s", NAME(type)); const size_t length = ((uintptr_t)rdata->octets - (uintptr_t)comma) - 1; if (!length || length > 255) SYNTAX_ERROR(parser, "Invalid alpn in %s", NAME(type)); *comma = (uint8_t)length; return 0; } nonnull_all static int32_t parse_port( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *data = token->data; (void)field; (void)key; (void)param; if (!token->length || token->length > 5) SYNTAX_ERROR(parser, "Invalid port in %s", NAME(type)); uint64_t number = 0; for (;; data++) { const uint64_t digit = (uint8_t)*data - '0'; if (digit > 9) break; number = number * 10 + digit; } uint16_t port = (uint16_t)number; port = htobe16(port); memcpy(rdata->octets, &port, 2); rdata->octets += 2; if (rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); if (data != token->data + token->length || number > 65535) SYNTAX_ERROR(parser, "Invalid port in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_ipv4hint( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *t = token->data, *te = token->data + token->length; size_t n = 0; (void)field; (void)key; (void)param; if ((n = (size_t)scan_ip4(t, rdata->octets)) == 0) SYNTAX_ERROR(parser, "Invalid ipv4hint in %s", NAME(type)); rdata->octets += 4; t += n; while (*t == ',') { if (rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid ipv4hint in %s", NAME(type)); if ((n = (size_t)scan_ip4(t + 1, rdata->octets)) == 0) SYNTAX_ERROR(parser, "Invalid ipv4hint in %s", NAME(type)); rdata->octets += 4; t += n + 1; } if (t != te || rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid ipv4hint in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_ech( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { size_t size = (uintptr_t)rdata->limit - (uintptr_t)rdata->octets; size_t length; (void)field; (void)key; (void)param; if (token->length / 4 > size / 3) SYNTAX_ERROR(parser, "maximum size exceeded"); struct base64_state state = { .eof = 0, .bytes = 0, .carry = 0 }; if (!base64_stream_decode( &state, token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid ech in %s", NAME(type)); rdata->octets += length; if (state.bytes) SYNTAX_ERROR(parser, "Invalid ech in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_ipv6hint( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *t = token->data, *te = token->data + token->length; size_t n = 0; (void)field; (void)key; (void)param; if ((n = (size_t)scan_ip6(t, rdata->octets)) == 0) SYNTAX_ERROR(parser, "Invalid ipv6hint in %s", NAME(type)); rdata->octets += 16; t += n; while (*t == ',') { if (rdata->octets >= rdata->limit) SYNTAX_ERROR(parser, "Invalid ipv6hint in %s", NAME(type)); if ((n = (size_t)scan_ip6(t + 1, rdata->octets)) == 0) SYNTAX_ERROR(parser, "Invalid ipv6hint in %s", NAME(type)); rdata->octets += 16; t += n + 1; } if (t != te || rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid ipv6hint in %s", NAME(type)); return 0; } // RFC9461 section 5: // "dohpath" is a single-valued SvcParamKey whose value (in both // presentation format and wire format) MUST be a URI Template in // relative form ([RFC6570], Section 1.1) encoded in UTF-8 [RFC3629]. nonnull_all static int32_t parse_dohpath( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *t = token->data, *te = t + token->length; (void)field; (void)key; (void)param; // FIXME: easily optimized using SIMD (and possibly SWAR) while ((t < te) & (rdata->octets < rdata->limit)) { *rdata->octets = (uint8_t)*t; if (*t == '\\') { uint32_t o; if (!(o = unescape(t, rdata->octets))) SYNTAX_ERROR(parser, "Invalid dohpath in %s", NAME(type)); rdata->octets += 1; t += o; } else { rdata->octets += 1; t += 1; } } // RFC9461 section 5: // The URI Template MUST contain a "dns" variable, and MUST be chosen such // that the result after DoH URI Template expansion (RFC8484 section 6) // is always a valid and function ":path" value (RFC9113 section 8.3.1) // FIXME: implement if (t != te || rdata->octets >= rdata->limit) SYNTAX_ERROR(parser, "Invalid dohpath in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_unknown( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *t = token->data, *te = t + token->length; (void)key; (void)param; while ((t < te) & (rdata->octets < rdata->limit)) { *rdata->octets = (uint8_t)*t; if (*t == '\\') { uint32_t o; if (!(o = unescape(t, rdata->octets))) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets += 1; t += o; } else { rdata->octets += 1; t += 1; } } if (t != te || rdata->octets >= rdata->limit) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return 0; } nonnull_all static int32_t parse_tls_supported_groups( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { const char *t = token->data, *te = token->data + token->length; const uint8_t *rdata_start = rdata->octets; (void)field; (void)key; (void)param; while (t < te && rdata->octets+2 <= rdata->limit) { uint64_t number = 0; for (;; t++) { const uint64_t digit = (uint8_t)*t - '0'; if (digit > 9) break; number = number * 10 + digit; } uint16_t group = (uint16_t)number; group = htobe16(group); memcpy(rdata->octets, &group, 2); rdata->octets += 2; if (number > 65535) SYNTAX_ERROR(parser, "Invalid tls-supported-group in %s", NAME(type)); const uint8_t *g; for (g = rdata_start; g < rdata->octets - 2; g += 2) { if (memcmp(g, &group, 2) == 0) SEMANTIC_ERROR(parser, "Duplicate group in tls-supported-groups in %s", NAME(type)); } if (*t != ',') break; else t++; } if (t != te || rdata->octets > rdata->limit) SYNTAX_ERROR(parser, "Invalid tls-supported-groups in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_mandatory_lax( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *svc_param, rdata_t *rdata, const token_t *token); nonnull_all static int32_t parse_mandatory( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *svc_param, rdata_t *rdata, const token_t *token); #define SVC_PARAM(name, key, value, parse, parse_lax) \ { { { name, sizeof(name) - 1 }, key }, value, parse, parse_lax } #define NO_VALUE (0u) #define OPTIONAL_VALUE (1u << 1) #define MANDATORY_VALUE (1u << 2) static const svc_param_info_t svc_params[] = { // RFC9460 section 8: // The presentation value SHALL be a comma-separated list (Appendix A.1) // of one or more valid SvcParamKeys ... SVC_PARAM("mandatory", 0u, MANDATORY_VALUE, parse_mandatory, parse_mandatory_lax), SVC_PARAM("alpn", 1u, MANDATORY_VALUE, parse_alpn, parse_alpn), // RFC9460 section 7.1.1: // For "no-default-alpn", the presentation and wire format values MUST be // empty. When "no-default-alpn" is specified in an RR, "alpn" must also be // specified in order for the RR to be "self-consistent" (Section 2.4.3). SVC_PARAM("no-default-alpn", 2u, NO_VALUE, parse_unknown, parse_unknown), // RFC9460 section 7.2: // The presentation value of the SvcParamValue is a single decimal integer // between 0 and 65535 in ASCII. ... SVC_PARAM("port", 3u, MANDATORY_VALUE, parse_port, parse_port), // RFC9460 section 7.3: // The presentation value SHALL be a comma-separated list (Appendix A.1) // of one or more IP addresses ... SVC_PARAM("ipv4hint", 4u, MANDATORY_VALUE, parse_ipv4hint, parse_ipv4hint), SVC_PARAM("ech", 5u, OPTIONAL_VALUE, parse_ech, parse_ech), // RFC9460 section 7.3: // See "ipv4hint". SVC_PARAM("ipv6hint", 6u, MANDATORY_VALUE, parse_ipv6hint, parse_ipv6hint), // RFC9461 section 5: // If the "alpn" SvcParam indicates support for HTTP, "dohpath" MUST be // present. SVC_PARAM("dohpath", 7u, MANDATORY_VALUE, parse_dohpath, parse_dohpath), // RFC9540 section 4. // Both the presentation and wire-format values for the "ohttp" parameter // MUST be empty. SVC_PARAM("ohttp", 8u, NO_VALUE, parse_unknown, parse_unknown), // draft-ietf-tls-key-share-prediction-01 section 3.1 SVC_PARAM("tls-supported-groups", 9u, MANDATORY_VALUE, parse_tls_supported_groups, parse_tls_supported_groups), }; static const svc_param_info_t unknown_svc_param = SVC_PARAM("unknown", 0u, OPTIONAL_VALUE, parse_unknown, parse_unknown); #undef SVC_PARAM nonnull_all static really_inline size_t scan_unknown_svc_param_key( const char *data, uint16_t *key, const svc_param_info_t **param) { size_t length = 4; uint32_t number = (uint8_t)data[3] - '0'; if (number > 9) return 0; uint32_t leading_zero = number == 0; for (;; length++) { const uint32_t digit = (uint8_t)data[length] - '0'; if (digit > 9) break; number = number * 10 + digit; } leading_zero &= length > 4; if (leading_zero || length > 3 + 5) return 0; if (number < (sizeof(svc_params) / sizeof(svc_params[0]))) return (void)(*param = &svc_params[(*key = (uint16_t)number)]), length; if (number < 65535) return (void)(*key = (uint16_t)number), (void)(*param = &unknown_svc_param), length; return 0; } nonnull_all static really_inline size_t scan_svc_param( const char *data, uint16_t *key, const svc_param_info_t **param) { // draft-ietf-dnsop-svcb-https-12 section 2.1: // alpha-lc = %x61-7A ; a-z // SvcParamKey = 1*63(alpha-lc / DIGIT / "-") // // FIXME: naive implementation if (memcmp(data, "mandatory", 9) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_MANDATORY)]), 9; else if (memcmp(data, "alpn", 4) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_ALPN)]), 4; else if (memcmp(data, "no-default-alpn", 15) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_NO_DEFAULT_ALPN)]), 15; else if (memcmp(data, "port", 4) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_PORT)]), 4; else if (memcmp(data, "ipv4hint", 8) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_IPV4HINT)]), 8; else if (memcmp(data, "ech", 3) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_ECH)]), 3; else if (memcmp(data, "ipv6hint", 8) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_IPV6HINT)]), 8; else if (memcmp(data, "dohpath", 7) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_DOHPATH)]), 7; else if (memcmp(data, "ohttp", 5) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_OHTTP)]), 5; else if (memcmp(data, "tls-supported-groups", 20) == 0) return (void)(*param = &svc_params[(*key = ZONE_SVC_PARAM_KEY_TLS_SUPPORTED_GROUPS)]), 20; else if (memcmp(data, "key", 3) == 0) return scan_unknown_svc_param_key(data, key, param); else return 0; } nonnull_all static really_inline size_t scan_svc_param_key( const char *data, uint16_t *key) { // FIXME: improve implementation const svc_param_info_t *param; return scan_svc_param(data, key, ¶m); } nonnull_all static int32_t parse_mandatory( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { (void)field; (void)param; // RFC9460 section 8: // This SvcParamKey is always automatically mandatory and MUST NOT appear // in its own value-list. Other automatically mandatory keys SHOULD NOT // appear in the list either. uint64_t mandatory = (1u << ZONE_SVC_PARAM_KEY_MANDATORY); uint64_t keys = 0u; int32_t highest_key = -1; const char *data = token->data; uint8_t *whence = rdata->octets; size_t skip; // RFC9460 section 9: // The "automatically mandatory" keys (Section 8) are "port" and // "no-default-alpn". if (type->name.value == ZONE_TYPE_HTTPS) mandatory = (1u << ZONE_SVC_PARAM_KEY_MANDATORY) | (1u << ZONE_SVC_PARAM_KEY_NO_DEFAULT_ALPN) | (1u << ZONE_SVC_PARAM_KEY_PORT); // RFC9460 section 8: // The presentation value SHALL be a comma-seperatred list of one or more // valid SvcParamKeys, ... if (!(skip = scan_svc_param_key(data, &key))) SYNTAX_ERROR(parser, "Invalid mandatory in %s", NAME(type)); if (key < 64) keys = 1llu << key; highest_key = key; key = htobe16(key); memcpy(rdata->octets, &key, sizeof(key)); rdata->octets += sizeof(key); data += skip; while (*data == ',' && rdata->octets < rdata->limit) { if (!(skip = scan_svc_param_key(data + 1, &key))) SYNTAX_ERROR(parser, "Invalid mandatory of %s", NAME(type)); // check if key appears in automatically mandatory key list if (key < 64) keys |= 1llu << key; data += skip + 1; if (key > highest_key) { highest_key = key; key = htobe16(key); memcpy(rdata->octets, &key, 2); rdata->octets += 2; } else { // RFC9460 section 8: // In wire format, the keys are represented by their numeric values in // network byte order, concatenated in ascending order. uint8_t *octets = whence; uint16_t smaller_key = 0; while (octets < rdata->octets) { memcpy(&smaller_key, octets, sizeof(smaller_key)); smaller_key = be16toh(smaller_key); if (key <= smaller_key) break; octets += 2; } assert(octets <= rdata->octets); // RFC9460 section 8: // Keys MAY appear in any order, but MUST NOT appear more than once. if (key == smaller_key) SEMANTIC_ERROR(parser, "Duplicate key in mandatory of %s", NAME(type)); assert(key < smaller_key); uint16_t length = (uint16_t)(rdata->octets - octets); memmove(octets + 2, octets, length); key = htobe16(key); memcpy(octets, &key, 2); rdata->octets += 2; } } if (keys & mandatory) SEMANTIC_ERROR(parser, "Automatically mandatory key(s) in mandatory of %s", NAME(type)); if (rdata->octets >= rdata->limit) SYNTAX_ERROR(parser, "Invalid mandatory in %s", NAME(type)); if (data != token->data + token->length) SYNTAX_ERROR(parser, "Invalid mandatory in %s", NAME(type)); return 0; } nonnull_all static int32_t parse_mandatory_lax( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, rdata_t *rdata, const token_t *token) { (void)field; // RFC9460 section 8: // This SvcParamKey is always automatically mandatory and MUST NOT appear // in its own value-list. Other automatically mandatory keys SHOULD NOT // appear in the list either. uint64_t mandatory = (1u << ZONE_SVC_PARAM_KEY_MANDATORY); uint64_t keys = 0; // RFC9460 section 8: // In wire format, the keys are represented by their numeric values in // network byte order, concatenated in strictly increasing numeric order. // // cannot reorder in secondary mode, print an error bool out_of_order = false; int32_t highest_key = -1; const uint8_t *whence = rdata->octets; const char *data = token->data; size_t skip; // RFC9460 section 8: // The presentation value SHALL be a comma-seperatred list of one or more // valid SvcParamKeys, ... if (!(skip = scan_svc_param_key(data, &key))) SYNTAX_ERROR(parser, "Invalid key in %s of %s", NAME(param), NAME(type)); if (key < 64) keys |= 1llu << key; // RFC9460 section 9: // The "automatically mandatory" keys (Section 8) are "port" and // "no-default-alpn". if (type->name.value == ZONE_TYPE_HTTPS) mandatory = (1u << ZONE_SVC_PARAM_KEY_MANDATORY) | (1u << ZONE_SVC_PARAM_KEY_NO_DEFAULT_ALPN) | (1u << ZONE_SVC_PARAM_KEY_PORT); key = htobe16(key); memcpy(rdata->octets, &key, 2); rdata->octets += 2; data += skip; while (*data == ',' && rdata->octets < rdata->limit) { if (!(skip = scan_svc_param_key(data + 1, &key))) SYNTAX_ERROR(parser, "Invalid key in %s of %s", NAME(param), NAME(type)); // check if key appears in automatically mandatory key list if (key < 64) keys |= (1llu << key); if ((int32_t)key <= highest_key) { // RFC9460 section 8: // In wire format, the keys are represented by their numeric values in // network byte order, concatenated in ascending order. const uint8_t *octets = whence; uint16_t smaller_key = 0; while (octets < rdata->octets) { memcpy(&smaller_key, octets, sizeof(smaller_key)); smaller_key = be16toh(smaller_key); if (key <= smaller_key) break; octets += 2; } assert(octets <= rdata->octets); // RFC9460 section 8: // Keys MAY appear in any order, but MUST NOT appear more than once. if (key == smaller_key) SEMANTIC_ERROR(parser, "Duplicate key in mandatory of %s", NAME(type)); assert(key < smaller_key); out_of_order = true; } data += skip + 1; key = htobe16(key); memcpy(rdata->octets, &key, 2); rdata->octets += 2; } if (keys & mandatory) SEMANTIC_ERROR(parser, "Automatically mandatory key(s) in mandatory of %s", NAME(type)); if (out_of_order) SEMANTIC_ERROR(parser, "Out of order keys in mandatory of %s", NAME(type)); if (rdata->octets >= rdata->limit - 2) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); if (data != token->data + token->length) SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); return 0; } nonnull_all static really_inline int32_t check_mandatory( zone_parser_t *parser, const type_info_t *type, const rdata_info_t *field, const rdata_t *rdata, const uint8_t *parameters) { // parameters are guaranteed to be in order (automatic in strict mode) if (parameters[0] || parameters[1]) return 0; // no mandatory parameter uint16_t length; memcpy(&length, parameters + 2, sizeof(length)); length = be16toh(length); assert(rdata->octets - parameters >= 4 + length); bool missing_keys = false; const uint8_t *limit = parameters + 4 + length; const uint8_t *keys = parameters + 4; parameters += 4 + length; assert(parameters <= rdata->octets); for (; keys < limit; keys += 2) { uint16_t key; memcpy(&key, keys, sizeof(key)); // no byteswap, compare big endian // mandatory is guaranteed to exist if (key == 0) continue; if ((missing_keys = (parameters == rdata->octets))) break; assert(rdata->octets - parameters >= 4); memcpy(&length, parameters + 2, 2); length = be16toh(length); assert(rdata->octets - parameters >= 4 + length); // parameters are guaranteed to be sorted if (memcmp(parameters, &key, 2) == 0) { parameters += 4 + length; } else { const uint8_t *parameter = parameters + 4 + length; assert(rdata->octets - parameters >= 4); while (parameter < rdata->octets) { if (memcmp(parameter, &key, 2) == 0) break; memcpy(&length, parameter + 2, 2); length = be16toh(length); assert(rdata->octets - parameters >= 4 + length); parameter += 4 + length; } if ((missing_keys = (parameter == rdata->octets))) break; } } if (missing_keys) SEMANTIC_ERROR(parser, "Mandatory %s missing in %s", NAME(field), NAME(type)); return 0; } nonnull((1, 2, 3, 5, 7)) static really_inline int32_t parse_svc_param( parser_t *parser, const type_info_t *type, const rdata_info_t *field, uint16_t key, const svc_param_info_t *param, const parse_svc_param_t parse, rdata_t *rdata, const token_t *token) { switch ((token != NULL) | param->has_value) { case 0: // void parameter without value return 0; case 1: // void parameter with value assert(token); SEMANTIC_ERROR(parser, "%s with value in %s", NAME(field), NAME(type)); if (unlikely(!token->length)) return 0; break; case 2: // parameter without optional value return 0; case 3: // parameter with optional value assert(token); if (unlikely(!token->length)) return 0; break; case 4: // parameter without value SEMANTIC_ERROR(parser, "%s without value in %s", NAME(field), NAME(type)); return 0; case 5: // parameter with value assert(token); if (unlikely(!token->length)) SEMANTIC_ERROR(parser, "%s without value in %s", NAME(field), NAME(type)); break; } return parse(parser, type, field, key, param, rdata, token); } nonnull_all static int32_t parse_svc_params_lax( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, token_t *token) { bool out_of_order = false; int32_t code, highest_key = -1; uint32_t errors = 0; const uint8_t *whence = rdata->octets; uint64_t keys = 0; // FIXME: check if parameter even fits while (is_contiguous(token)) { size_t count; uint16_t key; const svc_param_info_t *param; const token_t *value = token; if (!(count = scan_svc_param(token->data, &key, ¶m))) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); assert(param); if (likely(key > highest_key)) highest_key = key; else out_of_order = true; if (key < 64) keys |= (1llu << key); if (token->data[count] != '=') value = NULL; else if (token->data[count+1] != '"') (void)(token->data += count + 1), token->length -= count + 1; else if ((code = take_quoted(parser, type, field, token)) < 0) return code; uint8_t *octets = rdata->octets; uint16_t length; rdata->octets += 4; if ((code = parse_svc_param( parser, type, field, key, param, param->parse_lax, rdata, value)) < 0) return code; errors += (code != 0); key = htobe16(key); memcpy(octets, &key, sizeof(key)); assert(rdata->octets >= octets && (rdata->octets - octets) <= 65535 + 4); length = (uint16_t)((rdata->octets - octets) - 4); length = htobe16(length); memcpy(octets + 2, &length, sizeof(length)); take(parser, token); } if (likely(errors == 0 && whence != rdata->octets)) { assert(whence <= rdata->octets + 4); if (unlikely(out_of_order)) { SEMANTIC_ERROR(parser, "Out of order %s in %s", NAME(field), NAME(type)); } else { // warn about missing or out-of-order parameters if (keys & 0x01) check_mandatory(parser, type, field, rdata, whence); // RFC9460 section 7.2: // For "no-default-alpn", the presentation and wire-format values MUST // be empty. When "no-default-alpn" is specified in an RR, "alpn" must // also be specified in order for the RR to be "self-consistent" // (Section 2.4.3). if ((keys & 0x04) && !(keys & 0x02)) SEMANTIC_ERROR(parser, "%s with no-default-alpn but without alpn in %s", NAME(field), NAME(type)); } } return have_delimiter(parser, type, token); } // https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml nonnull_all static really_inline int32_t parse_svc_params( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, token_t *token) { // propagate data as-is if secondary if (parser->options.secondary) return parse_svc_params_lax(parser, type, field, rdata, token); int32_t code; int32_t highest_key = -1; uint8_t *whence = rdata->octets; uint64_t keys = 0; while (is_contiguous(token)) { size_t count; uint16_t key; const token_t *value = token; const svc_param_info_t *param; if (!(count = scan_svc_param(token->data, &key, ¶m))) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); assert(param); if (key < 64) keys |= (1llu << key); if (token->data[count] != '=') value = NULL; else if (token->data[count+1] != '"') (void)(token->data += count + 1), token->length -= count + 1; else if ((code = take_quoted(parser, type, field, token)) < 0) return code; uint8_t *octets; uint16_t length; if (likely(key > highest_key)) { highest_key = key; octets = rdata->octets; rdata->octets += 4; if ((code = parse_svc_param( parser, type, field, key, param, param->parse, rdata, value))) return code; assert(rdata->octets >= octets && (rdata->octets - octets) <= 65535 + 4); length = (uint16_t)((rdata->octets - octets) - 4); } else { octets = whence; uint16_t smaller_key = 65535; // this can probably be done in a function or something while (octets < rdata->octets) { memcpy(&smaller_key, octets, sizeof(smaller_key)); smaller_key = be16toh(smaller_key); if (key <= smaller_key) break; memcpy(&length, octets + 2, sizeof(length)); length = be16toh(length); octets += length + 4; } assert(octets < rdata->octets); if (key == smaller_key) SEMANTIC_ERROR(parser, "Duplicate key in %s", NAME(type)); rdata_t rdata_view; // RFC9460 section 2.2: // SvcParamKeys SHALL appear in increasing numeric order. // // move existing data to end of the buffer and reset limit to // avoid allocating memory assert(rdata->octets - octets < ZONE_RDATA_SIZE); length = (uint16_t)(rdata->octets - octets); rdata_view.octets = octets + 4u; rdata_view.limit = parser->rdata->octets + (ZONE_RDATA_SIZE - length); // move data PADDING_SIZE past limit to ensure SIMD operatations // do not overwrite existing data memmove(rdata_view.limit + ZONE_BLOCK_SIZE, octets, length); if ((code = parse_svc_param( parser, type, field, key, param, param->parse, &rdata_view, token))) return code; assert(rdata_view.octets < rdata_view.limit); memmove(rdata_view.octets, rdata_view.limit + ZONE_BLOCK_SIZE, length); rdata->octets = rdata_view.octets + length; length = (uint16_t)(rdata_view.octets - octets) - 4u; } key = htobe16(key); memcpy(octets, &key, sizeof(key)); length = htobe16(length); memcpy(octets + 2, &length, sizeof(length)); take(parser, token); } if ((code = have_delimiter(parser, type, token))) return code; assert(whence); if ((keys & (1u << ZONE_SVC_PARAM_KEY_MANDATORY)) && (code = check_mandatory(parser, type, field, rdata, whence)) < 0) return code; // RFC9460 section 7.2: // For "no-default-alpn", the presentation and wire-format values MUST be // empty. When "no-default-alpn" is specified in an RR, "alpn" must also // be specified in order for the RR to be "self-consistent" // (Section 2.4.3). if ((keys & 0x04) && !(keys & 0x02)) SEMANTIC_ERROR(parser, "%s with no-default-alpn but without alpn in %s", NAME(field), NAME(type)); return 0; } #endif // SVCB_H nsd-4.12.0/simdzone/src/generic/scanner.h0000644000175000017500000002746715002373055017653 0ustar mozziemozzie/* * scanner.h -- fast lexical analyzer for (DNS) zone files * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef SCANNER_H #define SCANNER_H #include #include #include // Copied from simdjson under the terms of The 3-Clause BSD License. // Copyright (c) 2018-2023 The simdjson authors static really_inline uint64_t find_escaped( uint64_t backslash, uint64_t *is_escaped) { backslash &= ~ *is_escaped; uint64_t follows_escape = backslash << 1 | *is_escaped; // Get sequences starting on even bits by clearing out the odd series using + const uint64_t even_bits = 0x5555555555555555ULL; uint64_t odd_sequence_starts = backslash & ~even_bits & ~follows_escape; uint64_t sequences_starting_on_even_bits; *is_escaped = add_overflow(odd_sequence_starts, backslash, &sequences_starting_on_even_bits); uint64_t invert_mask = sequences_starting_on_even_bits << 1; // The mask we want to return is the *escaped* bits, not escapes. // Mask every other backslashed character as an escaped character // Flip the mask for sequences that start on even bits, to correct them return (even_bits ^ invert_mask) & follows_escape; } // special characters in zone files cannot be identified without branching // (unlike json) due to comments (*). no algorithm was found (so far) that // can correctly identify quoted and comment regions where a quoted region // includes a semicolon (or newline for that matter) and/or a comment region // includes one (or more) quote characters. also, for comments, only newlines // directly following a non-escaped, non-quoted semicolon must be included static really_inline void find_delimiters( uint64_t quotes, uint64_t semicolons, uint64_t newlines, uint64_t in_quoted, uint64_t in_comment, uint64_t *quoted_, uint64_t *comment) { uint64_t delimiters, starts = quotes | semicolons; uint64_t end; assert(!(quotes & semicolons)); // carry over state from previous block end = (newlines & in_comment) | (quotes & in_quoted); end &= -end; delimiters = end; starts &= ~((in_comment | in_quoted) ^ (-end - end)); while (starts) { const uint64_t start = -starts & starts; assert(start); const uint64_t quote = quotes & start; const uint64_t semicolon = semicolons & start; // FIXME: technically, this introduces a data dependency end = (newlines & -semicolon) | (quotes & (-quote - quote)); end &= -end; delimiters |= end | start; starts &= -end - end; } *quoted_ = delimiters & quotes; *comment = delimiters & ~quotes; } static inline uint64_t follows(const uint64_t match, uint64_t *overflow) { const uint64_t result = match << 1 | (*overflow); *overflow = match >> 63; return result; } static const simd_table_t blank = SIMD_TABLE( 0x20, // 0x00 : " " : 0x20 -- space 0x00, // 0x01 0x00, // 0x02 0x00, // 0x03 0x00, // 0x04 0x00, // 0x05 0x00, // 0x06 0x00, // 0x07 0x00, // 0x08 0x09, // 0x09 : "\t" : 0x09 -- tab 0x00, // 0x0a 0x00, // 0x0b 0x00, // 0x0c 0x0d, // 0x0d : "\r" : 0x0d -- carriage return 0x00, // 0x0e 0x00 // 0x0f ); static const simd_table_t special = SIMD_TABLE( 0x00, // 0x00 : "\0" : 0x00 -- end-of-file 0x00, // 0x01 0x00, // 0x02 0x00, // 0x03 0x00, // 0x04 0x00, // 0x05 0x00, // 0x06 0x00, // 0x07 0x28, // 0x08 : "(" : 0x28 -- start grouped 0x29, // 0x09 : ")" : 0x29 -- end grouped 0x0a, // 0x0a : "\n" : 0x0a -- end-of-line 0x00, // 0x0b 0x00, // 0x0c 0x00, // 0x0d 0x00, // 0x0e 0x00 // 0x0f ); typedef struct block block_t; struct block { simd_8x64_t input; uint64_t newline; uint64_t backslash; uint64_t escaped; uint64_t comment; uint64_t quoted; uint64_t semicolon; uint64_t in_quoted; uint64_t in_comment; uint64_t contiguous; uint64_t follows_contiguous; uint64_t blank; uint64_t special; }; static really_inline void scan(parser_t *parser, block_t *block) { // escaped newlines are classified as contiguous. however, escape sequences // have no meaning in comments and newlines, escaped or not, have no // special meaning in quoted block->newline = simd_find_8x64(&block->input, '\n'); block->backslash = simd_find_8x64(&block->input, '\\'); block->escaped = find_escaped( block->backslash, &parser->file->state.is_escaped); block->comment = 0; block->quoted = simd_find_8x64(&block->input, '"') & ~block->escaped; block->semicolon = simd_find_8x64(&block->input, ';') & ~block->escaped; block->in_quoted = parser->file->state.in_quoted; block->in_comment = parser->file->state.in_comment; if (block->in_comment || block->semicolon) { find_delimiters( block->quoted, block->semicolon, block->newline, block->in_quoted, block->in_comment, &block->quoted, &block->comment); block->in_quoted ^= prefix_xor(block->quoted); parser->file->state.in_quoted = (uint64_t)((int64_t)block->in_quoted >> 63); block->in_comment ^= prefix_xor(block->comment); parser->file->state.in_comment = (uint64_t)((int64_t)block->in_comment >> 63); } else { block->in_quoted ^= prefix_xor(block->quoted); parser->file->state.in_quoted = (uint64_t)((int64_t)block->in_quoted >> 63); } block->blank = simd_find_any_8x64(&block->input, blank) & ~(block->escaped | block->in_quoted | block->in_comment); block->special = simd_find_any_8x64(&block->input, special) & ~(block->escaped | block->in_quoted | block->in_comment); block->contiguous = ~(block->blank | block->special | block->quoted) & ~(block->in_quoted | block->in_comment); block->follows_contiguous = follows(block->contiguous, &parser->file->state.follows_contiguous); } static really_inline void write_indexes(parser_t *parser, const block_t *block, uint64_t clear) { uint64_t fields = (block->contiguous & ~block->follows_contiguous) | (block->quoted & block->in_quoted) | (block->special); // delimiters are only important for contigouos and quoted character strings // (all other tokens automatically have a length 1). write out both in // separate vectors and base logic solely on field vector, order is // automatically correct uint64_t delimiters = (~block->contiguous & block->follows_contiguous) | (block->quoted & ~block->in_quoted); fields &= ~clear; delimiters &= ~clear; const char *base = parser->file->buffer.data + parser->file->buffer.index; uint64_t field_count = count_ones(fields); uint64_t delimiter_count = count_ones(delimiters); // bulk of the data are contiguous and quoted character strings. field and // delimiter counts are therefore (mostly) equal. select the greater number // and write out indexes in a single loop leveraging superscalar properties // of modern CPUs uint64_t count = field_count; if (delimiter_count > field_count) count = delimiter_count; // take slow path if (escaped) newlines appear in contiguous or quoted // character strings. edge case, but must be supported and handled in the // scanner for ease of use and to accommodate for parallel processing in the // parser. escaped newlines may have been present in the last block uint64_t newlines = block->newline & (block->contiguous | block->in_quoted); // non-delimiting tokens may contain (escaped) newlines. tracking newlines // within tokens by taping them makes the lex operation more complex, resulting // in a significantly larger binary and slower operation, and may introduce an // infinite loop if the tape may not be sufficiently large enough. tokens // containing newlines is very much an edge case, therefore the scanner // implements an unlikely slow path that tracks the number of escaped newlines // during tokenization and registers them with each consecutive newline token. // this mode of operation nicely isolates location tracking in the scanner and // accommodates parallel processing should that ever be desired if (unlikely(*parser->file->newlines.tail || newlines)) { for (uint64_t i=0; i < count; i++) { const uint64_t field = fields & -fields; const uint64_t delimiter = delimiters & -delimiters; if (field & block->newline) { *parser->file->newlines.tail += count_ones(newlines & (field - 1)); if (*parser->file->newlines.tail) { parser->file->fields.tail[i] = line_feed; parser->file->newlines.tail++; } else { parser->file->fields.tail[i] = base + trailing_zeroes(field); } newlines &= -field; } else { parser->file->fields.tail[i] = base + trailing_zeroes(field); } parser->file->delimiters.tail[i] = base + trailing_zeroes(delimiter); fields &= ~field; delimiters &= ~delimiter; } *parser->file->newlines.tail += count_ones(newlines); parser->file->fields.tail += field_count; parser->file->delimiters.tail += delimiter_count; } else { for (uint64_t i=0; i < 6; i++) { parser->file->fields.tail[i] = base + trailing_zeroes(fields); parser->file->delimiters.tail[i] = base + trailing_zeroes(delimiters); fields = clear_lowest_bit(fields); delimiters = clear_lowest_bit(delimiters); } if (unlikely(count > 6)) { for (uint64_t i=6; i < 12; i++) { parser->file->fields.tail[i] = base + trailing_zeroes(fields); parser->file->delimiters.tail[i] = base + trailing_zeroes(delimiters); fields = clear_lowest_bit(fields); delimiters = clear_lowest_bit(delimiters); } if (unlikely(count > 12)) { for (uint64_t i=12; i < count; i++) { parser->file->fields.tail[i] = base + trailing_zeroes(fields); parser->file->delimiters.tail[i] = base + trailing_zeroes(delimiters); fields = clear_lowest_bit(fields); delimiters = clear_lowest_bit(delimiters); } } } parser->file->fields.tail += field_count; parser->file->delimiters.tail += delimiter_count; } } nonnull_all warn_unused_result static really_inline int32_t reindex(parser_t *parser) { block_t block = { 0 }; assert(parser->file->buffer.index <= parser->file->buffer.length); size_t left = parser->file->buffer.length - parser->file->buffer.index; const char *data = parser->file->buffer.data + parser->file->buffer.index; const char **tape = parser->file->fields.tail; const char **tape_limit = parser->file->fields.tape + ZONE_TAPE_SIZE; if (left >= ZONE_BLOCK_SIZE) { const char *data_limit = parser->file->buffer.data + (parser->file->buffer.length - ZONE_BLOCK_SIZE); while (data <= data_limit && ((uintptr_t)tape_limit - (uintptr_t)tape) >= ZONE_BLOCK_SIZE) { simd_loadu_8x64(&block.input, (const uint8_t *)data); scan(parser, &block); write_indexes(parser, &block, 0); parser->file->buffer.index += ZONE_BLOCK_SIZE; data += ZONE_BLOCK_SIZE; tape = parser->file->fields.tail; } assert(parser->file->buffer.index <= parser->file->buffer.length); left = parser->file->buffer.length - parser->file->buffer.index; } // only scan partial blocks after reading all data if (parser->file->end_of_file) { assert(left < ZONE_BLOCK_SIZE); if (!left) { parser->file->end_of_file = NO_MORE_DATA; } else if (((uintptr_t)tape_limit - (uintptr_t)tape) >= left) { // input is required to be padded, but may contain garbage uint8_t buffer[ZONE_BLOCK_SIZE] = { 0 }; memcpy(buffer, data, left); const uint64_t clear = ~((1llu << left) - 1); simd_loadu_8x64(&block.input, buffer); scan(parser, &block); block.contiguous &= ~clear; write_indexes(parser, &block, clear); parser->file->end_of_file = NO_MORE_DATA; parser->file->buffer.index += left; } } return (uint64_t)((int64_t)(block.contiguous | block.in_quoted) >> 63) != 0; } #endif // SCANNER_H nsd-4.12.0/simdzone/src/generic/parser.h0000644000175000017500000007616715002373055017517 0ustar mozziemozzie/* * parser.h -- base parser definitions * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef PARSER_H #define PARSER_H #include #include #include #include #include #if _MSC_VER # define strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) #else # include #endif typedef zone_parser_t parser_t; // convenience typedef zone_file_t file_t; typedef zone_name_buffer_t name_buffer_t; typedef zone_rdata_buffer_t rdata_buffer_t; typedef struct token token_t; struct token { int32_t code; const char *data; size_t length; }; // view of current RDATA buffer typedef struct rdata rdata_t; struct rdata { uint8_t *octets; uint8_t *limit; }; typedef struct string string_t; struct string { const char *data; size_t length; }; typedef struct mnemonic mnemonic_t; struct mnemonic { struct { char data[16]; /* MUST be 16 because of usage with SIMD cmpeq */ size_t length; } key; uint32_t value; }; #define NAME(info) ((info)->name.key.data) typedef struct svc_param_info svc_param_info_t; struct svc_param_info; typedef struct rdata_info rdata_info_t; struct rdata_info; typedef struct type_info type_info_t; struct type_info; typedef int32_t (*parse_svc_param_t)( parser_t *, const type_info_t *, const rdata_info_t *, uint16_t, const svc_param_info_t *, rdata_t *, const token_t *); struct svc_param_info { struct { struct { char data[24]; size_t length; } key; uint32_t value; } name; uint32_t has_value; parse_svc_param_t parse, parse_lax; }; struct rdata_info { struct { string_t key; } name; // convenience }; typedef struct class_info class_info_t; struct class_info { mnemonic_t name; }; typedef int32_t (*check_rr_t)( parser_t *, const type_info_t *, const rdata_t *); typedef int32_t (*parse_rdata_t)( parser_t *, const type_info_t *, rdata_t *, token_t *); struct type_info { mnemonic_t name; uint16_t defined_in; bool is_obsolete; bool is_experimental; struct { size_t length; const rdata_info_t *fields; } rdata; check_rr_t check; parse_rdata_t parse; }; #define END_OF_FILE (0) #define CONTIGUOUS (1<<0) #define QUOTED (1<<1) #define LINE_FEED (1<<2) #define LEFT_PAREN (1<<3) #define RIGHT_PAREN (1<<4) #define BLANK (1<<6) #define COMMENT (1<<7) static const uint8_t classify[256] = { // 0x00 = "\0" 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x00 - 0x07 // 0x09 = "\t", 0x0a = "\n", 0x0d = "\r" 0x01, 0x40, 0x04, 0x01, 0x01, 0x40, 0x01, 0x01, // 0x08 - 0x0f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x10 - 0x17 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x18 - 0x1f // 0x20 = " ", 0x22 = "\"" 0x40, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x20 - 0x27 // 0x28 = "(", 0x29 = ")" 0x08, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x28 - 0x2f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x30 - 0x37 // 0x3b = ";" 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, // 0x38 - 0x3f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x40 - 0x47 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x48 - 0x4f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x50 - 0x57 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x58 - 0x5f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x60 - 0x67 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x68 - 0x6f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x70 - 0x77 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x78 - 0x7f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x80 - 0x87 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x88 - 0x8f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x90 - 0x97 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x98 - 0x9f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa0 - 0xa7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa8 - 0xaf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb0 - 0xb7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb8 - 0xbf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc0 - 0xc7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc8 - 0xcf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd0 - 0xd7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd8 - 0xdf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe0 - 0xe7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe8 - 0xef 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xf8 - 0xf7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 // 0xf8 - 0xff }; // special constant to mark line feeds with additional line count. i.e. CRLF // within text. line feeds have no special meaning other than terminating the // record and require no further processing static const char line_feed[ZONE_BLOCK_SIZE] = { '\n', '\0' }; // special constant used as data on errors static const char end_of_file[ZONE_BLOCK_SIZE] = { '\0' }; #define READ_ALL_DATA (1) #define NO_MORE_DATA (2) #define MISSING_QUOTE (3) extern int32_t zone_open_file( parser_t *, const char *path, size_t length, zone_file_t **); extern void zone_close_file( parser_t *, zone_file_t *); extern void zone_vlog(parser_t *, uint32_t, const char *, va_list); nonnull((1)) static really_inline void defer_error(token_t *token, int32_t code) { token->code = code; token->data = end_of_file; token->length = 0; } nonnull((1,3)) warn_unused_result static never_inline int32_t raise_error( parser_t *parser, int32_t code, const char *format, ...) { va_list arguments; uint32_t category = ZONE_ERROR; if (code == ZONE_SEMANTIC_ERROR && parser->options.secondary) category = ZONE_WARNING; va_start(arguments, format); zone_vlog(parser, category, format, arguments); va_end(arguments); if (category == ZONE_WARNING) return 0; return code; } #define RAISE_ERROR(parser, code, ...) \ do { \ return raise_error((parser), (code), __VA_ARGS__); \ } while (0) #define SYNTAX_ERROR(parser, ...) \ RAISE_ERROR((parser), ZONE_SYNTAX_ERROR, __VA_ARGS__) #define OUT_OF_MEMORY(parser, ...) \ RAISE_ERROR((parser), ZONE_OUT_OF_MEMORY, __VA_ARGS__) #define READ_ERROR(parser, ...) \ RAISE_ERROR((parser), ZONE_READ_ERROR, __VA_ARGS__) #define NOT_IMPLEMENTED(parser, ...) \ RAISE_ERROR((parser), ZONE_NOT_IMPLEMENTED, __VA_ARGS__) #define NOT_PERMITTED(parser, ...) \ RAISE_ERROR((parser), ZONE_NOT_PERMITTED, __VA_ARGS__) #define NOT_A_FILE(parser, ...) \ RAISE_ERROR((parser), ZONE_NOT_A_FILE, __VA_ARGS__) // semantic errors in zone files are special as a secondary may choose // to report, but otherwise ignore them. e.g. a TTL with the MSB set. cases // where the data can be presented in wire format but is otherwise considered // invalid. e.g. a TTL is limited to 32-bits, values that require more bits // are invalid without exception, but secondaries may choose to accept values // with the MSB set in order to update the zone #define SEMANTIC_ERROR(parser, ...) \ do { \ if (raise_error((parser), ZONE_SEMANTIC_ERROR, __VA_ARGS__)) \ return ZONE_SEMANTIC_ERROR; \ } while (0) nonnull_all warn_unused_result static really_inline int32_t reindex(parser_t *parser); // limit maximum size of buffer to avoid malicious inputs claiming all memory. // the maximum size of the buffer is the worst-case size of rdata, or 65535 // bytes, in presentation format. comma-separated value lists as introduced // by RFC 9460 allow for double escaping. a reasonable limit is therefore // 65535 (rdata) * 4 (\DDD) * 4 (\DDD) + 64 (sufficiently large enough to // cover longest key and ancillary characters) bytes. #define MAXIMUM_WINDOW_SIZE (65535u * 4u * 4u + 64u) nonnull_all warn_unused_result static int32_t refill(parser_t *parser) { // refill if possible (i.e. not if string or if file is empty) if (parser->file->end_of_file) return 0; assert(parser->file->handle); // move unread data to start of buffer char *data = parser->file->buffer.data + parser->file->buffer.index; // account for non-terminated character-strings if (*parser->file->fields.head[0] != '\0') data = (char *)parser->file->fields.head[0]; *parser->file->fields.head = parser->file->buffer.data; // account for unread data left in buffer size_t length = (size_t) ((parser->file->buffer.data + parser->file->buffer.length) - data); // account for non-terminated character-string left in buffer assert((parser->file->buffer.data + parser->file->buffer.index) >= data); size_t index = (size_t) ((parser->file->buffer.data + parser->file->buffer.index) - data); memmove(parser->file->buffer.data, data, length); parser->file->buffer.length = length; parser->file->buffer.index = index; parser->file->buffer.data[length] = '\0'; // allocate extra space if required if (parser->file->buffer.length == parser->file->buffer.size) { size_t size = parser->file->buffer.size; if (parser->file->buffer.size >= MAXIMUM_WINDOW_SIZE) SYNTAX_ERROR(parser, "Impossibly large input, exceeds %zu bytes", size); size += ZONE_WINDOW_SIZE; if (!(data = realloc(parser->file->buffer.data, size + 1 + ZONE_BLOCK_SIZE))) OUT_OF_MEMORY(parser, "Not enough memory to allocate buffer of %zu", size); parser->file->buffer.size = size; parser->file->buffer.data = data; // update reference to partial token parser->file->fields.head[0] = data; } size_t count = fread( parser->file->buffer.data + parser->file->buffer.length, sizeof(parser->file->buffer.data[0]), parser->file->buffer.size - parser->file->buffer.length, parser->file->handle); if (!count && ferror(parser->file->handle)) READ_ERROR(parser, "Cannot refill buffer"); // always null-terminate for terminating token parser->file->buffer.length += (size_t)count; parser->file->buffer.data[parser->file->buffer.length] = '\0'; parser->file->end_of_file = feof(parser->file->handle) != 0; /* After the file, there is padding, that is used by vector instructions, * initialise those bytes. */ memset(parser->file->buffer.data+parser->file->buffer.length+1, 0, ZONE_BLOCK_SIZE); return 0; } // do not invoke directly nonnull_all warn_unused_result static really_inline int32_t advance(parser_t *parser) { int32_t code; // save embedded line count (quoted or escaped newlines) parser->file->newlines.tape[0] = parser->file->newlines.tail[0]; parser->file->newlines.head = parser->file->newlines.tape; parser->file->newlines.tail = parser->file->newlines.tape; // restore non-terminated token (partial quoted or contiguous) parser->file->fields.tape[0] = parser->file->fields.tail[1]; parser->file->fields.head = parser->file->fields.tape; parser->file->fields.tail = parser->file->fields.tape + (*parser->file->fields.tape[0] != '\0'); // reset delimiters parser->file->delimiters.head = parser->file->delimiters.tape; parser->file->delimiters.tail = parser->file->delimiters.tape; // delayed syntax error if (parser->file->end_of_file == MISSING_QUOTE) SYNTAX_ERROR(parser, "Missing closing quote"); if ((code = refill(parser)) < 0) return code; if (reindex(parser)) { // save non-terminated token parser->file->fields.tail[0] = parser->file->fields.tail[-1]; parser->file->fields.tail--; // delay syntax error so correct line number is available if (parser->file->end_of_file == NO_MORE_DATA && *parser->file->fields.tail[1] == '"') parser->file->end_of_file = MISSING_QUOTE; } else { parser->file->fields.tail[1] = end_of_file; } // FIXME: if tail is still equal to tape, refill immediately?! // terminate (end of buffer is null-terminated) parser->file->fields.tail[0] = parser->file->buffer.data + parser->file->buffer.length; parser->file->delimiters.tail[0] = parser->file->buffer.data + parser->file->buffer.length; // start-of-line must be false if start of tape is not start of buffer if (*parser->file->fields.head != parser->file->buffer.data) parser->file->start_of_line = false; return 0; } nonnull_all warn_unused_result static really_inline bool is_contiguous(const token_t *token) { return token->code == CONTIGUOUS; } nonnull_all warn_unused_result static really_inline bool is_quoted(const token_t *token) { return token->code == QUOTED; } nonnull_all warn_unused_result static really_inline bool is_contiguous_or_quoted(const token_t *token) { return (token->code == CONTIGUOUS || token->code == QUOTED); } nonnull_all warn_unused_result static really_inline bool is_delimiter(const token_t *token) { return (token->code == LINE_FEED || token->code == END_OF_FILE); } nonnull_all warn_unused_result static really_inline bool is_line_feed(const token_t *token) { return token->code == LINE_FEED; } nonnull_all warn_unused_result static really_inline bool is_end_of_file(const token_t *token) { return token->code == 0; } #undef SYNTAX_ERROR #define SYNTAX_ERROR(parser, token, ...) \ do { \ zone_log((parser), ZONE_ERROR, __VA_ARGS__); \ defer_error((token), ZONE_SYNTAX_ERROR); \ return; \ } while (0) #define ERROR(parser, token, code) \ do { \ defer_error(token, code); \ return; \ } while (0) nonnull_all static never_inline void maybe_take(parser_t *parser, token_t *token) { for (;;) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (likely(token->code == CONTIGUOUS)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return; } else if (token->code == LINE_FEED) { if (unlikely(token->data == line_feed)) parser->file->span += *parser->file->newlines.head++; parser->file->span++; parser->file->fields.head++; if (unlikely(parser->file->grouped)) continue; parser->file->start_of_line = classify[ (uint8_t)*(token->data+1) ] != BLANK; token->length = 1; return; } else if (token->code == QUOTED) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return; } else if (token->code == END_OF_FILE) { int32_t code; if (parser->file->end_of_file == NO_MORE_DATA) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing closing brace"); token->data = end_of_file; token->length = 1; return; } else if (unlikely((code = advance(parser)) < 0)) { ERROR(parser, token, code); } } else if (token->code == LEFT_PAREN) { if (unlikely(parser->file->grouped)) SYNTAX_ERROR(parser, token, "Nested opening brace"); parser->file->grouped = true; parser->file->fields.head++; } else { assert(token->code == RIGHT_PAREN); if (unlikely(!parser->file->grouped)) SYNTAX_ERROR(parser, token, "Missing opening brace"); parser->file->grouped = false; parser->file->fields.head++; } } } nonnull_all static really_inline void take(parser_t *parser, token_t *token) { for (;;) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (likely(token->code == CONTIGUOUS)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return; } else if (token->code == LINE_FEED) { if (unlikely(token->data == line_feed)) parser->file->span += *parser->file->newlines.head++; parser->file->span++; parser->file->fields.head++; if (unlikely(parser->file->grouped)) continue; parser->file->start_of_line = classify[ (uint8_t)*(token->data+1) ] != BLANK; token->length = 1; return; } else if (token->code == QUOTED) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return; } else { maybe_take(parser, token); return; } } } #undef SYNTAX_ERROR #undef ERROR // token sequence is predictable. fields typically require a specific type, // except names, strings and SvcParams. even then, names are typically not // quoted and strings (or text) are typically quoted. implement specialized // tape accessors for performance and reduction in binary size. #define SYNTAX_ERROR(parser, token, ...) \ do { \ zone_log((parser), ZONE_ERROR, __VA_ARGS__); \ defer_error((token), ZONE_SYNTAX_ERROR); \ return ZONE_SYNTAX_ERROR; \ } while (0) #define ERROR(parser, token, code) \ do { \ defer_error((token), (code)); \ return (code); \ } while (0) nonnull_all warn_unused_result static never_inline int32_t dont_have_contiguous( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (token->code < 0) return token->code; assert(token->code != CONTIGUOUS); if (token->code == QUOTED) SYNTAX_ERROR(parser, token, "Invalid %s in %s", NAME(field), NAME(type)); assert(token->code == END_OF_FILE || token->code == LINE_FEED); SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); } nonnull_all warn_unused_result static really_inline int32_t have_contiguous( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (unlikely(token->code != CONTIGUOUS)) return dont_have_contiguous(parser, type, field, token); return 0; } nonnull_all warn_unused_result static never_inline int32_t maybe_take_contiguous( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { int32_t code; assert(token->code != CONTIGUOUS); for (;;) { if (likely(token->code == CONTIGUOUS)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else if (token->code == END_OF_FILE) { if (parser->file->end_of_file == NO_MORE_DATA) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); if ((code = advance(parser)) < 0) ERROR(parser, token, code); } else if (token->code == QUOTED) { SYNTAX_ERROR(parser, token, "Invalid %s in %s", NAME(field), NAME(type)); } else if (token->code == LEFT_PAREN) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Nested opening brace"); parser->file->grouped = true; parser->file->fields.head++; } else if (token->code == RIGHT_PAREN) { if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing opening brace"); parser->file->grouped = false; parser->file->fields.head++; } else if (token->code == LINE_FEED) { if (token->data == line_feed) parser->file->span += *parser->file->newlines.head++; parser->file->span++; if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); parser->file->fields.head++; } token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; } } nonnull_all warn_unused_result static really_inline int32_t take_contiguous( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (unlikely(token->code != CONTIGUOUS)) return maybe_take_contiguous(parser, type, field, token); assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } nonnull_all warn_unused_result static never_inline int32_t dont_have_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (token->code < 0) return token->code; assert(token->code != QUOTED); if (token->code == CONTIGUOUS) SYNTAX_ERROR(parser, token, "Invalid %s in %s", NAME(field), NAME(type)); assert(token->code == END_OF_FILE || token->code == LINE_FEED); SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); } nonnull_all warn_unused_result static really_inline int32_t have_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (unlikely(token->code != QUOTED)) return dont_have_quoted(parser, type, field, token); return 0; } nonnull_all warn_unused_result static never_inline int32_t maybe_take_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { int32_t code; assert(token->code != QUOTED); for (;;) { if (likely(token->code == QUOTED)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else if (token->code == END_OF_FILE) { if (parser->file->end_of_file == NO_MORE_DATA) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); if ((code = advance(parser)) < 0) ERROR(parser, token, code); } else if (token->code == CONTIGUOUS) { SYNTAX_ERROR(parser, token, "Invalid %s in %s", NAME(field), NAME(type)); } else if (token->code == LEFT_PAREN) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Nested opening brace"); parser->file->grouped = true; parser->file->fields.head++; } else if (token->code == RIGHT_PAREN) { if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing opening brace"); parser->file->grouped = false; parser->file->fields.head++; } else if (token->code == LINE_FEED) { if (token->data == line_feed) parser->file->span += *parser->file->newlines.head++; parser->file->span++; if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); parser->file->fields.head++; } else { assert(token->code < 0); return token->code; } token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; } } nonnull_all warn_unused_result static really_inline int32_t take_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (unlikely((token->code != QUOTED))) return maybe_take_quoted(parser, type, field, token); assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } nonnull_all warn_unused_result static never_inline int32_t dont_have_contiguous_or_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (token->code == QUOTED || token->code < 0) return token->code; assert(token->code == END_OF_FILE || token->code == LINE_FEED); SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); } nonnull_all warn_unused_result static really_inline int32_t have_contiguous_or_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { if (unlikely(token->code != CONTIGUOUS)) return dont_have_contiguous_or_quoted(parser, type, field, token); return 0; } nonnull_all warn_unused_result static never_inline int32_t maybe_take_contiguous_or_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { int32_t code; for (;;) { if (likely(token->code == CONTIGUOUS)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else if (token->code == QUOTED) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else if (token->code == END_OF_FILE) { if (parser->file->end_of_file == NO_MORE_DATA) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); if ((code = advance(parser)) < 0) ERROR(parser, token, code); } else if (token->code == LEFT_PAREN) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Nested opening brace"); parser->file->grouped = true; parser->file->fields.head++; } else if (token->code == RIGHT_PAREN) { if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing opening brace"); parser->file->grouped = false; parser->file->fields.head++; } else if (token->code == LINE_FEED) { if (token->data == line_feed) parser->file->span += *parser->file->newlines.head++; parser->file->span++; if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing %s in %s", NAME(field), NAME(type)); parser->file->fields.head++; } token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; } } nonnull_all warn_unused_result static really_inline int32_t take_contiguous_or_quoted( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (likely(token->code == CONTIGUOUS)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->length = (uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else { return maybe_take_contiguous_or_quoted(parser, type, field, token); } } nonnull_all warn_unused_result static really_inline int32_t take_quoted_or_contiguous( parser_t *parser, const type_info_t *type, const rdata_info_t *field, token_t *token) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (likely(token->code == QUOTED)) { assert(*parser->file->delimiters.head > *parser->file->fields.head); token->data++; token->length = ((uintptr_t)*parser->file->delimiters.head - (uintptr_t)*parser->file->fields.head) - 1; parser->file->fields.head++; parser->file->delimiters.head++; return 0; } else { return maybe_take_contiguous_or_quoted(parser, type, field, token); } } diagnostic_push() clang_diagnostic_ignored(unused-function) gcc_diagnostic_ignored(unused-function) nonnull_all warn_unused_result static never_inline int32_t dont_have_delimiter( parser_t *parser, const type_info_t *type, token_t *token) { if (token->code == END_OF_FILE || token->code < 0) return token->code; assert(token->code == CONTIGUOUS || token->code == QUOTED); SYNTAX_ERROR(parser, token, "Trailing data in %s", NAME(type)); } nonnull_all warn_unused_result static never_inline int32_t have_delimiter( parser_t *parser, const type_info_t *type, token_t *token) { if (unlikely(token->code != LINE_FEED)) return dont_have_delimiter(parser, type, token); return 0; } diagnostic_pop() nonnull_all warn_unused_result static never_inline int32_t maybe_take_delimiter( parser_t *parser, const type_info_t *type, token_t *token) { int32_t code; for (;;) { if (likely(token->code == LINE_FEED)) { if (unlikely(token->data == line_feed)) parser->file->span += *parser->file->newlines.head++; if (unlikely(parser->file->grouped)) { parser->file->span++; parser->file->fields.head++; } else { token->length = 1; parser->file->span++; parser->file->start_of_line = classify[ (uint8_t)*(token->data+1) ] != BLANK; parser->file->fields.head++; return 0; } } else if (token->code == END_OF_FILE) { if (parser->file->end_of_file == NO_MORE_DATA) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing closing brace"); token->data = end_of_file; token->length = 1; return 0; } if ((code = advance(parser)) < 0) ERROR(parser, token, code); } else if (token->code == LEFT_PAREN) { if (parser->file->grouped) SYNTAX_ERROR(parser, token, "Nested opening brace"); parser->file->grouped = true; parser->file->fields.head++; } else if (token->code == RIGHT_PAREN) { if (!parser->file->grouped) SYNTAX_ERROR(parser, token, "Missing opening brace"); parser->file->grouped = false; parser->file->fields.head++; } else { assert(token->code == CONTIGUOUS || token->code == QUOTED); SYNTAX_ERROR(parser, token, "Trailing data in %s", NAME(type)); } token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; } } nonnull_all warn_unused_result static really_inline int32_t take_delimiter( parser_t *parser, const type_info_t *type, token_t *token) { token->data = *parser->file->fields.head; token->code = (int32_t)classify[ (uint8_t)**parser->file->fields.head ]; if (likely(token->code == LINE_FEED)) { if (unlikely(parser->file->grouped || token->data == line_feed)) return maybe_take_delimiter(parser, type, token); token->length = 1; parser->file->span++; parser->file->start_of_line = classify[ (uint8_t)*(*parser->file->fields.head+1) ] != BLANK; parser->file->fields.head++; return 0; } else { return maybe_take_delimiter(parser, type, token); } } #undef SYNTAX_ERROR #undef ERROR // define SYNTAX_ERROR for the rest of the code base #define SYNTAX_ERROR(parser, ...) \ RAISE_ERROR((parser), ZONE_SYNTAX_ERROR, __VA_ARGS__) #endif // PARSER_H nsd-4.12.0/simdzone/src/generic/nxt.h0000644000175000017500000000275315002373055017022 0ustar mozziemozzie/* * nxt.h - NXT (RFC2535) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NXT_H #define NXT_H nonnull_all static really_inline int32_t scan_type( const char *data, size_t length, uint16_t *code, const mnemonic_t **mnemonic); nonnull_all static really_inline int32_t parse_nxt( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, token_t *token) { uint16_t code; const mnemonic_t *mnemonic; if (is_contiguous(token)) { if (scan_type(token->data, token->length, &code, &mnemonic) != 1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); uint8_t bit = (uint8_t)(code % 8); uint8_t block = (uint8_t)(code / 8), highest_block = block; memset(rdata->octets, 0, block + 1); rdata->octets[block] = (uint8_t)(1 << (7 - bit)); take(parser, token); while (is_contiguous(token)) { if (scan_type(token->data, token->length, &code, &mnemonic) != 1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); bit = (uint8_t)(code % 8); block = (uint8_t)(code / 8); if (block > highest_block) { memset(&rdata->octets[highest_block+1], 0, block - highest_block); highest_block = block; } rdata->octets[block] |= 1 << (7 - bit); take(parser, token); } rdata->octets += highest_block + 1; } return have_delimiter(parser, type, token); } #endif // NXT_H nsd-4.12.0/simdzone/src/generic/number.h0000644000175000017500000000677715002373055017513 0ustar mozziemozzie/* * number.h -- integer parsing routines * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NUMBER_H #define NUMBER_H nonnull((1,3)) static really_inline int32_t scan_int8( const char *data, size_t length, uint8_t *number) { uint32_t sum = (uint8_t)data[0] - '0'; if (sum > 9 || !length || length > 3) return 0; for (size_t count=1; count < length; count++) { const uint8_t digit = (uint8_t)data[count] - '0'; sum = sum * 10 + digit; if (digit > 9) return 0; } *number = (uint8_t)sum; return sum <= 255u; } nonnull((1,3)) static really_inline int32_t scan_int16( const char *data, size_t length, uint16_t *number) { uint32_t sum = (uint8_t)data[0] - '0'; if (sum > 9 || !length || length > 5) return 0; for (size_t count=1; count < length; count++) { const uint8_t digit = (uint8_t)data[count] - '0'; sum = sum * 10 + digit; if (digit > 9) return 0; } *number = (uint16_t)sum; return sum <= 65535u; } nonnull((1,3)) static really_inline int32_t scan_int32( const char *data, size_t length, uint32_t *number) { uint64_t sum = (uint8_t)data[0] - '0'; if (sum > 9 || !length || length > 10) return 0; for (size_t count=1; count < length; count++) { const uint8_t digit = (uint8_t)data[count] - '0'; sum = sum * 10 + digit; if (digit > 9) return 0; } *number = (uint32_t)sum; return sum <= 4294967295u; } nonnull((1,3)) static really_inline int32_t scan_int64( const char *data, size_t length, uint64_t *number) { uint64_t sum = (uint8_t)data[0] - '0'; if (sum > 9 || !length || length > 20) return 0; for (size_t count=1; count < length; count++) { const uint8_t digit = (uint8_t)data[count] - '0'; sum = sum * 10 + digit; if (digit > 9) return 0; } *number = sum; return 1; /* TODO: detect overflow */ } nonnull_all static really_inline int32_t parse_int8( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint8_t number; if (!scan_int8(token->data, token->length, &number)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets++ = number; return 0; } nonnull_all static really_inline int32_t parse_int16( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint16_t number; if (!scan_int16(token->data, token->length, &number)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); number = htobe16(number); memcpy(rdata->octets, &number, 2); rdata->octets += 2; return 0; } nonnull_all static really_inline int32_t parse_int32( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint32_t number; if (!scan_int32(token->data, token->length, &number)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); number = htobe32(number); memcpy(rdata->octets, &number, 4); rdata->octets += 4; return 0; } nonnull_all static really_inline int32_t parse_int64( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint64_t number; if (!scan_int64(token->data, token->length, &number)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); number = htobe64(number); memcpy(rdata->octets, &number, 8); rdata->octets += 8; return 0; } #endif // NUMBER_H nsd-4.12.0/simdzone/src/generic/nsec.h0000644000175000017500000000352015002373055017132 0ustar mozziemozzie/* * nsec.h -- NSEC (RFC4043) parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NSEC_H #define NSEC_H nonnull_all static really_inline int32_t scan_type( const char *, size_t, uint16_t *, const mnemonic_t **); typedef uint8_t nsec_t[32 /* 256 / 8 */ + 2]; nonnull_all static really_inline int32_t parse_nsec( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, token_t *token) { if (likely(is_contiguous(token))) { nsec_t *bitmap = (void *)rdata->octets; assert(rdata->octets <= rdata->limit); assert((size_t)(rdata->limit - rdata->octets) >= 256 * sizeof(nsec_t)); uint32_t highest_window = 0; uint32_t windows[256] = { 0 }; do { uint16_t code; const mnemonic_t *mnemonic; if (scan_type(token->data, token->length, &code, &mnemonic) != 1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); const uint8_t bit = (uint8_t)(code % 256); const uint8_t window = code / 256; const uint8_t block = bit / 8; if (!windows[window]) memset(bitmap[window], 0, sizeof(bitmap[window])); if (window > highest_window) highest_window = window; windows[window] |= 1 << block; bitmap[window][2 + block] |= (1 << (7 - bit % 8)); take(parser, token); } while (is_contiguous(token)); for (uint32_t window = 0; window <= highest_window; window++) { if (!windows[window]) continue; const uint8_t blocks = (uint8_t)(64 - leading_zeroes(windows[window])); memmove(rdata->octets, &bitmap[window], 2 + blocks); rdata->octets[0] = (uint8_t)window; rdata->octets[1] = blocks; rdata->octets += 2 + blocks; } } return have_delimiter(parser, type, token); } #endif // NSEC_H nsd-4.12.0/simdzone/src/generic/nsap.h0000644000175000017500000000343615002373055017151 0ustar mozziemozzie/* * nsap.h -- NSAP (RFC1706) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NSAP_H #define NSAP_H // https://datatracker.ietf.org/doc/html/rfc1706 (historic) nonnull_all static really_inline int32_t parse_nsap( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const uint8_t *data = (const uint8_t *)token->data; // RFC1706 section 7 // NSAP format is "0x" (i.e., a zero followed by an 'x' character) followed // by a variable length string of hex characters (0 to 9, a to f). The hex // string is case-insensitive. "."s (i.e., periods) may be inserted in the // hex string anywhere after "0x" for readability. The "."s have no // significance other than for readability and are not propagated in the // protocol (e.g., queries or zone transfers). if (unlikely(data[0] != '0' || !(data[1] == 'X' || data[1] == 'x'))) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); data += 2; while (rdata->octets < rdata->limit) { uint32_t d0 = base16_table_dec_32bit_d0[data[0]]; uint32_t d1 = base16_table_dec_32bit_d1[data[1]]; if ((d0 | d1) > 0xff) { while (*data == '.') data++; d0 = base16_table_dec_32bit_d0[data[0]]; if (d0 > 0xff) break; data += 1; while (*data == '.') data++; d1 = base16_table_dec_32bit_d1[data[0]]; if (d1 > 0xff) goto bad_sequence; data += 1; } else { data += 2; } *rdata->octets++ = (uint8_t)(d0 | d1); } if (rdata->octets <= rdata->limit && data == (uint8_t *)token->data + token->length) return 0; bad_sequence: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } #endif // NSAP_H nsd-4.12.0/simdzone/src/generic/name.h0000644000175000017500000000753415002373055017133 0ustar mozziemozzie/* * name.h -- domain name parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NAME_H #define NAME_H typedef struct name_block name_block_t; struct name_block { uint64_t backslashes; uint64_t dots; }; nonnull_all static really_inline void copy_name_block( name_block_t *block, const char *text, uint8_t *wire) { simd_8x32_t input; simd_loadu_8x32(&input, text); simd_storeu_8x32(wire, &input); block->backslashes = simd_find_8x32(&input, '\\'); block->dots = simd_find_8x32(&input, '.'); } nonnull_all static really_inline int32_t scan_name( const char *data, size_t tlength, uint8_t octets[255 + ZONE_BLOCK_SIZE], size_t *lengthp) { uint64_t label = 0; const char *text = data; uint8_t *wire = octets + 1; name_block_t block; octets[0] = 0; // real world domain names quickly exceed 16 octets (www.example.com is // encoded as 3www7example3com0, or 18 octets), but rarely exceed 32 // octets. encode in 32-byte blocks. copy_name_block(&block, text, wire); uint64_t count = 32, length = 0, base = 0, left = tlength; uint64_t carry = 0; if (tlength < 32) count = tlength; uint64_t mask = (1llu << count) - 1u; // check for escape sequences if (unlikely(block.backslashes & mask)) goto escaped; // check for root, i.e. "." if (unlikely(block.dots & 1llu)) return ((*lengthp = tlength) == 1 ? 0 : -1); length = count; block.dots &= mask; carry = (block.dots >> (length - 1)); // check for null labels, i.e. ".." if (unlikely(block.dots & (block.dots >> 1))) return -1; if (likely(block.dots)) { count = trailing_zeroes(block.dots); block.dots = clear_lowest_bit(block.dots); octets[label] = (uint8_t)count; label = count + 1; while (block.dots) { count = trailing_zeroes(block.dots); block.dots = clear_lowest_bit(block.dots); octets[label] = (uint8_t)(count - label); label = count + 1; } } octets[label] = (uint8_t)(length - label); if (tlength <= 32) return (void)(*lengthp = length + 1), carry == 0; text += length; wire += length; left -= length; do { copy_name_block(&block, text, wire); count = 32; if (left < 32) count = left; mask = (1llu << count) - 1u; base = length; // check for escape sequences if (unlikely(block.backslashes & mask)) { escaped: block.backslashes &= -block.backslashes; mask = block.backslashes - 1; block.dots &= mask; count = count_ones(mask); const uint32_t octet = unescape(text+count, wire+count); if (!octet) return -1; text += count + octet; wire += count + 1; length += count + 1; left -= count + octet; count += 1; // for correct carry } else { block.dots &= mask; text += count; wire += count; length += count; left -= count; } // check for null labels, i.e. ".." if (unlikely(block.dots & ((block.dots >> 1) | carry))) return -1; carry = block.dots >> (count - 1); if (likely(block.dots)) { count = trailing_zeroes(block.dots) + base; block.dots = clear_lowest_bit(block.dots); octets[label] = (uint8_t)(count - label); // check if label exceeds 63 octets if (unlikely(count - label > 63)) return -1; label = count + 1; while (block.dots) { count = trailing_zeroes(block.dots) + base; block.dots = clear_lowest_bit(block.dots); octets[label] = (uint8_t)(count - label); label = count + 1; } } else { // check if label exceeds 63 octets if (length - label > 63) return -1; } octets[label] = (uint8_t)(length - label); } while (left && length < 255); if (length >= 255) return -1; *lengthp = length + 1; return carry == 0; } #endif // NAME_H nsd-4.12.0/simdzone/src/generic/loc.h0000644000175000017500000001355015002373055016763 0ustar mozziemozzie/* * loc.h -- Location Information (RFC1876) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef LOC_H #define LOC_H nonnull_all static really_inline int32_t scan_degrees( const char *text, size_t length, uint32_t *degrees) { uint8_t digits[3]; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; digits[2] = (uint8_t)text[2] - '0'; switch (length) { case 1: *degrees = digits[0] * 3600000; if (digits[0] > 9) return -1; return 0; case 2: *degrees = digits[0] * 36000000 + digits[1] * 3600000; if (digits[0] > 9 || digits[1] > 9) return -1; return 0; case 3: *degrees = digits[0] * 360000000 + digits[1] * 36000000 + digits[2] * 3600000; if (*degrees > 648000000u) return -1; if (digits[0] > 9 || digits[1] > 9 || digits[2] > 9) return -1; return 0; default: return -1; } } nonnull_all static really_inline int64_t scan_minutes( const char *text, size_t length, uint32_t *minutes) { uint8_t digits[2]; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; switch (length) { case 1: *minutes = digits[0] * 60000; if (digits[0] > 9) return -1; return 0; case 2: *minutes = digits[0] * 600000 + digits[1] * 60000; if (*minutes > 3600000 || digits[0] > 9 || digits[1] > 9) return -1; return 0; default: return -1; } } nonnull_all static really_inline int64_t scan_seconds( const char *text, size_t length, uint32_t *seconds) { uint8_t digits[3]; size_t count; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; if (length == 1 || text[1] == '.') { count = 1; *seconds = digits[0] * 1000; if (digits[0] > 9) return -1; digits[0] = (uint8_t)text[2] - '0'; digits[1] = (uint8_t)text[3] - '0'; digits[2] = (uint8_t)text[4] - '0'; } else if (length == 2 || text[2] == '.') { count = 2; *seconds = digits[0] * 10000 + digits[1] * 1000; if (*seconds > 60000 || digits[0] > 5 || digits[1] > 9) return -1; digits[0] = (uint8_t)text[3] - '0'; digits[1] = (uint8_t)text[4] - '0'; digits[2] = (uint8_t)text[5] - '0'; } else { return -1; } switch (length - count) { case 0: return 0; case 1: return -1; case 2: *seconds += digits[0] * 100u; if (digits[0] > 9) return -1; return 0; case 3: *seconds += digits[0] * 100u + digits[1] * 10u; if (digits[0] > 9 || digits[1] > 9) return -1; return 0; case 4: *seconds += digits[0] * 100u + digits[1] * 10u + digits[2]; if (digits[0] > 9 || digits[1] > 9 || digits[0] > 9) return -1; return 0; default: return -1; } } nonnull((1,3)) static really_inline int32_t scan_altitude( const char *text, size_t length, uint32_t *altitude) { uint64_t negative = 0, limit = 11, maximum = 4284967295llu; if (text[0] == '-') (void)(negative = 1), (void)(limit = 8), maximum = 10000000llu; length -= (text[length - 1] == 'm'); uint64_t meters = 0, index = negative; for (;; index++) { const uint8_t digit = (uint8_t)text[index] - '0'; if (digit > 9) break; meters = meters * 10 + digit; } uint64_t centimeters = meters * 100u; // convert to centimeters if (text[index] == '.') { uint8_t digits[2]; limit += 1; digits[0] = (uint8_t)text[index+1] - '0'; digits[1] = (uint8_t)text[index+2] - '0'; switch (length - index) { case 1: index += 1; break; case 2: if (digits[0] > 9) return -1; centimeters += (uint64_t)digits[0] * 10u; index += 2; break; case 3: if (digits[0] > 9 || digits[1] > 9) return -1; centimeters += (uint64_t)digits[0] * 10u + (uint64_t)digits[1]; index += 3; break; default: return -1; } } if (index == negative || index > limit || index != length || centimeters > maximum) return -1; if (negative) *altitude = (uint32_t)(10000000llu - centimeters); else *altitude = (uint32_t)(10000000llu + centimeters); return 0; } // converts ascii size/precision X * 10**Y(cm) to 0xXY nonnull((1,3)) static really_inline int32_t scan_precision( const char *text, size_t length, uint8_t *scientific) { uint64_t meters = 0, centimeters; // RFC1876 conversion routines static uint64_t poweroften[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; length -= text[length - 1] == 'm'; size_t index = 0; for (;; index++) { const uint8_t digit = (uint8_t)text[index] - '0'; if (digit > 9) break; meters = meters * 10 + digit; } if (index == 0 || index > 8) // 0 .. 90000000.00 return -1; // syntax error centimeters = meters * 100; // convert to centimeters if (text[index] == '.') { uint8_t digits[2]; digits[0] = (uint8_t)text[index+1] - '0'; digits[1] = (uint8_t)text[index+2] - '0'; switch (length - index) { case 1: index += 1; break; case 2: if (digits[0] > 9) return -1; index += 2; centimeters += digits[0] * 10; break; case 3: if (digits[0] > 9 || digits[1] > 9) return -1; index += 3; centimeters += digits[0] * 10 + digits[1]; break; default: return -1; } } if (index != length) return -1; // syntax error uint8_t exponent = 0; while (exponent < 9 && centimeters >= poweroften[exponent+1]) exponent++; uint8_t mantissa = (uint8_t)(centimeters / poweroften[exponent]); if (mantissa > 9u) mantissa = 9u; *scientific = (uint8_t)(mantissa << 4) | exponent; return 0; } #endif // LOC_H nsd-4.12.0/simdzone/src/generic/ip6.h0000644000175000017500000001164515002373055016707 0ustar mozziemozzie/*- * SPDX-License-Identifier: ISC * * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef IP6_H #define IP6_H #ifndef NS_INT16SZ #define NS_INT16SZ 2 #endif #ifndef NS_IN6ADDRSZ #define NS_IN6ADDRSZ 16 #endif #ifndef NS_INADDRSZ #define NS_INADDRSZ 4 #endif /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * length if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning !0. * author: * Paul Vixie, 1996. */ static int inet_pton4(const char *src, uint8_t *dst) { static const char digits[] = "0123456789"; int saw_digit, octets, ch; uint8_t tmp[NS_INADDRSZ], *tp; const char *start = src; saw_digit = 0; octets = 0; *(tp = tmp) = 0; for (; (ch = *src); src++) { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { uint32_t new = *tp * 10 + (uint32_t)(pch - digits); if (new > 255) return (0); *tp = (uint8_t)new; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else break; } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (int)(src - start); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * length if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning !0. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ static int inet_pton6(const char *src, uint8_t *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; uint32_t val; int len; const char *start = src; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; for (; (ch = *src); src++) { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src+1; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && (len = inet_pton4(curtok, tp)) > 0) { src = curtok + len; tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } break; } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = (int)(tp - colonp); int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (int)(src - start); } nonnull_all static really_inline int32_t scan_ip6(const char *text, uint8_t *wire) { return inet_pton6(text, wire); } nonnull_all static really_inline int32_t parse_ip6( parser_t *parser, const type_info_t *type, const rdata_info_t *item, rdata_t *rdata, const token_t *token) { if ((size_t)inet_pton6(token->data, rdata->octets) != token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); rdata->octets += 16; return 0; } #endif // IP6_H nsd-4.12.0/simdzone/src/generic/ip4.h0000644000175000017500000000262115002373055016677 0ustar mozziemozzie/* * ip4.h -- fallback parser for IPv4 addresses * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef IP4_H #define IP4_H nonnull_all static really_inline int32_t scan_ip4(const char *text, uint8_t *wire) { const char *start = text; uint32_t round = 0; for (;;) { uint8_t digits[3], count; uint32_t octet; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; digits[2] = (uint8_t)text[2] - '0'; if (digits[0] > 9) return 0; else if (digits[1] > 9) (void)(count = 1), octet = digits[0]; else if (digits[2] > 9) (void)(count = 2), octet = digits[0] * 10 + digits[1]; else (void)(count = 3), octet = digits[0] * 100 + digits[1] * 10 + digits[2]; if (octet > 255 || (count > 1 && !digits[0])) return 0; text += count; wire[round++] = (uint8_t)octet; if (text[0] != '.' || round == 4) break; text += 1; } if (round != 4) return 0; return (int32_t)(text - start); } nonnull_all static really_inline int32_t parse_ip4( parser_t *parser, const type_info_t *type, const rdata_info_t *item, rdata_t *rdata, const token_t *token) { if ((size_t)scan_ip4(token->data, rdata->octets) != token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); rdata->octets += 4; return 0; } #endif // IP4_H nsd-4.12.0/simdzone/src/generic/ilnp64.h0000644000175000017500000000257115002373055017323 0ustar mozziemozzie/* * ilnp64.h -- 64-bit Locator (RFC6742 section 2.3) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ILNP64_H #define ILNP64_H // FIXME: very likely eligable for vectorization (or optimization even), but // gains are small as the type is not frequently used nonnull_all static really_inline int32_t parse_ilnp64( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint16_t a[4] = { 0, 0, 0, 0 }; size_t n = 0; const char *p = token->data, *g = p; for (;;) { const uint8_t c = (uint8_t)*p; if (c == ':') { if (n == 3 || p == g || p - g > 4) break; g = p += 1; n += 1; } else { uint16_t x; if (c >= '0' && c <= '9') x = c - '0'; else if (c >= 'A' && c <= 'F') x = c - ('A' - 10); else if (c >= 'a' && c <= 'f') x = c - ('a' - 10); else break; a[n] = (uint16_t)(a[n] << 4u) + x; p += 1; } } if (n != 3 || p == g || p - g > 4 || classify[(uint8_t)*p] == CONTIGUOUS) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); a[0] = htobe16(a[0]); a[1] = htobe16(a[1]); a[2] = htobe16(a[2]); a[3] = htobe16(a[3]); memcpy(rdata->octets, a, 8); rdata->octets += 8; return 0; } #endif // ILNP64_H nsd-4.12.0/simdzone/src/generic/gpos.h0000644000175000017500000001256315002373055017161 0ustar mozziemozzie/* * gpos.h -- Geographical Location (RFC1712) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef GPOS_H #define GPOS_H nonnull_all static really_inline int32_t parse_latitude( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const char *text = token->data + (token->data[0] == '-'); uint32_t degrees; uint8_t digits[4]; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; digits[2] = (uint8_t)text[2] - '0'; digits[3] = (uint8_t)text[3] - '0'; int32_t mask = ((digits[0] <= 9) << 0) | // 0b0001 ((digits[1] <= 9) << 1) | // 0b0010 ((digits[2] <= 9) << 2) | // 0b0100 ((digits[3] <= 9) << 3); // 0b1000 if (token->length > 255) goto bad_latitude; switch (mask) { case 0x01: // 0b0001 ("d...") case 0x09: // 0b1001 ("d..d") text += 1; break; case 0x03: // 0b0011 ("dd..") // ensure no leading zero and range is between -90 and 90 degrees = digits[0] * 10 + digits[1]; if (degrees < 10 || degrees > 90) goto bad_latitude; text += 2; break; case 0x05: // 0b1010 ("d.d.") case 0x0d: // 0b1011 ("d.dd") if (text[1] != '.') text += 1; else for (text += 2; 10u > (uint8_t)((uint8_t)text[0] - '0'); text++) ; break; case 0x0b: // 0b1011 ("dd.d") if (text[2] != '.') text += 2; else for (text += 3; 10u > (uint8_t)((uint8_t)text[0] - '0'); text++) ; break; default: goto bad_latitude; } if (text != token->data + token->length) goto bad_latitude; *rdata->octets = (uint8_t)token->length; memcpy(rdata->octets + 1, token->data, token->length); rdata->octets += 1 + token->length; return 0; bad_latitude: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } nonnull_all static really_inline int32_t parse_longitude( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const char *text = token->data + (token->data[0] == '-'); uint32_t degrees; uint8_t digits[5]; digits[0] = (uint8_t)text[0] - '0'; digits[1] = (uint8_t)text[1] - '0'; digits[2] = (uint8_t)text[2] - '0'; digits[3] = (uint8_t)text[3] - '0'; digits[4] = (uint8_t)text[4] - '0'; int32_t mask = ((digits[0] <= 9) << 0) | // 0b00001 ((digits[1] <= 9) << 1) | // 0b00010 ((digits[2] <= 9) << 2) | // 0b00100 ((digits[3] <= 9) << 3) | // 0b01000 ((digits[4] <= 9) << 4); // 0b10000 if (token->length > 255) goto bad_longitude; switch (mask) { case 0x01: // 0b00001 ("d....") case 0x09: // 0b01001 ("d..d.") case 0x19: // 0b11001 ("d..dd") text += 1; break; case 0x03: // 0b00011 ("dd...") case 0x13: // 0b10011 ("dd..d") degrees = digits[0] * 10 + digits[1]; // ensure no leading zero if (degrees < 10) goto bad_longitude; text += 2; break; case 0x07: // 0b00111 ("ddd..") // ensure no leading zero and range is between -180 and 180 degrees = digits[0] * 100 + digits[1] * 10 + digits[2]; if (degrees < 100 || degrees > 180) goto bad_longitude; text += 3; break; case 0x05: // 0b00101 ("d.d..") case 0x0d: // 0b01101 ("d.dd.") case 0x1d: // 0b11101 ("d.ddd") if (text[1] != '.') text += 1; else for (text += 2; (uint8_t)((uint8_t)text[0] - '0') <= 9u; text++) ; break; case 0x0b: // 0b01011 ("dd.d.") case 0x1b: // 0b11011 ("dd.dd") // ensure no leading zero degrees = digits[0] * 10 + digits[1]; if (degrees < 10) goto bad_longitude; if (text[2] != '.') text += 2; else for (text += 3; (uint8_t)((uint8_t)text[0] - '0') <= 9u; text++) ; break; case 0x17: // 0b10111 ("ddd.d") // ensure no leading zero and range is between -180 and 180 degrees = digits[0] * 100 + digits[1] * 10 + digits[2]; if (degrees < 100 || degrees > 180) goto bad_longitude; if (text[3] != '.') text += 3; else for (text += 4; (uint8_t)((uint8_t)text[0] - '0') <= 9u; text++) ; break; default: goto bad_longitude; } if (text != token->data + token->length) goto bad_longitude; *rdata->octets = (uint8_t)token->length; memcpy(rdata->octets + 1, token->data, token->length); rdata->octets += 1 + token->length; return 0; bad_longitude: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } nonnull_all static really_inline int32_t parse_altitude( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const char *text = token->data; if (token->length > 255) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); for (; (uint8_t)((uint8_t)*text - '0') <= 9u; text++) ; if (*text == '.') for (text++; (uint8_t)((uint8_t)*text - '0') <= 9u; text++) ; if (text != token->data + token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets = (uint8_t)token->length; memcpy(rdata->octets + 1, token->data, token->length); rdata->octets += 1 + token->length; return 0; } #endif // GPOS_H nsd-4.12.0/simdzone/src/generic/format.h0000644000175000017500000003106715002373055017501 0ustar mozziemozzie/* * format.h * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef FORMAT_H #define FORMAT_H #define FIELDS(fields) \ { (sizeof(fields)/sizeof(fields[0])), fields } #define FIELD(name) \ { { { name, sizeof(name) - 1 } } } #define ENTRY(name, fields) \ { { { name, sizeof(name) - 1 }, 0 }, 0, false, false, fields, 0, 0 } nonnull_all static really_inline int32_t parse_type( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint16_t code; const mnemonic_t *mnemonic; if (scan_type(token->data, token->length, &code, &mnemonic) != 1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); code = htobe16(code); memcpy(rdata->octets, &code, 2); rdata->octets += 2; return 0; } nonnull_all static really_inline int32_t parse_name( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { size_t length = 0; assert(is_contiguous(token)); // a freestanding "@" denotes the current origin if (unlikely(token->length == 1 && token->data[0] == '@')) goto relative; switch (scan_name(token->data, token->length, rdata->octets, &length)) { case 0: rdata->octets += length; return 0; case 1: goto relative; } SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); relative: if (length > 255 - parser->file->origin.length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); memcpy(rdata->octets + length, parser->file->origin.octets, parser->file->origin.length); rdata->octets += length + parser->file->origin.length; return 0; } nonnull_all static really_inline int32_t parse_owner( parser_t *parser, const type_info_t *type, const rdata_info_t *field, const token_t *token) { size_t length = 0; uint8_t *octets = parser->file->owner.octets; assert(is_contiguous(token)); // a freestanding "@" denotes the origin if (unlikely(token->length == 1 && token->data[0] == '@')) goto relative; switch (scan_name(token->data, token->length, octets, &length)) { case 0: parser->file->owner.length = length; parser->owner = &parser->file->owner; return 0; case 1: goto relative; } SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); relative: if (length > 255 - parser->file->origin.length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); memcpy(octets+length, parser->file->origin.octets, parser->file->origin.length); parser->file->owner.length = length + parser->file->origin.length; parser->owner = &parser->file->owner; return 0; } nonnull_all static really_inline int32_t parse_string( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { if (rdata->limit == rdata->octets) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(type), NAME(field)); assert(rdata->limit > rdata->octets); int32_t length; uint8_t *octets = rdata->octets + 1; const uint8_t *limit = rdata->limit; if (rdata->limit - rdata->octets > (1 + 255)) limit = rdata->octets + 1 + 255; if ((length = scan_string(token->data, token->length, octets, limit)) == -1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(type), NAME(field)); *rdata->octets = (uint8_t)length; rdata->octets += 1u + (uint32_t)length; return 0; } nonnull_all static really_inline int32_t parse_text( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { int32_t length; if ((length = scan_string(token->data, token->length, rdata->octets, rdata->limit)) == -1) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(type), NAME(field)); rdata->octets += (uint32_t)length; return 0; } nonnull_all static really_inline int32_t parse_rr( parser_t *parser, token_t *token) { static const rdata_info_t fields[] = { FIELD("OWNER"), FIELD("TYPE"), FIELD("CLASS"), FIELD("TTL") }; static const type_info_t rr = ENTRY("RR", FIELDS(fields)); int32_t code; const type_info_t *descriptor; const mnemonic_t *mnemonic; rdata_t rdata = { parser->rdata->octets, parser->rdata->octets + 65535 }; parser->file->ttl = parser->file->default_ttl; if ((uint8_t)token->data[0] - '0' < 10) { parser->file->ttl = &parser->file->last_ttl; if (!scan_ttl(token->data, token->length, parser->options.pretty_ttls, &parser->file->last_ttl)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(&rr)); if (parser->file->last_ttl & (1u << 31)) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(&rr)); goto class_or_type; } else { switch (scan_type_or_class(token->data, token->length, &parser->file->last_type, &mnemonic)) { case 1: goto rdata; case 2: parser->file->last_class = parser->file->last_type; goto ttl_or_type; default: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(&rr)); } } ttl_or_type: if ((code = take_contiguous(parser, &rr, &fields[1], token)) < 0) return code; if ((uint8_t)token->data[0] - '0' < 10) { parser->file->ttl = &parser->file->last_ttl; if (!scan_ttl(token->data, token->length, parser->options.pretty_ttls, &parser->file->last_ttl)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(&rr)); if (parser->file->last_ttl & (1u << 31)) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(&fields[3]), NAME(&rr)); goto type; } else { if (unlikely(scan_type(token->data, token->length, &parser->file->last_type, &mnemonic) != 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(&rr)); goto rdata; } class_or_type: if ((code = take_contiguous(parser, &rr, &fields[1], token)) < 0) return code; switch (scan_type_or_class(token->data, token->length, &parser->file->last_type, &mnemonic)) { case 1: goto rdata; case 2: parser->file->last_class = parser->file->last_type; goto type; default: SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(&rr)); } type: if ((code = take_contiguous(parser, &rr, &fields[1], token)) < 0) return code; if (unlikely(scan_type(token->data, token->length, &parser->file->last_type, &mnemonic) != 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(&rr)); rdata: descriptor = (const type_info_t *)mnemonic; // RFC3597 // parse generic rdata if rdata starts with "\\#" take(parser, token); if (likely(token->data[0] != '\\')) return descriptor->parse(parser, descriptor, &rdata, token); else if (is_contiguous(token) && strncmp(token->data, "\\#", token->length) == 0) return parse_generic_rdata(parser, descriptor, &rdata, token); else return descriptor->parse(parser, descriptor, &rdata, token); } // RFC1035 section 5.1 // $INCLUDE [] [] nonnull_all static really_inline int32_t parse_dollar_include( parser_t *parser, token_t *token) { static const rdata_info_t fields[] = { FIELD("file-name"), FIELD("domain-name") }; static const type_info_t include = ENTRY("$INCLUDE", FIELDS(fields)); if (parser->options.no_includes) NOT_PERMITTED(parser, "%s is disabled", NAME(&include)); int32_t code; file_t *file; if ((code = take_quoted_or_contiguous(parser, &include, &fields[0], token)) < 0) return code; if ((code = zone_open_file(parser, token->data, token->length, &file)) < 0) return code; name_buffer_t name; const name_buffer_t *origin = &parser->file->origin; // $INCLUDE directive MAY specify an origin take(parser, token); if (is_contiguous(token)) { if (scan_name(token->data, token->length, name.octets, &name.length) != 0) { zone_close_file(parser, file); SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), NAME(&include)); } origin = &name; take(parser, token); } // store the current owner to restore later if necessary file_t *includer; includer = parser->file; includer->owner = *parser->owner; file->includer = includer; file->owner = *origin; file->origin = *origin; file->last_type = 0; file->last_class = includer->last_class; file->last_ttl = includer->last_ttl; file->line = 1; if (!is_delimiter(token)) { zone_close_file(parser, file); return have_delimiter(parser, &include, token); } // check for recursive includes for (uint32_t depth = 1; includer; depth++, includer = includer->includer) { if (strcmp(includer->path, file->path) == 0) { zone_error(parser, "Circular include in %s", file->name); zone_close_file(parser, file); return ZONE_SEMANTIC_ERROR; } if (depth > parser->options.include_limit) { zone_error(parser, "Include %s nested too deeply", file->name); zone_close_file(parser, file); return ZONE_SEMANTIC_ERROR; } } // signal $INCLUDE to application if (parser->options.include.callback) { code = parser->options.include.callback( parser, file->name, file->path, parser->user_data); if (code) { zone_close_file(parser, file); return code; } } adjust_line_count(parser->file); parser->file = file; return 0; } // RFC1035 section 5.1 // $ORIGIN [] nonnull_all static inline int32_t parse_dollar_origin( parser_t *parser, token_t *token) { static const rdata_info_t fields[] = { FIELD("name") }; static const type_info_t origin = ENTRY("$ORIGIN", FIELDS(fields)); int32_t code; if ((code = take_contiguous_or_quoted(parser, &origin, &fields[0], token)) < 0) return code; if (scan_name(token->data, token->length, parser->file->origin.octets, &parser->file->origin.length) != 0) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(&origin)); if ((code = take_delimiter(parser, &origin, token)) < 0) return code; adjust_line_count(parser->file); return code; } // RFC2308 section 4 // $TTL [] nonnull_all static really_inline int32_t parse_dollar_ttl( parser_t *parser, token_t *token) { static const rdata_info_t fields[] = { FIELD("ttl") }; static const type_info_t ttl = ENTRY("$TTL", FIELDS(fields)); int32_t code; if ((code = take_contiguous(parser, &ttl, &fields[0], token)) < 0) return code; if (!scan_ttl(token->data, token->length, parser->options.pretty_ttls, &parser->file->dollar_ttl)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(&ttl)); if (parser->file->dollar_ttl & (1u << 31)) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(&ttl)); if ((code = take_delimiter(parser, &ttl, token)) < 0) return code; parser->file->ttl = parser->file->default_ttl = &parser->file->dollar_ttl; adjust_line_count(parser->file); return 0; } static inline int32_t parse(parser_t *parser) { static const rdata_info_t fields[] = { FIELD("OWNER") }; static const type_info_t rr = ENTRY("RR", FIELDS(fields)); int32_t code = 0; token_t token; while (code >= 0) { take(parser, &token); if (likely(is_contiguous(&token))) { if (likely(parser->file->start_of_line)) { // control entry if (unlikely(token.data[0] == '$')) { if (token.length == 4 && memcmp(token.data, "$TTL", 4) == 0) code = parse_dollar_ttl(parser, &token); else if (token.length == 7 && memcmp(token.data, "$ORIGIN", 7) == 0) code = parse_dollar_origin(parser, &token); else if (token.length == 8 && memcmp(token.data, "$INCLUDE", 8) == 0) code = parse_dollar_include(parser, &token); else SYNTAX_ERROR(parser, "Unknown control entry"); continue; } if ((code = parse_owner(parser, &rr, &fields[0], &token)) < 0) return code; if ((code = take_contiguous(parser, &rr, &fields[0], &token)) < 0) return code; } else if (unlikely(!parser->owner->length)) { SYNTAX_ERROR(parser, "No last stated owner"); } code = parse_rr(parser, &token); } else if (is_end_of_file(&token)) { if (parser->file->end_of_file == NO_MORE_DATA) { if (!parser->file->includer) break; file_t *file = parser->file; parser->file = parser->file->includer; parser->owner = &parser->file->owner; zone_close_file(parser, file); } } else if (is_line_feed(&token)) { assert(token.code == LINE_FEED); adjust_line_count(parser->file); } else { code = have_contiguous(parser, &rr, &fields[0], &token); } } return code; } #endif // FORMAT_H nsd-4.12.0/simdzone/src/generic/eui.h0000644000175000017500000000407215002373055016767 0ustar mozziemozzie/* * eui.h -- EUI-48 and EUI-64 (RFC7043) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef EUI_H #define EUI_H nonnull((1,2)) static really_inline bool eui_base16_dec_loop_generic_32_inner(const uint8_t *s, uint8_t *o, bool last) { const uint32_t val1 = base16_table_dec_32bit_d0[s[0]] | base16_table_dec_32bit_d1[s[1]]; const uint32_t val2 = base16_table_dec_32bit_d0[s[3]] | base16_table_dec_32bit_d1[s[4]]; if (val1 > 0xff || val2 > 0xff || s[2] != '-' || (!last && s[5] != '-')) return false; o[0] = (uint8_t)val1; o[1] = (uint8_t)val2; return true; } // RFC7043 section 3.2, require xx-xx-xx-xx-xx-xx nonnull_all static really_inline int32_t parse_eui48( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const uint8_t *input = (const uint8_t *)token->data; if (token->length == 17 && eui_base16_dec_loop_generic_32_inner(input, rdata->octets, false) && eui_base16_dec_loop_generic_32_inner(input+6, rdata->octets+2, false) && eui_base16_dec_loop_generic_32_inner(input+12, rdata->octets+4, true)) return (void)(rdata->octets += 6), 0; SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } // RFC7043 section 4.2, require xx-xx-xx-xx-xx-xx-xx-xx nonnull_all static really_inline int32_t parse_eui64( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { const uint8_t *input = (const uint8_t *)token->data; if (token->length == 23 && eui_base16_dec_loop_generic_32_inner(input, rdata->octets, false) && eui_base16_dec_loop_generic_32_inner(input+6, rdata->octets+2, false) && eui_base16_dec_loop_generic_32_inner(input+12, rdata->octets+4, false) && eui_base16_dec_loop_generic_32_inner(input+18, rdata->octets+6, true)) return (void)(rdata->octets += 8), 0; SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); } #endif // EUI_H nsd-4.12.0/simdzone/src/generic/endian.h0000644000175000017500000001336015002373055017443 0ustar mozziemozzie/* * endian.h -- byte order abstractions * * Copyright (c) 2023, NLnet Labs. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ENDIAN_H #define ENDIAN_H #include "config.h" // https://www.austingroupbugs.net/view.php?id=162#c665 #if _WIN32 #include #define LITTLE_ENDIAN 1234 #define BIG_ENDIAN 4321 #define BYTE_ORDER LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN #define htobe16(x) _byteswap_ushort(x) #define htobe32(x) _byteswap_ulong(x) #define htobe64(x) _byteswap_uint64(x) #define htole16(x) (x) #define htole32(x) (x) #define htole64(x) (x) #define be16toh(x) _byteswap_ushort(x) #define be32toh(x) _byteswap_ulong(x) #define be64toh(x) _byteswap_uint64(x) #define le16toh(x) (x) #define le32toh(x) (x) #define le64toh(x) (x) #else #define htobe16(x) (x) #define htobe32(x) (x) #define htobe64(x) (x) #define htole16(x) _byteswap_ushort(x) #define htole32(x) _byteswap_ulong(x) #define htole64(x) _byteswap_uint64(x) #define be16toh(x) (x) #define be32toh(x) (x) #define be64toh(x) (x) #define le16toh(x) _byteswap_ushort(x) #define le32toh(x) _byteswap_ulong(x) #define le64toh(x) _byteswap_uint64(x) #endif #elif __APPLE__ #include #if !defined BYTE_ORDER # define BYTE_ORDER __BYTE_ORDER__ #endif #if !defined LITTLE_ENDIAN # define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ #endif #if !defined BIG_ENDIAN # define BIG_ENDIAN __ORDER_BIG_ENDIAN__ #endif #define htobe16(x) OSSwapHostToBigInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #else #if HAVE_ENDIAN_H #include #elif defined(__OpenBSD__) // endian.h was added in OpenBSD 5.6. machine/endian.h exports optimized // bswap routines for use in sys/endian.h, which it includes. #include #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include #endif #if defined(__NetBSD__) /* Bring bswap{16,32,64} into scope: */ #include #include #endif #if !defined(LITTLE_ENDIAN) # if defined(__ORDER_LITTLE_ENDIAN__) # define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ # else # define LITTLE_ENDIAN 1234 # endif #endif #if !defined(BIG_ENDIAN) # if defined(__ORDER_BIG_ENDIAN__) # define BIG_ENDIAN __ORDER_BIG_ENDIAN__ # else # define BIG_ENDIAN 4321 # endif #endif #if !defined(BYTE_ORDER) # if defined(__BYTE_ORDER__) # define BYTE_ORDER __BYTE_ORDER__ # elif defined(__BYTE_ORDER) # define BYTE_ORDER __BYTE_ORDER # elif defined(i386) || defined(__i386__) || defined(__i486__) || \ defined(__i586__) || defined(__i686__) || \ defined(__x86) || defined(__x86_64) || defined(__x86_64__) || \ defined(__amd64) || defined(__amd64__) # define BYTE_ORDER LITTLE_ENDIAN # elif defined(sparc) || defined(__sparc) || defined(__sparc__) || \ defined(POWERPC) || defined(mc68000) || defined(sel) # define BYTE_ORDER BIG_ENDIAN # else # error "missing definition of BYTE_ORDER" # endif #endif #if !defined(__NetBSD__) #if !HAVE_DECL_BSWAP16 static really_inline uint16_t bswap16(uint16_t x) { // Copied from src/common/lib/libc/gen/bswap16.c in NetBSD // Written by Manuel Bouyer . // Public domain. return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff); } #endif #if !HAVE_DECL_BSWAP32 static really_inline uint32_t bswap32(uint32_t x) { // Copied from src/common/lib/libc/gen/bswap32.c in NetBSD // Written by Manuel Bouyer . // Public domain. return ( (x << 24) & 0xff000000 ) | ( (x << 8) & 0x00ff0000 ) | ( (x >> 8) & 0x0000ff00 ) | ( (x >> 24) & 0x000000ff ); } #endif #if !HAVE_DECL_BSWAP64 static really_inline uint64_t bswap64(uint64_t x) { // Copied from src/common/lib/libc/gen/bswap64.c in NetBSD // Written by Manuel Bouyer . // Public domain. return ( (x << 56) & 0xff00000000000000ull ) | ( (x << 40) & 0x00ff000000000000ull ) | ( (x << 24) & 0x0000ff0000000000ull ) | ( (x << 8) & 0x000000ff00000000ull ) | ( (x >> 8) & 0x00000000ff000000ull ) | ( (x >> 24) & 0x0000000000ff0000ull ) | ( (x >> 40) & 0x000000000000ff00ull ) | ( (x >> 56) & 0x00000000000000ffull ); } #endif #endif /* !defined(__NetBSD__) */ # if BYTE_ORDER == LITTLE_ENDIAN # define htobe(bits, x) bswap ## bits((x)) # define htole(bits, x) (x) # define betoh(bits, x) bswap ## bits((x)) # define letoh(bits, x) (x) # else # define htobe(bits, x) (x) # define htole(bits, x) bswap ## bits((x)) # define betoh(bits, x) (x) # define letoh(bits, x) bswap ## bits((x)) # endif # if !defined htobe16 # define htobe16(x) htobe(16,(x)) # endif # if !defined htobe32 # define htobe32(x) htobe(32,(x)) # endif # if !defined htobe64 # define htobe64(x) htobe(64,(x)) # endif # if !defined htole16 # define htole16(x) htole(16,(x)) # endif # if !defined htole32 # define htole32(x) htole(32,(x)) # endif # if !defined htole64 # define htole64(x) htole(64,(x)) # endif # if !defined be16toh # define be16toh(x) betoh(16,(x)) # endif # if !defined be32toh # define be32toh(x) betoh(32,(x)) # endif # if !defined be64toh # define be64toh(x) betoh(64,(x)) # endif # if !defined le16toh # define le16toh(x) letoh(16,(x)) # endif # if !defined le32toh # define le32toh(x) letoh(32,(x)) # endif # if !defined le64toh # define le64toh(x) letoh(64,(x)) # endif #endif #endif // ENDIAN_H nsd-4.12.0/simdzone/src/generic/cert.h0000644000175000017500000000645315002373055017147 0ustar mozziemozzie/* * cert.h * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef CERT_H #define CERT_H // https://www.iana.org/assignments/cert-rr-types/cert-rr-types.xhtml typedef struct certificate_type certificate_type_t; struct certificate_type { struct { char name[8]; size_t length; } key; uint16_t value; }; #define BAD_CERTIFICATE_TYPE(value) \ { { "", 0 }, 0 } #define CERTIFICATE_TYPE(name, value) \ { { name, sizeof(name) - 1 }, value } static const certificate_type_t certificate_types[] = { BAD_CERTIFICATE_TYPE(0), CERTIFICATE_TYPE("PKIX", 1), CERTIFICATE_TYPE("SPKI", 2), CERTIFICATE_TYPE("PGP", 3), CERTIFICATE_TYPE("IPKIX", 4), CERTIFICATE_TYPE("ISPKI", 5), CERTIFICATE_TYPE("IPGP", 6), CERTIFICATE_TYPE("ACPKIX", 7), CERTIFICATE_TYPE("IACPKIX", 8), CERTIFICATE_TYPE("URI", 253), CERTIFICATE_TYPE("OID", 254), }; static const certificate_type_t *certificate_type_map[16] = { &certificate_types[5], // ISPKI (0) &certificate_types[0], &certificate_types[0], &certificate_types[0], &certificate_types[0], &certificate_types[0], &certificate_types[10], // OID (6) &certificate_types[0], &certificate_types[3], // PGP (8) &certificate_types[4], // IPKIX (9) &certificate_types[2], // SPKI (10) &certificate_types[1], // PKIX (11) &certificate_types[8], // IACPKIX (12) &certificate_types[9], // URI (13) &certificate_types[6], // IPGP (14) &certificate_types[7] // ACPKIX (15) }; // magic value generated using certificate-hash.c static uint8_t certificate_hash(uint64_t value) { value = le64toh(value); uint32_t value32 = (uint32_t)((value >> 32) ^ value); return (uint8_t)((value32 * 98112ull) >> 32) & 0xf; } nonnull_all static really_inline int32_t scan_certificate_type( const char *data, size_t length, uint16_t *type) { static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if ((uint8_t)*data - '0' > 9) { uint64_t input; memcpy(&input, data, 8); static const uint64_t letter_mask = 0x4040404040404040llu; // convert to upper case input &= ~((input & letter_mask) >> 1); // zero out non-relevant bytes uint64_t zero_mask; memcpy(&zero_mask, &zero_masks[32 - (length & 0xf)], 8); input &= zero_mask; const uint8_t index = certificate_hash(input); assert(index < 16); const certificate_type_t *certificate_type = certificate_type_map[index]; uint64_t name; memcpy(&name, certificate_type->key.name, 8); *type = certificate_type->value; return (input == name) & (length == certificate_type->key.length) & (*type != 0); } return scan_int16(data, length, type); } nonnull_all static really_inline int32_t parse_certificate_type( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint16_t cert; if (!scan_certificate_type(token->data, token->length, &cert)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); cert = htobe16(cert); memcpy(rdata->octets, &cert, 2); rdata->octets += 2; return 0; } #endif // CERT_H nsd-4.12.0/simdzone/src/generic/caa.h0000644000175000017500000000646515002373055016741 0ustar mozziemozzie/* * caa.h -- CAA (RFC8659) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef CAA_H #define CAA_H static const uint8_t bad_caa_chars[256] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x00 - 0x07 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x08 - 0x0f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x10 - 0x17 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x18 - 0x10f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x20 - 0x27 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x28 - 0x2f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 - 0x37 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x38 - 0x3f 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40 - 0x47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x58 - 0x5f 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x78 - 0x7f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x80 - 0x87 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x88 - 0x8f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x90 - 0x97 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x98 - 0x9f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa0 - 0xa7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa8 - 0xaf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb0 - 0xb7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb8 - 0xbf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc0 - 0xc7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc8 - 0xcf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd0 - 0xd7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd8 - 0xdf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe0 - 0xe7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe0 - 0xe7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xf8 - 0xff 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xf8 - 0xff }; nonnull_all static really_inline int32_t parse_caa_tag( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { // RFC8659 section 4.1 // https://datatracker.ietf.org/doc/html/rfc8659 // // Certification Authority Restriction Properties registered by IANA // https://www.iana.org/assignments/pkix-parameters/pkix-parameters.xhtml if (token->length > 255) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets++ = (uint8_t)token->length; uint32_t bad_chars = 0; for (size_t count=0; count < token->length; count++) { const uint8_t octet = (uint8_t)token->data[count]; *rdata->octets++ = octet; bad_chars |= bad_caa_chars[octet]; } // Tags MAY contain ASCII characters "a" through "z", "A" through "Z", // and the numbers 0 through 9. Tags MUST NOT contain any other // characters. Matching of tags is case insensitive. if (bad_chars) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return 0; } #endif // CAA_H nsd-4.12.0/simdzone/src/generic/base64.h0000644000175000017500000010467115002373055017277 0ustar mozziemozzie/* * base64.h -- Fast Base64 stream decoder * * Copyright (c) 2005-2007, Nick Galbreath. * Copyright (c) 2015-2018, Wojciech MuĹ‚a. * Copyright (c) 2016-2017, Matthieu Darbois. * Copyright (c) 2013-2022, Alfred Klomp. * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause * */ #ifndef BASE64_H #define BASE64_H // Modified version of https://github.com/aklomp/base64 struct base64_state { int eof; int bytes; unsigned char carry; }; #include #define CHAR62 '+' #define CHAR63 '/' #define CHARPAD '=' // End-of-file definitions. // Almost end-of-file when waiting for the last '=' character: #define BASE64_AEOF 1 // End-of-file when stream end has been reached or invalid input provided: #define BASE64_EOF 2 // In the lookup table below, note that the value for '=' (character 61) is // 254, not 255. This character is used for in-band signaling of the end of // the datastream, and we will use that later. The characters A-Z, a-z, 0-9 // and + / are mapped to their "decoded" values. The other bytes all map to // the value 255, which flags them as "invalid input". static const uint8_t base64_table_dec_8bit[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0..15 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 16..31 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, // 32..47 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, // 48..63 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64..79 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 80..95 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96..111 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, // 112..127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 128..143 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; #if BYTE_ORDER == LITTLE_ENDIAN /* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */ static const uint32_t base64_table_dec_32bit_d0[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000f8, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000fc, 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 0x00000064, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, 0x000000c4, 0x000000c8, 0x000000cc, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; static const uint32_t base64_table_dec_32bit_d1[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000e003, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000f003, 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 0x00009001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, 0x00001003, 0x00002003, 0x00003003, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; static const uint32_t base64_table_dec_32bit_d2[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00800f00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00c00f00, 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 0x00400600, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, 0x00400c00, 0x00800c00, 0x00c00c00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; static const uint32_t base64_table_dec_32bit_d3[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x003e0000, 0xffffffff, 0xffffffff, 0xffffffff, 0x003f0000, 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 0x00190000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, 0x00310000, 0x00320000, 0x00330000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; #elif BYTE_ORDER == BIG_ENDIAN /* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */ const uint32_t base64_table_dec_32bit_d0[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xfc000000, 0xd0000000, 0xd4000000, 0xd8000000, 0xdc000000, 0xe0000000, 0xe4000000, 0xe8000000, 0xec000000, 0xf0000000, 0xf4000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x04000000, 0x08000000, 0x0c000000, 0x10000000, 0x14000000, 0x18000000, 0x1c000000, 0x20000000, 0x24000000, 0x28000000, 0x2c000000, 0x30000000, 0x34000000, 0x38000000, 0x3c000000, 0x40000000, 0x44000000, 0x48000000, 0x4c000000, 0x50000000, 0x54000000, 0x58000000, 0x5c000000, 0x60000000, 0x64000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x68000000, 0x6c000000, 0x70000000, 0x74000000, 0x78000000, 0x7c000000, 0x80000000, 0x84000000, 0x88000000, 0x8c000000, 0x90000000, 0x94000000, 0x98000000, 0x9c000000, 0xa0000000, 0xa4000000, 0xa8000000, 0xac000000, 0xb0000000, 0xb4000000, 0xb8000000, 0xbc000000, 0xc0000000, 0xc4000000, 0xc8000000, 0xcc000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d1[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x03e00000, 0xffffffff, 0xffffffff, 0xffffffff, 0x03f00000, 0x03400000, 0x03500000, 0x03600000, 0x03700000, 0x03800000, 0x03900000, 0x03a00000, 0x03b00000, 0x03c00000, 0x03d00000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00100000, 0x00200000, 0x00300000, 0x00400000, 0x00500000, 0x00600000, 0x00700000, 0x00800000, 0x00900000, 0x00a00000, 0x00b00000, 0x00c00000, 0x00d00000, 0x00e00000, 0x00f00000, 0x01000000, 0x01100000, 0x01200000, 0x01300000, 0x01400000, 0x01500000, 0x01600000, 0x01700000, 0x01800000, 0x01900000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x01a00000, 0x01b00000, 0x01c00000, 0x01d00000, 0x01e00000, 0x01f00000, 0x02000000, 0x02100000, 0x02200000, 0x02300000, 0x02400000, 0x02500000, 0x02600000, 0x02700000, 0x02800000, 0x02900000, 0x02a00000, 0x02b00000, 0x02c00000, 0x02d00000, 0x02e00000, 0x02f00000, 0x03000000, 0x03100000, 0x03200000, 0x03300000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d2[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000f8000, 0xffffffff, 0xffffffff, 0xffffffff, 0x000fc000, 0x000d0000, 0x000d4000, 0x000d8000, 0x000dc000, 0x000e0000, 0x000e4000, 0x000e8000, 0x000ec000, 0x000f0000, 0x000f4000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00004000, 0x00008000, 0x0000c000, 0x00010000, 0x00014000, 0x00018000, 0x0001c000, 0x00020000, 0x00024000, 0x00028000, 0x0002c000, 0x00030000, 0x00034000, 0x00038000, 0x0003c000, 0x00040000, 0x00044000, 0x00048000, 0x0004c000, 0x00050000, 0x00054000, 0x00058000, 0x0005c000, 0x00060000, 0x00064000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00068000, 0x0006c000, 0x00070000, 0x00074000, 0x00078000, 0x0007c000, 0x00080000, 0x00084000, 0x00088000, 0x0008c000, 0x00090000, 0x00094000, 0x00098000, 0x0009c000, 0x000a0000, 0x000a4000, 0x000a8000, 0x000ac000, 0x000b0000, 0x000b4000, 0x000b8000, 0x000bc000, 0x000c0000, 0x000c4000, 0x000c8000, 0x000cc000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d3[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00003e00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00003f00, 0x00003400, 0x00003500, 0x00003600, 0x00003700, 0x00003800, 0x00003900, 0x00003a00, 0x00003b00, 0x00003c00, 0x00003d00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, 0x00000900, 0x00000a00, 0x00000b00, 0x00000c00, 0x00000d00, 0x00000e00, 0x00000f00, 0x00001000, 0x00001100, 0x00001200, 0x00001300, 0x00001400, 0x00001500, 0x00001600, 0x00001700, 0x00001800, 0x00001900, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00001a00, 0x00001b00, 0x00001c00, 0x00001d00, 0x00001e00, 0x00001f00, 0x00002000, 0x00002100, 0x00002200, 0x00002300, 0x00002400, 0x00002500, 0x00002600, 0x00002700, 0x00002800, 0x00002900, 0x00002a00, 0x00002b00, 0x00002c00, 0x00002d00, 0x00002e00, 0x00002f00, 0x00003000, 0x00003100, 0x00003200, 0x00003300, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; #else # error "byte order unknown" #endif // LITTLE_ENDIAN static really_inline int dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds) { const uint32_t str = base64_table_dec_32bit_d0[(*s)[0]] | base64_table_dec_32bit_d1[(*s)[1]] | base64_table_dec_32bit_d2[(*s)[2]] | base64_table_dec_32bit_d3[(*s)[3]]; #if BYTE_ORDER == LITTLE_ENDIAN // LUTs for little-endian set MSB in case of invalid character: if (str & UINT32_C(0x80000000)) { return 0; } #else // LUTs for big-endian set LSB in case of invalid character: if (str & UINT32_C(1)) { return 0; } #endif // Store the output: memcpy(*o, &str, sizeof (str)); *s += 4; *o += 3; *rounds -= 1; return 1; } static really_inline void dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 8) { return; } // Process blocks of 4 bytes per round. Because one extra zero byte is // written after the output, ensure that there will be at least 4 bytes // of input data left to cover the gap. (Two data bytes and up to two // end-of-string markers.) size_t rounds = (*slen - 4) / 4; *slen -= rounds * 4; // 4 bytes consumed per round *olen += rounds * 3; // 3 bytes produced per round do { if (rounds >= 8) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 4) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 2) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } dec_loop_generic_32_inner(s, o, &rounds); break; } while (rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 4; *olen -= rounds * 3; } nonnull((1,2,4,5)) static really_inline int base64_stream_decode( struct base64_state *state, const char *src, size_t srclen, uint8_t *out, size_t *outlen) { int ret = 0; const uint8_t *s = (const uint8_t *) src; uint8_t *o = (uint8_t *) out; uint8_t q; // Use local temporaries to avoid cache thrashing: size_t olen = 0; size_t slen = srclen; struct base64_state st; st.eof = state->eof; st.bytes = state->bytes; st.carry = state->carry; // If we previously saw an EOF or an invalid character, bail out: if (st.eof) { *outlen = 0; ret = 0; // If there was a trailing '=' to check, check it: if (slen && (st.eof == BASE64_AEOF)) { state->bytes = 0; state->eof = BASE64_EOF; ret = ((base64_table_dec_8bit[*s++] == 254) && (slen == 1)) ? 1 : 0; } return ret; } // Turn four 6-bit numbers into three bytes: // out[0] = 11111122 // out[1] = 22223333 // out[2] = 33444444 // Duff's device again: switch (st.bytes) { #if defined(__SUNPRO_C) #pragma error_messages(off, E_STATEMENT_NOT_REACHED) #endif for (;;) #if defined(__SUNPRO_C) #pragma error_messages(default, E_STATEMENT_NOT_REACHED) #endif { case 0: dec_loop_generic_32(&s, &slen, &o, &olen); if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.eof = BASE64_EOF; // Treat character '=' as invalid for byte 0: break; } st.carry = (uint8_t)(q << 2); st.bytes++; // fallthrough case 1: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.eof = BASE64_EOF; // Treat character '=' as invalid for byte 1: break; } *o++ = st.carry | (q >> 4); st.carry = (uint8_t)(q << 4); st.bytes++; olen++; // fallthrough case 2: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.bytes++; // When q == 254, the input char is '='. // Check if next byte is also '=': if (q == 254) { if (slen-- != 0) { st.bytes = 0; // EOF: st.eof = BASE64_EOF; q = base64_table_dec_8bit[*s++]; ret = ((q == 254) && (slen == 0)) ? 1 : 0; break; } else { // Almost EOF st.eof = BASE64_AEOF; ret = 1; break; } } // If we get here, there was an error: break; } *o++ = st.carry | (q >> 2); st.carry = (uint8_t)(q << 6); st.bytes++; olen++; // fallthrough case 3: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.bytes = 0; st.eof = BASE64_EOF; // When q == 254, the input char is '='. Return 1 and EOF. // When q == 255, the input char is invalid. Return 0 and EOF. ret = ((q == 254) && (slen == 0)) ? 1 : 0; break; } *o++ = st.carry | q; st.carry = 0; st.bytes = 0; olen++; } } state->eof = st.eof; state->bytes = st.bytes; state->carry = st.carry; *outlen = olen; return ret; } nonnull((1,3,4)) static really_inline int base64_decode( const char *src, size_t srclen, uint8_t *out, size_t *outlen) { struct base64_state state = { .eof = 0, .bytes = 0, .carry = 0 }; return base64_stream_decode(&state, src, srclen, out, outlen) & !state.bytes; } nonnull_all static really_inline int32_t parse_base64_sequence( parser_t *parser, const type_info_t *type, const rdata_info_t *item, rdata_t *rdata, token_t *token) { if (is_contiguous(token)) { struct base64_state state = { .eof = 0, .bytes = 0, .carry = 0 }; do { size_t length = token->length / 4; if (((uintptr_t)rdata->limit - (uintptr_t)rdata->octets) / 3 < length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); if (!base64_stream_decode(&state, token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); rdata->octets += length; take(parser, token); } while (is_contiguous(token)); // incomplete base64 sequence if (state.bytes) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); } return have_delimiter(parser, type, token); } nonnull_all static really_inline int32_t parse_base64( parser_t *parser, const type_info_t *type, const rdata_info_t *item, rdata_t *rdata, const token_t *token) { size_t length = token->length / 4; if (((uintptr_t)rdata->limit - (uintptr_t)rdata->octets) / 3 < length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); if (!base64_decode(token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(item), NAME(type)); rdata->octets += length; return 0; } #endif // BASE64_H nsd-4.12.0/simdzone/src/generic/base32.h0000644000175000017500000001007515002373055017264 0ustar mozziemozzie/* * base32.h -- Base32 decoder * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef BASE32_H #define BASE32_H static const uint8_t b32rmap[256] = { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */ 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, /* 8 - 15 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 - 23 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24 - 31 */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 - 39 */ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40 - 47 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 48 - 55 */ 0x08, 0x09, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, /* 56 - 63 */ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* 64 - 71 */ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* 72 - 79 */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0xff, /* 80 - 87 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88 - 95 */ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* 96 - 103 */ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* 104 - 111 */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0xff, /* 112 - 119 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120 - 127 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 - 135 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 136 - 143 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 144 - 151 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 152 - 159 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 160 - 167 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 168 - 175 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 176 - 183 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 184 - 191 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 192 - 199 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 200 - 207 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 208 - 215 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 216 - 223 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 224 - 231 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 232 - 239 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 240 - 247 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 248 - 255 */ }; static const uint8_t b32rmap_special = 0xf0; nonnull_all static really_inline int32_t parse_base32( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint32_t state = 0; size_t length = (token->length * 5) / 8; if (length > 255 || (uintptr_t)rdata->limit - (uintptr_t)rdata->octets < (length + 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets++ = (uint8_t)length; const char *p = token->data; for (;; p++) { const uint8_t ofs = b32rmap[(uint8_t)*p]; if (ofs >= b32rmap_special) break; switch (state) { case 0: *rdata->octets = (uint8_t)(ofs << 3); state = 1; break; case 1: *rdata->octets++ |= (uint8_t)(ofs >> 2); *rdata->octets = (uint8_t)(ofs << 6); state = 2; break; case 2: *rdata->octets |= (uint8_t)(ofs << 1); state = 3; break; case 3: *rdata->octets++ |= (uint8_t)(ofs >> 4); *rdata->octets = (uint8_t)(ofs << 4); state = 4; break; case 4: *rdata->octets++ |= (uint8_t)(ofs >> 1); *rdata->octets = (uint8_t)(ofs << 7); state = 5; break; case 5: *rdata->octets |= (uint8_t)(ofs << 2); state = 6; break; case 6: *rdata->octets++ |= (uint8_t)(ofs >> 3); *rdata->octets = (uint8_t)(ofs << 5); state = 7; break; case 7: *rdata->octets++ |= ofs; state = 0; break; } } if (p != token->data + token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return 0; } #endif // BASE32_H nsd-4.12.0/simdzone/src/generic/base16.h0000644000175000017500000002266315002373055017274 0ustar mozziemozzie/* * base16.h -- Fast Base16 stream decoder * * Copyright (c) 2005-2016, Nick Galbreath. * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause * */ #ifndef BASE16_H #define BASE16_H // adaptation of base16 decoder by Nick Galbreath to operate similar to the // base64 stream decoder by Alfred Klomp. // https://github.com/client9/stringencoders // https://github.com/aklomp/base64 struct base16_state { int eof; int bytes; unsigned char carry; }; #define BASE16_EOF 1 static const uint32_t base16_table_dec_32bit_d0[256] = { 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, 256, 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 256, 256, 256, 256, 256, 256, 256, 160, 176, 192, 208, 224, 240, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 160, 176, 192, 208, 224, 240, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 }; static const uint32_t base16_table_dec_32bit_d1[256] = { 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, 256, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 }; static really_inline int base16_dec_loop_generic_32_inner( const uint8_t **s, uint8_t **o, size_t *rounds) { const uint32_t val1 = base16_table_dec_32bit_d0[(*s)[0]] | base16_table_dec_32bit_d1[(*s)[1]]; const uint32_t val2 = base16_table_dec_32bit_d0[(*s)[2]] | base16_table_dec_32bit_d1[(*s)[3]]; if (val1 > 0xff || val2 > 0xff) return 0; (*o)[0] = (uint8_t)val1; (*o)[1] = (uint8_t)val2; *s += 4; *o += 2; *rounds -= 1; return 1; } static really_inline void base16_dec_loop_generic_32( const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 4) return; // some comment on the how and what... size_t rounds = (*slen - 4) / 4; *slen -= rounds * 4; // 4 bytes consumed per round *olen += rounds * 2; // 2 bytes produced per round do { if (rounds >= 8) { if (base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds)) continue; break; } if (rounds >= 4) { if (base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds)) continue; break; } if (rounds >= 2) { if (base16_dec_loop_generic_32_inner(s, o, &rounds) && base16_dec_loop_generic_32_inner(s, o, &rounds)) continue; break; } base16_dec_loop_generic_32_inner(s, o, &rounds); break; } while (rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 4; *olen -= rounds * 2; } nonnull((1,2,4,5)) static really_inline int base16_stream_decode( struct base16_state *state, const char *src, size_t srclen, uint8_t *out, size_t *outlen) { int ret = 0; const uint8_t *s = (const uint8_t *) src; uint8_t *o = (uint8_t *) out; uint32_t q; // Use local temporaries to avoid cache thrashing: size_t olen = 0; size_t slen = srclen; struct base16_state st; st.eof = state->eof; st.bytes = state->bytes; st.carry = state->carry; if (st.eof) { *outlen = 0; return ret; } // Duff's device again: switch (st.bytes) { #if defined(__SUNPRO_C) #pragma error_messages(off, E_STATEMENT_NOT_REACHED) #endif for (;;) #if defined(__SUNPRO_C) #pragma error_messages(default, E_STATEMENT_NOT_REACHED) #endif { case 0: base16_dec_loop_generic_32(&s, &slen, &o, &olen); if (slen-- == 0) { ret = 1; break; } if ((q = base16_table_dec_32bit_d0[*s++]) >= 255) { st.eof = BASE16_EOF; break; } st.carry = (uint8_t)q; st.bytes = 1; // fallthrough case 1: if (slen-- == 0) { ret = 1; break; } if ((q = base16_table_dec_32bit_d1[*s++]) >= 255) { st.eof = BASE16_EOF; break; } *o++ = st.carry | (uint8_t)q; st.carry = 0; st.bytes = 0; olen++; } } state->eof = st.eof; state->bytes = st.bytes; state->carry = st.carry; *outlen = olen; return ret; } nonnull((1,3,4)) static really_inline int base16_decode( const char *src, size_t srclen, uint8_t *out, size_t *outlen) { struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 }; return base16_stream_decode(&state, src, srclen, out, outlen) & !state.bytes; } // FIXME: RFC3597 section 5 states each word of data must contain an even // number of hexadecimal digits. The same is not true for DS records. // RFC4043 section 5.3 merely states whitespace is allowed within the // hexadecimal text. Words containing an uneven number of hexadecimal // digits are impractical, but supported (BIND supports uneven // sequences) nonnull_all static really_inline int32_t parse_base16_sequence( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, token_t *token) { if (is_contiguous(token)) { struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 }; do { size_t length = (token->length + 1) / 2; if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); if (!base16_stream_decode(&state, token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets += length; take(parser, token); } while (is_contiguous(token)); if (state.bytes) *rdata->octets++ = state.carry; } return have_delimiter(parser, type, token); } nonnull_all static really_inline int32_t parse_base16( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { size_t length = token->length / 2; if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); if (!base16_decode(token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets += length; return 0; } nonnull_all static really_inline int32_t parse_salt( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { if (token->length == 1 && token->data[0] == '-') return (void)(*rdata->octets++ = 0), 0; size_t length = token->length / 2; uint8_t *octets = rdata->octets++; // FIXME: not quite right yet! we must not exceed 255 octets! if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < (length + 1)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); if (!base16_decode(token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *octets = (uint8_t)length; rdata->octets += length; return 0; } #endif // BASE16_H nsd-4.12.0/simdzone/src/generic/atma.h0000644000175000017500000001716015002373055017131 0ustar mozziemozzie/* * atma.h -- ATMA parser (see: https://web.archive.org/web/20190112072924/http://www.broadband-forum.org/ftp/pub/approved-specs/af-dans-0152.000.pdf ) * * Copyright (c) 2025, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ATMA_H #define ATMA_H static const uint8_t bad_atma_chars[256] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x00 - 0x07 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x08 - 0x0f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x10 - 0x17 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x18 - 0x1f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x20 - 0x27 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, // 0x28 - 0x2f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 - 0x37 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x38 - 0x3f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x40 - 0x47 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x48 - 0x4f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x50 - 0x57 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x58 - 0x5f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x60 - 0x67 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x68 - 0x6f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x70 - 0x77 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x78 - 0x7f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x80 - 0x87 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x88 - 0x8f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x90 - 0x97 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x98 - 0x9f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa0 - 0xa7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xa8 - 0xaf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb0 - 0xb7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xb8 - 0xbf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc0 - 0xc7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xc8 - 0xcf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd0 - 0xd7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xd8 - 0xdf 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe0 - 0xe7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xe0 - 0xe7 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xf8 - 0xff 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0xf8 - 0xff }; static const uint8_t atma_increment[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01 - 0x07 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2f 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x30 - 0x37 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40 - 0x47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9f 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa0 - 0xa7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa8 - 0xaf 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb0 - 0xb7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb8 - 0xbf 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 - 0xc7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc8 - 0xcf 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd0 - 0xd7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd8 - 0xdf 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe0 - 0xe7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe0 - 0xe7 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf8 - 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf8 - 0x00 }; nonnull_all static really_inline int32_t parse_atma_e164( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { uint32_t bad_chars = 0; for (size_t count=1; count < token->length; count++) { const uint8_t octet = (uint8_t)token->data[count]; *rdata->octets = octet; rdata->octets += atma_increment[octet]; bad_chars |= bad_atma_chars[octet]; } if (bad_chars) SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return 0; } nonnull((1,2,4,5)) static really_inline int atma_stream_decode( struct base16_state *state, const char *src, size_t srclen, uint8_t *out, size_t *outlen) { int ret = 0; const uint8_t *s = (const uint8_t *) src; uint8_t *o = (uint8_t *) out; uint32_t q; // Use local temporaries to avoid cache thrashing: size_t olen = 0; size_t slen = srclen; struct base16_state st; st.eof = state->eof; st.bytes = state->bytes; st.carry = state->carry; if (st.eof) { *outlen = 0; return ret; } // Duff's device again: switch (st.bytes) { #if defined(__SUNPRO_C) #pragma error_messages(off, E_STATEMENT_NOT_REACHED) #endif for (;;) #if defined(__SUNPRO_C) #pragma error_messages(default, E_STATEMENT_NOT_REACHED) #endif { case 0: base16_dec_loop_generic_32(&s, &slen, &o, &olen); if (slen-- == 0) { ret = 1; break; } if ((q = base16_table_dec_32bit_d0[*s++]) == 256) { st.eof = BASE16_EOF; break; } else if (q == 257) { continue; } st.carry = (uint8_t)q; st.bytes = 1; // fallthrough case 1: if (slen-- == 0) { ret = 1; break; } if ((q = base16_table_dec_32bit_d1[*s++]) == 256) { st.eof = BASE16_EOF; break; } else if (q == 257) { continue; } *o++ = st.carry | (uint8_t)q; st.carry = 0; st.bytes = 0; olen++; } } state->eof = st.eof; state->bytes = st.bytes; state->carry = st.carry; *outlen = olen; return ret; } nonnull((1,3,4)) static really_inline int atma_decode( const char *src, size_t srclen, uint8_t *out, size_t *outlen) { struct base16_state state = { .eof = 0, .bytes = 0, .carry = 0 }; return atma_stream_decode(&state, src, srclen, out, outlen) & !state.bytes; } nonnull_all static really_inline int32_t parse_atma( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { if (token->length && (char)*token->data == '+') { *rdata->octets++ = 1; if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < token->length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); return parse_atma_e164(parser, type, field, rdata, token); } size_t length = token->length / 2; if ((uintptr_t)rdata->limit - (uintptr_t)rdata->octets < length) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); *rdata->octets++ = 0; if (!atma_decode(token->data, token->length, rdata->octets, &length)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets += length; return 0; } #endif // ATMA_H nsd-4.12.0/simdzone/src/generic/apl.h0000644000175000017500000000421615002373055016761 0ustar mozziemozzie/* * apl.h -- Address Prefix Lists (RFC3123) parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef APL_H #define APL_H static really_inline int32_t scan_apl( const char *text, size_t length, uint8_t *octets, size_t size) { uint8_t negate = text[0] == '!'; uint8_t digits[3]; int32_t count; uint32_t prefix; const uint8_t af_inet[2] = { 0x00, 0x01 }, af_inet6[2] = { 0x00, 0x02 }; // address family is immediately followed by a colon ":" if (text[negate + 1] != ':') return -1; switch (text[negate]) { case '1': if (size < 8) return -1; memcpy(octets, af_inet, sizeof(af_inet)); if (!(count = scan_ip4(&text[negate+2], &octets[4]))) return -1; count += negate + 2; digits[0] = (uint8_t)text[count+1] - '0'; digits[1] = (uint8_t)text[count+2] - '0'; if (text[count] != '/' || digits[0] > 9) return -1; if (digits[1] > 9) (void)(count += 2), prefix = digits[0]; else (void)(count += 3), prefix = digits[0] * 10 + digits[1]; if (prefix > 32 || (size_t)count != length) return -1; octets[2] = (uint8_t)prefix; octets[3] = (uint8_t)((negate << 7) | 4); return 8; case '2': if (size < 20) return -1; memcpy(octets, af_inet6, sizeof(af_inet6)); if (!(count = scan_ip6(&text[negate+2], &octets[4]))) return -1; count += negate + 2; digits[0] = (uint8_t)text[count+1] - '0'; digits[1] = (uint8_t)text[count+2] - '0'; digits[2] = (uint8_t)text[count+3] - '0'; if (text[count] != '/' || digits[0] > 9) return -1; if (digits[1] > 9) (void)(count += 2), prefix = digits[0]; else if (digits[2] > 9) (void)(count += 3), prefix = digits[0] * 10 + digits[1]; else (void)(count += 4), prefix = digits[0] * 100 + digits[1] * 10 + digits[0]; if (prefix > 128 || (size_t)count != length) return -1; octets[2] = (uint8_t)prefix; octets[3] = (uint8_t)((negate << 7) | 16); return 20; default: return -1; } } #endif // APL_H nsd-4.12.0/simdzone/src/generic/algorithm.h0000644000175000017500000001207415002373055020174 0ustar mozziemozzie/** * algorithm.h -- Algorithm RDATA parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ALGORITHM_H #define ALGORITHM_H // https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml typedef struct algorithm algorithm_t; struct algorithm { struct { char name[24]; size_t length; } key; uint8_t value; }; #define BAD_ALGORITHM(value) \ { { "", 0 }, 0 } #define ALGORITHM(name, value) \ { { name, sizeof(name) - 1 }, value } static const algorithm_t algorithms[32] = { BAD_ALGORITHM(0), ALGORITHM("RSAMD5", 1), ALGORITHM("DH", 2), ALGORITHM("DSA", 3), ALGORITHM("ECC", 4), ALGORITHM("RSASHA1", 5), ALGORITHM("DSA-NSEC-SHA1", 6), ALGORITHM("RSASHA1-NSEC3-SHA1", 7), ALGORITHM("RSASHA256", 8), BAD_ALGORITHM(9), ALGORITHM("RSASHA512", 10), BAD_ALGORITHM(11), ALGORITHM("ECC-GOST", 12), ALGORITHM("ECDSAP256SHA256", 13), ALGORITHM("ECDSAP384SHA384", 14), BAD_ALGORITHM(15), ALGORITHM("INDIRECT", 252), ALGORITHM("PRIVATEDNS", 253), ALGORITHM("PRIVATEOID", 254), }; static const struct { const algorithm_t *algorithm; uint8_t mask[24]; } algorithm_hash_map[16] = { { &algorithms[2], // DH (0) { 0xdf, 0xdf, 0 } }, { &algorithms[10], // RSASHA512 (1) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0 } }, { &algorithms[7], // RSASHA1-NSEC3-SHA1 (2) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0 } }, { &algorithms[8], // RSASHA256 (3) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0 } }, { &algorithms[13], // ECDSAP256SHA256 (4) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0 } }, { &algorithms[0], // unknown { 0 } }, { &algorithms[6], // DSA-NSEC-SHA1 (6) { 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0 } }, { &algorithms[1], // RSAMD5 (7) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0 } }, { &algorithms[5], // RSASHA1 (8) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0 } }, { &algorithms[17], // PRIVATEDNS (9) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0 } }, { &algorithms[18], // PRIVATEOID (10) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0 } }, { &algorithms[16], // INDIRECT (11) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0 } }, { &algorithms[14], // ECDSAP384SHA384 (12) { 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xff, 0xff, 0 } }, { &algorithms[3], // DSA (13) { 0xdf, 0xdf, 0xdf, 0 } }, { &algorithms[4], // ECC (14) { 0xdf, 0xdf, 0xdf, 0 } }, { &algorithms[12], // ECC-GHOST (15) { 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xdf, 0 } } }; #undef UNKNOWN_ALGORITHM #undef ALGORITHM // magic value generated using algorithm-hash.c static uint8_t algorithm_hash(uint64_t value) { value = le64toh(value); uint32_t value32 = (uint32_t)((value >> 32) ^ value); return (uint8_t)((value32 * 29874llu) >> 32) & 0xf; } nonnull_all warn_unused_result static really_inline int32_t scan_algorithm( const char *data, size_t length, uint8_t *number) { static const int8_t zero_masks[48] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if ((uint8_t)*data - '0' > 9) { uint64_t input; memcpy(&input, data, 8); const uint64_t letter_mask = 0x4040404040404040llu; // convert to upper case input &= ~((input & letter_mask) >> 1); // zero out non-relevant bytes uint64_t zero_mask; memcpy(&zero_mask, &zero_masks[32 - (length & 0x1f)], 8); input &= zero_mask; const uint8_t index = algorithm_hash(input); assert(index < 16); const algorithm_t *algorithm = algorithm_hash_map[index].algorithm; uint64_t matches, mask, name; // compare bytes 0-7 memcpy(&name, algorithm->key.name, 8); matches = input == name; // compare bytes 8-15 memcpy(&input, data + 8, 8); memcpy(&mask, algorithm_hash_map[index].mask + 8, 8); memcpy(&name, algorithm->key.name + 8, 8); matches &= (input & mask) == name; // compare bytes 16-23 memcpy(&input, data + 16, 8); memcpy(&mask, algorithm_hash_map[index].mask + 16, 8); memcpy(&name, algorithm->key.name + 16, 8); matches &= (input & mask) == name; *number = algorithm->value; return matches & (length == algorithm->key.length) & (*number > 0); } return scan_int8(data, length, number); } nonnull_all warn_unused_result static really_inline int32_t parse_algorithm( parser_t *parser, const type_info_t *type, const rdata_info_t *field, rdata_t *rdata, const token_t *token) { if (!scan_algorithm(token->data, token->length, rdata->octets)) SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); rdata->octets++; return 0; } #endif // ALGORITHM_H nsd-4.12.0/simdzone/src/fallback/0000755000175000017500000000000015002373055016154 5ustar mozziemozziensd-4.12.0/simdzone/src/fallback/text.h0000644000175000017500000000325315002373055017314 0ustar mozziemozzie/* * text.h -- fallback string parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef TEXT_H #define TEXT_H nonnull_all static really_inline uint32_t unescape(const char *text, uint8_t *wire) { uint8_t d[3]; if ((d[0] = (uint8_t)text[1] - '0') > 9) { *wire = (uint8_t)text[1]; return 2u; } else { d[1] = (uint8_t)text[2] - '0'; d[2] = (uint8_t)text[3] - '0'; uint32_t o = d[0] * 100 + d[1] * 10 + d[2]; *wire = (uint8_t)o; return (o > 255 || d[1] > 9 || d[2] > 9) ? 0 : 4u; } } nonnull_all static really_inline int32_t scan_string( const char *data, size_t length, uint8_t *octets, const uint8_t *limit) { const char *text = data, *text_limit = data + length; uint8_t *wire = octets; if (likely((uintptr_t)limit - (uintptr_t)wire >= length)) { while (text < text_limit) { *wire = (uint8_t)*text; if (likely(*text != '\\')) { text += 1; wire += 1; } else { const uint32_t octet = unescape(text, wire); if (!octet) return -1; text += octet; wire += 1; } } if (text != text_limit) return -1; return (int32_t)(wire - octets); } else { while (text < text_limit && wire < limit) { *wire = (uint8_t)*text; if (likely(*text != '\\')) { text += 1; wire += 1; } else { const uint32_t octet = unescape(text, wire); if (!octet) return -1; text += octet; wire += 1; } } if (text != text_limit || wire > limit) return -1; return (int32_t)(wire - octets); } } #endif // TEXT_H nsd-4.12.0/simdzone/src/fallback/scanner.h0000644000175000017500000001173715002373055017767 0ustar mozziemozzie/* * scanner.h -- fallback (non-simd) lexical analyzer for (DNS) zone data * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef SCANNER_H #define SCANNER_H #include #include #include nonnull_all static really_inline const char *scan_comment( parser_t *parser, const char *start, const char *end) { assert(!parser->file->state.is_escaped); while (start < end) { if (unlikely(*start == '\n')) { parser->file->state.in_comment = 0; return start; } start++; } parser->file->state.in_comment = 1; return start; } nonnull_all static really_inline const char *scan_quoted( parser_t *parser, const char *start, const char *end) { if (unlikely(parser->file->state.is_escaped && start < end)) goto escaped; while (start < end) { if (*start == '\\') { start++; escaped: if ((parser->file->state.is_escaped = (start == end))) break; assert(start < end); *parser->file->newlines.tail += (*start == '\n'); start++; } else if (*start == '\"') { parser->file->state.in_quoted = 0; *parser->file->delimiters.tail++ = start; return ++start; } else { *parser->file->newlines.tail += (*start == '\n'); start++; } } parser->file->state.in_quoted = 1; return start; } nonnull_all static really_inline const char *scan_contiguous( parser_t *parser, const char *start, const char *end) { if (parser->file->state.is_escaped && start < end) goto escaped; while (start < end) { // null-byte is considered contiguous by the indexer (for now) if (likely((classify[ (uint8_t)*start ] & ~CONTIGUOUS) == 0)) { if (unlikely(*start == '\\')) { start++; escaped: if ((parser->file->state.is_escaped = (start == end))) break; assert(start < end); parser->file->newlines.tail[0] += (*start == '\n'); } start++; } else { parser->file->state.follows_contiguous = 0; *parser->file->delimiters.tail++ = start; return start; } } parser->file->state.follows_contiguous = 1; return start; } nonnull_all static really_inline void scan( parser_t *parser, const char *start, const char *end) { if (parser->file->state.follows_contiguous) start = scan_contiguous(parser, start, end); else if (parser->file->state.in_comment) start = scan_comment(parser, start, end); else if (parser->file->state.in_quoted) start = scan_quoted(parser, start, end); while (start < end) { const int32_t code = classify[(uint8_t)*start]; if (code == BLANK) { start++; } else if ((code & ~CONTIGUOUS) == 0) { // null-byte is considered contiguous by the indexer (for now) *parser->file->fields.tail++ = start; start = scan_contiguous(parser, start, end); } else if (code == LINE_FEED) { if (*parser->file->newlines.tail) { *parser->file->fields.tail++ = line_feed; parser->file->newlines.tail++; } else { *parser->file->fields.tail++ = start; } start++; } else if (code == QUOTED) { *parser->file->fields.tail++ = start; start = scan_quoted(parser, start + 1, end); } else if (code == LEFT_PAREN || code == RIGHT_PAREN) { *parser->file->fields.tail++ = start; start++; } else { assert(code == COMMENT); start = scan_comment(parser, start, end); } } } nonnull_all warn_unused_result static really_inline int32_t reindex(parser_t *parser) { assert(parser->file->buffer.index <= parser->file->buffer.length); size_t left = parser->file->buffer.length - parser->file->buffer.index; const char *data = parser->file->buffer.data + parser->file->buffer.index; const char **tape = parser->file->fields.tail; const char **tape_limit = parser->file->fields.tape + ZONE_TAPE_SIZE; if (left >= ZONE_BLOCK_SIZE) { const char *data_limit = parser->file->buffer.data + (parser->file->buffer.length - ZONE_BLOCK_SIZE); while (data <= data_limit && ((uintptr_t)tape_limit - (uintptr_t)tape) >= ZONE_BLOCK_SIZE) { scan(parser, data, data + ZONE_BLOCK_SIZE); parser->file->buffer.index += ZONE_BLOCK_SIZE; data += ZONE_BLOCK_SIZE; tape = parser->file->fields.tail; } assert(parser->file->buffer.index <= parser->file->buffer.length); left = parser->file->buffer.length - parser->file->buffer.index; } // only scan partial blocks after reading all data if (parser->file->end_of_file) { assert(left < ZONE_BLOCK_SIZE); if (!left) { parser->file->end_of_file = NO_MORE_DATA; } else if (((uintptr_t)tape_limit - (uintptr_t)tape) >= left) { scan(parser, data, data + left); parser->file->end_of_file = NO_MORE_DATA; parser->file->buffer.index += left; parser->file->state.follows_contiguous = 0; } } return (parser->file->state.follows_contiguous | parser->file->state.in_quoted) != 0; } #endif // SCANNER_H nsd-4.12.0/simdzone/src/fallback/parser.c0000644000175000017500000000231315002373055017613 0ustar mozziemozzie/* * parser.c -- compilation target for fallback (DNS) zone parser * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "generic/endian.h" #include "fallback/bits.h" #include "generic/parser.h" #include "fallback/scanner.h" #include "generic/number.h" #include "generic/ttl.h" #include "generic/time.h" #include "fallback/text.h" #include "fallback/name.h" #include "generic/ip4.h" #include "generic/ip6.h" #include "generic/base16.h" #include "generic/base32.h" #include "generic/base64.h" #include "generic/nsec.h" #include "generic/nxt.h" #include "generic/caa.h" #include "generic/ilnp64.h" #include "generic/eui.h" #include "generic/nsap.h" #include "generic/wks.h" #include "generic/loc.h" #include "generic/gpos.h" #include "generic/apl.h" #include "generic/svcb.h" #include "generic/cert.h" #include "generic/atma.h" #include "generic/algorithm.h" #include "generic/types.h" #include "generic/type.h" #include "generic/format.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_fallback_parse(parser_t *parser) { return parse(parser); } diagnostic_pop() nsd-4.12.0/simdzone/src/fallback/name.h0000644000175000017500000000212615002373055017246 0ustar mozziemozzie/* * name.h -- domain name parser * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef NAME_H #define NAME_H nonnull_all static really_inline int32_t scan_name( const char *data, size_t length, uint8_t octets[255 + ZONE_BLOCK_SIZE], size_t *lengthp) { uint8_t *l = octets, *w = octets + 1; const uint8_t *we = octets + 255; const char *t = data, *te = t + length; l[0] = 0; if (*t == '.') return (*lengthp = length) == 1 ? 0 : -1; while ((t < te) & (w < we)) { *w = (uint8_t)*t; if (*t == '\\') { uint32_t n; if (!(n = unescape(t, w))) return -1; w += 1; t += n; } else if (*t == '.') { if ((w - 1) - l > 63 || (w - 1) - l == 0) return -1; l[0] = (uint8_t)((w - 1) - l); l = w; l[0] = 0; w += 1; t += 1; } else { w += 1; t += 1; } } if ((w - 1) - l > 63) return -1; *l = (uint8_t)((w - 1) - l); if (t != te || w > we) return -1; *lengthp = (size_t)(w - octets); return *l != 0; } #endif // NAME_H nsd-4.12.0/simdzone/src/fallback/bits.h0000644000175000017500000000412215002373055017265 0ustar mozziemozzie/* * bits.h -- bit manipulation instructions * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef BITS_H #define BITS_H #if _MSC_VER #include static really_inline uint64_t trailing_zeroes(uint64_t mask) { unsigned long index; if (_BitScanForward64(&index, mask)) return index; else return 64; } static really_inline uint64_t leading_zeroes(uint64_t mask) { unsigned long index; if (_BitScanReverse64(&index, mask)) return 63 - index; else return 64; } #else static really_inline uint64_t trailing_zeroes(uint64_t mask) { #if has_builtin(__builtin_ctzll) return (uint64_t)__builtin_ctzll(mask); #else // Code by Kim Walish from https://www.chessprogramming.org/BitScan. // Distributed under CC BY-SA 3.0. static const uint64_t magic = 0x03f79d71b4cb0a89ull; const int magictable[64] = { 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63 }; return magictable[((mask ^ (mask - 1)) * magic) >> 58]; #endif } static really_inline uint64_t leading_zeroes(uint64_t mask) { #if has_builtin(__builtin_clzll) return (uint64_t)__builtin_clzll(mask); #else // Code by Kim Walish from https://www.chessprogramming.org/BitScan. // Distributed under CC BY-SA 3.0. static const uint64_t magic = 0x03f79d71b4cb0a89ull; const int magictable[64] = { 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1, 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18, 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0 }; mask |= mask >> 1; mask |= mask >> 2; mask |= mask >> 4; mask |= mask >> 8; mask |= mask >> 16; mask |= mask >> 32; return magictable[(mask * magic) >> 58]; #endif } #endif // _MSC_VER #endif // BITS_H nsd-4.12.0/simdzone/src/fallback/bench.c0000644000175000017500000000116515002373055017402 0ustar mozziemozzie/* * bench.c -- benchmark function(s) for fallback (non-simd) implementation * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "zone.h" #include "attributes.h" #include "diagnostic.h" #include "generic/parser.h" #include "fallback/scanner.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) int32_t zone_bench_fallback_lex(parser_t *parser, size_t *tokens) { token_t token; (*tokens) = 0; take(parser, &token); while (token.code > 0) { (*tokens)++; take(parser, &token); } return token.code ? -1 : 0; } diagnostic_pop() nsd-4.12.0/simdzone/src/diagnostic.h0000644000175000017500000000314715002373055016717 0ustar mozziemozzie/* * diagnostic.h -- compiler diagnostic abstractions * * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef DIAGNOSTIC_H #define DIAGNOSTIC_H #if _MSC_VER # define diagnostic_push() \ __pragma(warning(push)) # define msvc_diagnostic_ignored(warning_specifier) \ __pragma(warning(disable:warning_specifier)) # define diagnostic_pop() \ __pragma(warning(pop)) // Support for selectively enabling and disabling warnings via // #pragma GCC diagnostic was added in GCC 4.6 // (https://gcc.gnu.org/gcc-4.6/changes.html). #elif (defined __clang__) \ || (defined __GNUC__ && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 406)) # define stringify(x) #x # define paste(flag, warning) stringify(flag ## warning) # define pragma(x) _Pragma(#x) # define diagnostic_ignored(warning) pragma(warning) # define diagnostic_push() _Pragma("GCC diagnostic push") # define diagnostic_pop() _Pragma("GCC diagnostic pop") # if __clang__ # define clang_diagnostic_ignored(warning) \ diagnostic_ignored(GCC diagnostic ignored paste(-W,warning)) # else # define gcc_diagnostic_ignored(warning) \ diagnostic_ignored(GCC diagnostic ignored paste(-W,warning)) # endif #endif #if !defined diagnostic_push # define diagnostic_push() # define diagnostic_pop() #endif #if !defined gcc_diagnostic_ignored # define gcc_diagnostic_ignored(warning) #endif #if !defined clang_diagnostic_ignored # define clang_diagnostic_ignored(warning) #endif #if !defined msvc_diagnostic_ignored # define msvc_diagnostic_ignored(warning) #endif #endif // DIAGNOSTIC_H nsd-4.12.0/simdzone/src/config.h.in0000644000175000017500000000201115002373055016432 0ustar mozziemozzie/* * config.h.in -- configuration header template * * Copyright (c) 2024, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef CONFIG_H #define CONFIG_H /* Define to 1 if you have the declaration of `bswap16', and to 0 if you don't. */ #cmakedefine01 HAVE_DECL_BSWAP16 /* Define to 1 if you have the declaration of `bswap32', and to 0 if you don't. */ #cmakedefine01 HAVE_DECL_BSWAP32 /* Define to 1 if you have the declaration of `bswap64', and to 0 if you don't. */ #cmakedefine01 HAVE_DECL_BSWAP64 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ENDIAN_H 1 /* Define to 1 if you have the `getopt' function. */ #cmakedefine HAVE_GETOPT 1 /* Wether or not to compile support for AVX2 */ #cmakedefine HAVE_HASWELL 1 /* Wether or not to compile support for SSE4.2 */ #cmakedefine HAVE_WESTMERE 1 /* Defines _XOPEN_SOURCE and _POSIX_C_SOURCE implicitly in features.h */ #ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 #endif #endif // CONFIG_H nsd-4.12.0/simdzone/src/bench.c0000644000175000017500000001266015002373055015645 0ustar mozziemozzie/* * bench.c -- simple scanner/parser benchmarking tool * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include #include #include #if !defined(HAVE_GETOPT) # include "getopt.h" #else # include #endif #include "zone.h" #include "config.h" #include "isadetection.h" #include "attributes.h" #include "diagnostic.h" #if _MSC_VER #define strcasecmp(s1, s2) _stricmp(s1, s2) #define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) #else #include #endif typedef zone_parser_t parser_t; #if HAVE_HASWELL extern int32_t zone_bench_haswell_lex(zone_parser_t *, size_t *); extern int32_t zone_haswell_parse(zone_parser_t *); #endif #if HAVE_WESTMERE extern int32_t zone_bench_westmere_lex(zone_parser_t *, size_t *); extern int32_t zone_westmere_parse(zone_parser_t *); #endif extern int32_t zone_bench_fallback_lex(zone_parser_t *, size_t *); extern int32_t zone_fallback_parse(zone_parser_t *); typedef struct kernel kernel_t; struct kernel { const char *name; uint32_t instruction_set; int32_t (*bench_lex)(zone_parser_t *, size_t *); int32_t (*parse)(zone_parser_t *); }; static const kernel_t kernels[] = { #if HAVE_HASWELL { "haswell", AVX2, &zone_bench_haswell_lex, &zone_haswell_parse }, #endif #if HAVE_WESTMERE { "westmere", SSE42|PCLMULQDQ, &zone_bench_westmere_lex, &zone_westmere_parse }, #endif { "fallback", DEFAULT, &zone_bench_fallback_lex, &zone_fallback_parse } }; extern int32_t zone_open( zone_parser_t *, const zone_options_t *, zone_buffers_t *, const char *, void *user_data); extern void zone_close( zone_parser_t *); static int32_t bench_lex(zone_parser_t *parser, const kernel_t *kernel) { size_t tokens = 0; int32_t result; if ((result = kernel->bench_lex(parser, &tokens)) < 0) return result; printf("Lexed %zu tokens\n", tokens); return 0; } static int32_t bench_accept( parser_t *parser, const zone_name_t *owner, uint16_t type, uint16_t class, uint32_t ttl, uint16_t rdlength, const uint8_t *rdata, void *user_data) { (void)parser; (void)owner; (void)type; (void)class; (void)ttl; (void)rdlength; (void)rdata; (*(size_t *)user_data)++; return ZONE_SUCCESS; } static int32_t bench_parse(zone_parser_t *parser, const kernel_t *kernel) { size_t records = 0; int32_t result; parser->user_data = &records; result = kernel->parse(parser); printf("Parsed %zu records\n", records); return result; } diagnostic_push() msvc_diagnostic_ignored(4996) static const kernel_t *select_kernel(const char *name) { const size_t n = sizeof(kernels)/sizeof(kernels[0]); const uint32_t supported = detect_supported_architectures(); const kernel_t *kernel = NULL; if ((!name || !*name) && !(name = getenv("ZONE_KERNEL"))) { for (size_t i=0; !kernel && i < n; i++) { if ((kernels[i].instruction_set & supported) == kernels[i].instruction_set) kernel = &kernels[i]; } assert(kernel != NULL); } else { for (size_t i=0; !kernel && i < n; i++) { if (strcasecmp(name, kernels[i].name) == 0) kernel = &kernels[i]; } if (!kernel || (kernel->instruction_set && !(kernel->instruction_set & supported))) { fprintf(stderr, "Target %s is unavailable\n", name); return NULL; } } printf("Selected target %s\n", kernel->name); return kernel; } diagnostic_pop() static void help(const char *program) { const char *format = "Usage: %s [OPTION] \n" "\n" "Options:\n" " -h Display available options.\n" " -t target Select target (default:%s)\n" "\n" "Kernels:\n"; printf(format, program, kernels[0].name); for (size_t i=0, n=sizeof(kernels)/sizeof(kernels[0]); i < n; i++) printf(" %s\n", kernels[i].name); } static void usage(const char *program) { fprintf(stderr, "Usage: %s [OPTION] \n", program); exit(EXIT_FAILURE); } static uint8_t root[] = { 0 }; int main(int argc, char *argv[]) { const char *name = NULL, *program = argv[0]; for (const char *slash = argv[0]; *slash; slash++) if (*slash == '/' || *slash == '\\') program = slash + 1; for (int option; (option = getopt(argc, argv, "ht:")) != -1;) { switch (option) { case 'h': help(program); exit(EXIT_SUCCESS); case 't': name = optarg; break; default: usage(program); } } if (optind > argc || argc - optind < 2) usage(program); int32_t (*bench)(zone_parser_t *, const kernel_t *) = 0; if (strcasecmp(argv[optind], "lex") == 0) bench = &bench_lex; else if (strcasecmp(argv[optind], "parse") == 0) bench = &bench_parse; else usage(program); const kernel_t *kernel; if (!(kernel = select_kernel(name))) exit(EXIT_FAILURE); zone_parser_t parser; memset(&parser, 0, sizeof(parser)); zone_options_t options; memset(&options, 0, sizeof(options)); options.pretty_ttls = true; options.origin.octets = root; options.origin.length = 1; options.accept.callback = &bench_accept; options.default_ttl = 3600; options.default_class = 1; zone_name_buffer_t owner; zone_rdata_buffer_t rdata; zone_buffers_t buffers = { 1, &owner, &rdata }; if (zone_open(&parser, &options, &buffers, argv[argc-1], NULL) < 0) exit(EXIT_FAILURE); if (bench(&parser, kernel) < 0) exit(EXIT_FAILURE); zone_close(&parser); return EXIT_SUCCESS; } nsd-4.12.0/simdzone/src/attributes.h0000644000175000017500000000426215002373055016760 0ustar mozziemozzie/* * attributes.h -- internal compiler attribute abstractions * * Copyright (c) 2023-2024, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "zone/attributes.h" #ifndef ATTRIBUTES_H #define ATTRIBUTES_H #define nonnull(params) zone_nonnull(params) #define nonnull_all zone_nonnull_all #if _MSC_VER # define really_inline __forceinline # define never_inline __declspec(noinline) # define warn_unused_result # define no_sanitize_undefined # define likely(params) (params) # define unlikely(params) (params) #else // _MSC_VER #if defined __has_builtin # define has_builtin(params) __has_builtin(params) #else # define has_builtin(params) (0) #endif # if (zone_has_attribute(always_inline) || zone_has_gnuc(3, 1)) && ! defined __NO_INLINE__ // Compilation using GCC 4.2.1 without optimizations fails. // sorry, unimplemented: inlining failed in call to ... // GCC 4.1.2 and GCC 4.30 compile forward declared functions annotated // with __attribute__((always_inline)) without problems. Test if // __NO_INLINE__ is defined and define macro accordingly. # define really_inline inline __attribute__((always_inline)) # else # define really_inline inline # endif # if zone_has_attribute(noinline) || zone_has_gnuc(2, 96) # define never_inline __attribute__((noinline)) # else # define never_inline # endif # if zone_has_attribute(warn_unused_result) # define warn_unused_result __attribute__((warn_unused_result)) # else # define warn_unused_result # endif # if zone_has_attribute(no_sanitize) // GCC 8.1 added the no_sanitize function attribute. # define no_sanitize_undefined __attribute__((no_sanitize("undefined"))) # elif zone_has_attribute(no_sanitize_undefined) // GCC 4.9.0 added the UndefinedBehaviorSanitizer (ubsan) and the // no_sanitize_undefined function attribute. # define no_sanitize_undefined # else # define no_sanitize_undefined # endif # if has_builtin(__builtin_expect) # define likely(params) __builtin_expect(!!(params), 1) # define unlikely(params) __builtin_expect(!!(params), 0) # else # define likely(params) (params) # define unlikely(params) (params) # endif #endif #endif // ATTRIBUTES_H nsd-4.12.0/simdzone/m4/0000755000175000017500000000000015002373055014146 5ustar mozziemozziensd-4.12.0/simdzone/m4/ax_check_compile_flag.m40000644000175000017500000000407015002373055020657 0ustar mozziemozzie# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS nsd-4.12.0/simdzone/include/0000755000175000017500000000000015002373055015251 5ustar mozziemozziensd-4.12.0/simdzone/include/zone/0000755000175000017500000000000015002373055016224 5ustar mozziemozziensd-4.12.0/simdzone/include/zone/attributes.h0000644000175000017500000000271615002373055020571 0ustar mozziemozzie/* * attributes.h -- compiler attribute abstractions * * Copyright (c) 2022, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ZONE_ATTRIBUTES_H #define ZONE_ATTRIBUTES_H #if defined __GNUC__ # define zone_has_gnuc(major, minor) \ ((__GNUC__ > major) || (__GNUC__ == major && __GNUC_MINOR__ >= minor)) #else # define zone_has_gnuc(major, minor) (0) #endif #if defined __has_attribute # define zone_has_attribute(params) __has_attribute(params) #else # define zone_has_attribute(params) (0) #endif #if zone_has_attribute(nonnull) # define zone_nonnull(params) __attribute__((__nonnull__ params)) # define zone_nonnull_all __attribute__((__nonnull__)) #else # define zone_nonnull(params) # define zone_nonnull_all #endif #if zone_has_attribute(format) || zone_has_gnuc(2, 4) # define zone_format(params) __attribute__((__format__ params)) # if __MINGW32__ # if __MINGW_PRINTF_FORMAT # define zone_format_printf(string_index, first_to_check) \ zone_format((__MINGW_PRINTF_FORMAT, string_index, first_to_check)) # else # define zone_format_printf(string_index, first_to_check) \ zone_format((gnu_printf, string_index, first_to_check)) # endif # else # define zone_format_printf(string_index, first_to_check) \ zone_format((printf, string_index, first_to_check)) # endif #else # define zone_format(params) # define zone_format_printf(string_index, first_to_check) #endif #endif // ZONE_ATTRIBUTES_H nsd-4.12.0/simdzone/include/zone.h0000644000175000017500000004773615002373055016416 0ustar mozziemozzie/* * zone.h -- (DNS) presentation format parser * * Copyright (c) 2022-2024, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef ZONE_H #define ZONE_H /** * @file * @brief simdzone main header */ #include #include #include #include #include #include "zone/attributes.h" #include "zone/export.h" #if defined (__cplusplus) extern "C" { #endif /** * @defgroup class_codes Class codes * * Supported CLASSes. * * See @iana{DNS CLASSes,dns-parameters,dns-parameters-2} for a list of * classes registered by IANA. * * @{ */ /** Internet @rfc{1035} */ #define ZONE_CLASS_IN (1u) /** CSNET @rfc{1035} @obsolete */ #define ZONE_CLASS_CS (2u) /** CHAOS @rfc{1035} */ #define ZONE_CLASS_CH (3u) /** Hesiod @rfc{1035} */ #define ZONE_CLASS_HS (4u) /** Any (QCLASS) @rfc{1035} */ #define ZONE_CLASS_ANY (255u) /** @} */ /** * @defgroup type_codes Type codes * * Supported resource record (RR) TYPEs. * * See @iana{RR TYPEs,dns-parameters,dns-parameters-4} for a list of * types registered by IANA. * * @{ */ /** Host address @rfc{1035} */ #define ZONE_TYPE_A (1u) /** Authoritative name server @rfc{1035} */ #define ZONE_TYPE_NS (2u) /** Mail destination @rfc{1035} @obsolete */ #define ZONE_TYPE_MD (3u) /** Mail forwarder @rfc{1035} @obsolete */ #define ZONE_TYPE_MF (4u) /** Canonical name for an alias @rfc{1035} */ #define ZONE_TYPE_CNAME (5u) /** Marks the start of authority @rfc{1035} */ #define ZONE_TYPE_SOA (6u) /** Mailbox domain name @rfc{1035} @experimental */ #define ZONE_TYPE_MB (7u) /** Mail group member @rfc{1035} @experimental */ #define ZONE_TYPE_MG (8u) /** Mail rename domain name @rfc{1035} @experimental */ #define ZONE_TYPE_MR (9u) /** Anything @rfc{883} @obsolete */ #define ZONE_TYPE_NULL (10u) /** Well known service description @rfc{1035} */ #define ZONE_TYPE_WKS (11u) /** Domain name pointer @rfc{1035} */ #define ZONE_TYPE_PTR (12u) /** Host information @rfc{1035} */ #define ZONE_TYPE_HINFO (13u) /** Mailbox or mail list information @rfc{1035} */ #define ZONE_TYPE_MINFO (14u) /** Mail exchange @rfc{1035} */ #define ZONE_TYPE_MX (15u) /** Text strings @rfc{1035} */ #define ZONE_TYPE_TXT (16u) /** Responsible person @rfc{1035} */ #define ZONE_TYPE_RP (17u) /** AFS Data Base location @rfc{1183} @rfc{5864} */ #define ZONE_TYPE_AFSDB (18u) /** X.25 PSDN address @rfc{1183} */ #define ZONE_TYPE_X25 (19u) /** ISDN address @rfc{1183} */ #define ZONE_TYPE_ISDN (20u) /** Route Through @rfc{1183} */ #define ZONE_TYPE_RT (21u) /** NSAP address, NSAP style A record @rfc{1706} */ #define ZONE_TYPE_NSAP (22u) /** Domain name pointer, NSAP style @rfc{1348} @rfc{1637} */ #define ZONE_TYPE_NSAP_PTR (23u) /** Signature @rfc{2535} */ #define ZONE_TYPE_SIG (24u) /** Public key @rfc{2535} @rfc{2930} */ #define ZONE_TYPE_KEY (25u) /** X.400 mail mapping information @rfc{2163} */ #define ZONE_TYPE_PX (26u) /** Geographical Position @rfc{1712} */ #define ZONE_TYPE_GPOS (27u) /** IPv6 Address @rfc{3596} */ #define ZONE_TYPE_AAAA (28u) /** Location Information @rfc{1876} */ #define ZONE_TYPE_LOC (29u) /** Next domain @rfc{3755} @rfc{2535} @obsolete */ #define ZONE_TYPE_NXT (30u) /** Endpoint Identifier */ #define ZONE_TYPE_EID (31u) /** Nimrod Locator */ #define ZONE_TYPE_NIMLOC (32u) /** Server Selection @rfc{2782} */ #define ZONE_TYPE_SRV (33u) /** ATM Address */ #define ZONE_TYPE_ATMA (34u) /** Naming Authority Pointer @rfc{2915} @rfc{2168} @rfc{3403} */ #define ZONE_TYPE_NAPTR (35u) /** Key Exchanger @rfc{2230} */ #define ZONE_TYPE_KX (36u) /** CERT @rfc{4398}*/ #define ZONE_TYPE_CERT (37u) /** IPv6 Address @rfc{3226} @rfc{2874} @rfc{6563} @obsolete */ #define ZONE_TYPE_A6 (38u) /** DNAME @rfc{6672} */ #define ZONE_TYPE_DNAME (39u) /** SINK @draft{eastlake, kitchen-sink} */ #define ZONE_TYPE_SINK (40u) /** Address Prefix List @rfc{3123} */ #define ZONE_TYPE_APL (42u) /** Delegation Signer @rfc{4034} @rfc{3658} */ #define ZONE_TYPE_DS (43u) /** SSH Key Fingerprint @rfc{4255} */ #define ZONE_TYPE_SSHFP (44u) /** IPsec public key @rfc{4025} */ #define ZONE_TYPE_IPSECKEY (45u) /** Resource Record Signature @rfc{4034} @rfc{3755} */ #define ZONE_TYPE_RRSIG (46u) /** Next Secure @rfc{4034} @rfc{3755} */ #define ZONE_TYPE_NSEC (47u) /** DNS Public Key @rfc{4034} @rfc{3755} */ #define ZONE_TYPE_DNSKEY (48u) /** DHCID @rfc{4701} */ #define ZONE_TYPE_DHCID (49u) /** NSEC3 @rfc{5155} */ #define ZONE_TYPE_NSEC3 (50u) /** NSEC3PARAM @rfc{5155} */ #define ZONE_TYPE_NSEC3PARAM (51u) /** TLSA @rfc{6698} */ #define ZONE_TYPE_TLSA (52u) /** S/MIME cert association @rfc{8162} */ #define ZONE_TYPE_SMIMEA (53u) /** Host Identity Protocol @rfc{8005} */ #define ZONE_TYPE_HIP (55u) /** NINFO */ #define ZONE_TYPE_NINFO (56u) /** RKEY */ #define ZONE_TYPE_RKEY (57u) /** Trust Anchor LINK @draft{ietf, dnsop-dnssec-trust-history} */ #define ZONE_TYPE_TALINK (58u) /** Child DS @rfc{7344} */ #define ZONE_TYPE_CDS (59u) /** DNSKEY(s) the Child wants reflected in DS @rfc{7344} */ #define ZONE_TYPE_CDNSKEY (60u) /** OpenPGP Key @rfc{7929} */ #define ZONE_TYPE_OPENPGPKEY (61u) /** Child-To-Parent Synchronization @rfc{7477} */ #define ZONE_TYPE_CSYNC (62u) /** Zone message digest @rfc{8976} */ #define ZONE_TYPE_ZONEMD (63u) /** Service binding @rfc{9460} */ #define ZONE_TYPE_SVCB (64u) /** Service binding @rfc{9460} */ #define ZONE_TYPE_HTTPS (65u) /** Endpoint discovery for delegation synchronization @draft{ietf, dnsop-generalized-notify} */ #define ZONE_TYPE_DSYNC (66u) /** Sender Policy Framework @rfc{7208} */ #define ZONE_TYPE_SPF (99u) /** Node Identifier @rfc{6742} */ #define ZONE_TYPE_NID (104u) /** 32-bit Locator for ILNPv4-capable nodes @rfc{6742} */ #define ZONE_TYPE_L32 (105u) /** 64-bit Locator for ILNPv6-capable nodes @rfc{6742} */ #define ZONE_TYPE_L64 (106u) /** Name of an ILNP subnetwork @rfc{6742} */ #define ZONE_TYPE_LP (107u) /** EUI-48 address @rfc{7043} */ #define ZONE_TYPE_EUI48 (108u) /** EUI-64 address @rfc{7043} */ #define ZONE_TYPE_EUI64 (109u) /** Uniform Resource Identifier @rfc{7553} */ #define ZONE_TYPE_URI (256u) /** Certification Authority Restriction @rfc{6844} */ #define ZONE_TYPE_CAA (257u) /** DNS Authoritative Source (DNS-AS) */ #define ZONE_TYPE_AVC (258u) /** Digital Object Architecture @draft{durand, doa-over-dns} */ #define ZONE_TYPE_DOA (259u) /** Automatic Multicast Tunneling Relay @rfc{8777} */ #define ZONE_TYPE_AMTRELAY (260u) /** Resolver Information as Key/Value Pairs @rfc{9606} */ #define ZONE_TYPE_RESINFO (261u) /** Public wallet address */ #define ZONE_TYPE_WALLET (262u) /** BP Convergence Layer Adapter */ #define ZONE_TYPE_CLA (263u) /** BP Node Number */ #define ZONE_TYPE_IPN (264u) /** DNSSEC Trust Authorities */ #define ZONE_TYPE_TA (32768u) /** DNSSEC Lookaside Validation @rfc{4431} @obsolete */ #define ZONE_TYPE_DLV (32769u) /** @} */ /** * @defgroup svc_params Service Parameter Keys * * Supported service parameters. * * See @iana{Service Parameter Keys (SvcParamKeys),dns-svcb,dns-svcparamkeys} * for a list of service parameter keys registered by IANA. * * @{ */ /** Parameters clients must not ignore @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_MANDATORY (0u) /** Application Layer Protocol Negotiation (ALPN) protocol identifiers @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_ALPN (1u) /** No support for default protocol (alpn must be specified) @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_NO_DEFAULT_ALPN (2u) /** TCP or UDP port for alternative endpoint @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_PORT (3u) /** IPv4 address hints @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_IPV4HINT (4u) /** Encrypted ClientHello (ECH) configuration @draft{ietf, tls-svcb-ech} */ #define ZONE_SVC_PARAM_KEY_ECH (5u) /** IPv6 address hints @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_IPV6HINT (6u) /** URI template in relative form @rfc{9461} */ #define ZONE_SVC_PARAM_KEY_DOHPATH (7u) /** Target is an Oblivious HTTP service @rfc{9540} */ #define ZONE_SVC_PARAM_KEY_OHTTP (8u) /** Supported groups in TLS @draft{ietf, tls-key-share-prediction} */ #define ZONE_SVC_PARAM_KEY_TLS_SUPPORTED_GROUPS (9u) /** Reserved ("invalid key") @rfc{9460} */ #define ZONE_SVC_PARAM_KEY_INVALID_KEY (65535u) /** @} */ /** * Number of bytes per block. * * Higher throughput is achieved by block-based operation. The size of a * block is determined by the word size of the CPU. To avoid pipeline flushes * as much as possible buffers are required to be padded by the number of * bytes in a single block. * * @warning The input buffer to @zone_parse_string is required to be * null-terminated and padded, which is somewhat counter intuitive. A * future release may lift this requirement (@issue{174}). */ #define ZONE_BLOCK_SIZE (64) /** * Number of blocks per window. * * Master files can become quite large and are read in multiples of blocks. * The input buffer is expanded as needed. */ #define ZONE_WINDOW_SIZE (256 * ZONE_BLOCK_SIZE) // 16KB /** Maximum size of domain name. */ #define ZONE_NAME_SIZE (255) typedef struct zone_name_buffer zone_name_buffer_t; struct zone_name_buffer { /** Length of domain name stored in buffer. */ size_t length; /** Maximum number of octets in a domain name plus padding. */ uint8_t octets[ ZONE_NAME_SIZE + ZONE_BLOCK_SIZE ]; }; /** Maximum size of RDATA section. */ #define ZONE_RDATA_SIZE (65535) typedef struct zone_rdata_buffer zone_rdata_buffer_t; struct zone_rdata_buffer { /** Maximum number of octets in RDATA section plus padding. */ uint8_t octets[ ZONE_RDATA_SIZE + ZONE_BLOCK_SIZE ]; }; /** * @brief Tape capacity per-file. * * Tape capacity must be sufficiently large to hold every token from a single * worst-case read (e.g. 64 consecutive line feeds). Not likely to occur in * practice, therefore, to optimize throughput, allocate at least twice the * size so consecutive index operations can be performed. */ #define ZONE_TAPE_SIZE ((100 * ZONE_BLOCK_SIZE) + ZONE_BLOCK_SIZE) typedef struct zone_file zone_file_t; struct zone_file { /** @private */ zone_file_t *includer; /** @private */ zone_name_buffer_t origin, owner; /** @private */ uint16_t last_type; /** Last stated TTL. */ uint32_t last_ttl; /** Last parsed TTL in $TTL entry. */ uint32_t dollar_ttl; /** TTL passed to accept callback. */ uint32_t *ttl; /** Default TTL passed to accept. */ /** Last stated TTL is used as default unless $TTL entry was found. */ uint32_t *default_ttl; /** @private */ uint16_t last_class; /** Number of lines spanned by RR. */ /** Non-terminating line feeds, i.e. escaped line feeds, line feeds in quoted sections or within parentheses, are counted, but deferred for consistency in error reports */ size_t span; /** Starting line of RR. */ size_t line; /** Filename in control directive. */ char *name; /** Absolute path. */ char *path; /** @private */ FILE *handle; /** @private */ bool grouped; /** @private */ bool start_of_line; /** @private */ uint8_t end_of_file; /** @private */ struct { size_t index, length, size; char *data; } buffer; /** @private */ /** scanner state is kept per-file */ struct { uint64_t in_comment; uint64_t in_quoted; uint64_t is_escaped; uint64_t follows_contiguous; } state; /** @private */ /** vector of tokens generated by the scanner guaranteed to be large enough to hold every token for a single read + terminators */ struct { const char **head, **tail, *tape[ZONE_TAPE_SIZE + 2]; } fields; struct { const char **head, **tail, *tape[ZONE_TAPE_SIZE + 1]; } delimiters; struct { uint16_t *head, *tail, tape[ZONE_TAPE_SIZE + 1]; } newlines; }; typedef struct zone_parser zone_parser_t; struct zone_parser; /** * @brief Signature of callback function that is invoked for log messages. * * By default messages are printed to stdout (info) and stderr (warnings, * errors). A custom log handler (callback) may be provided for better * integration of reporting. * * @note file maybe NULL if initial file does not exist. */ typedef void(*zone_log_t)( zone_parser_t *, uint32_t, // priority const char *, // file size_t, // line const char *, // message void *); // user data /** * @brief Domain name and corresponding length in wire format. */ typedef struct zone_name zone_name_t; struct zone_name { /** Length of domain name. */ uint8_t length; /** Absolute, uncompressed, domain name in wire format. */ const uint8_t *octets; }; /** * @brief Signature of callback function invoked for each RR. * * Header is in host order, RDATA section is in network order. */ typedef int32_t(*zone_accept_t)( zone_parser_t *, const zone_name_t *, // owner (length + octets) uint16_t, // type uint16_t, // class uint32_t, // ttl uint16_t, // rdlength const uint8_t *, // rdata void *); // user data /** * @brief Signature of callback function invoked on $INCLUDE. * * Signal file name in $INCLUDE directive to application. Useful for * dependency tracking, etc. */ typedef int32_t(*zone_include_t)( zone_parser_t *, const char *, // name in $INCLUDE entry const char *, // fully qualified path void *); // user data /** * @brief Available configuration options. */ typedef struct { /** Non-strict mode of operation. */ /** Authoritative servers may choose to be more lenient when operating as a secondary as data may have been transferred over AXFR/IXFR that would have triggered an error otherwise. */ bool secondary; /** Disable $INCLUDE directive. */ /** Useful in setups where untrusted input may be offered. */ bool no_includes; /** Maximum $INCLUDE depth. 0 for default. */ uint32_t include_limit; /** Enable 1h2m3s notations for TTLS. */ bool pretty_ttls; /** Origin in wire format. */ zone_name_t origin; /** Default TTL to use. */ uint32_t default_ttl; /** Default CLASS to use. */ uint16_t default_class; struct { /** Priorities NOT to write out. */ uint32_t mask; /** Callback invoked to write out log messages. */ zone_log_t callback; } log; struct { /** Callback invoked for each RR. */ zone_accept_t callback; } accept; struct { /** Callback invoked for each $INCLUDE entry. */ zone_include_t callback; } include; } zone_options_t; /** * @brief Scratch buffer space reserved for parser. * * @note Future versions may leverage multiple buffers to improve throughput * as parsing and committing resource records are disjunct operations. */ typedef struct zone_buffers zone_buffers_t; struct zone_buffers { /** Number of name and rdata buffers available. */ size_t size; /** Vector of name buffers to use as scratch buffer. */ zone_name_buffer_t *owner; /** Vector of rdata buffers to use as scratch buffer. */ zone_rdata_buffer_t *rdata; }; /** * @brief Parser state. * @warning Do not modify directly. */ struct zone_parser { /** @private */ zone_options_t options; /** @private */ void *user_data; struct { size_t size; struct { size_t active; zone_name_buffer_t *blocks; } owner; struct { size_t active; zone_rdata_buffer_t *blocks; } rdata; } buffers; /** @private */ zone_name_buffer_t *owner; /** @private */ zone_rdata_buffer_t *rdata; /** @private */ zone_file_t *file, first; }; /** * @defgroup return_codes Return codes * * @{ */ /** Success. */ #define ZONE_SUCCESS (0) /** A syntax error occurred. */ #define ZONE_SYNTAX_ERROR (-256) // (-1 << 8) /** A semantic error occurred. */ #define ZONE_SEMANTIC_ERROR (-512) // (-2 << 8) /** Operation failed due to lack of memory. */ #define ZONE_OUT_OF_MEMORY (-768) // (-3 << 8) /** Bad parameter value. */ #define ZONE_BAD_PARAMETER (-1024) // (-4 << 8) /** Error reading zone file. */ #define ZONE_READ_ERROR (-1280) // (-5 << 8) /** Control directive or support for record type is not implemented. */ #define ZONE_NOT_IMPLEMENTED (-1536) // (-6 << 8) /** Specified file does not exist. */ #define ZONE_NOT_A_FILE (-1792) // (-7 << 8) /** Access to specified file is not allowed. */ #define ZONE_NOT_PERMITTED (-2048) // (-8 << 8) /** @} */ /** * @brief Parse zone file * * Parse file containing resource records. * * @param[in] parser Zone parser * @param[in] options Settings used for parsing. * @param[in] buffers Scratch buffers used for parsing. * @param[in] path Path of master file to parse. * @param[in] user_data Pointer passed verbatim to callbacks. * * @returns @ref ZONE_SUCCESS on success or a negative number on error. */ ZONE_EXPORT int32_t zone_parse( zone_parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, const char *path, void *user_data) zone_nonnull((1,2,3,4)); /** * @brief Parse zone from string * * Parse string containing resource records in presentation format. * * @warning The input string must be null terminated and padded with at least * @ref ZONE_BLOCK_SIZE bytes. * * @param[in] parser Zone parser * @param[in] options Settings used for parsing. * @param[in] buffers Scratch buffers used by parsing. * @param[in] string Input string. * @param[in] length Length of string (excluding null byte and padding). * @param[in] user_data Pointer passed verbatim to callbacks. * * @returns @ref ZONE_SUCCESS on success or a negative number on error. */ ZONE_EXPORT int32_t zone_parse_string( zone_parser_t *parser, const zone_options_t *options, zone_buffers_t *buffers, const char *string, size_t length, void *user_data) zone_nonnull((1,2,3,4)); /** * @defgroup log_priorities Log categories. * * @note No direct relation between log categories and error codes exists. * Log categories communicate the importance of the log message, error * codes communicate what went wrong to the caller. * @{ */ /** Error condition. */ /** @hideinitializer */ #define ZONE_ERROR (1u<<1) /** Warning condition. */ /** @hideinitializer */ #define ZONE_WARNING (1u<<2) /** Informational message. */ /** @hideinitializer */ #define ZONE_INFO (1u<<3) /** @} */ /** * @brief Write message to active log handler. * * The zone parser operates on a per-record base and therefore cannot detect * errors that span records. e.g. SOA records being specified more than once. * The user may print a message using the active log handler, keeping the * error message format consistent. * * @param[in] parser Zone parser * @param[in] priority Log priority * @param[in] format Format string compatible with printf * @param[in] ... Variadic arguments corresponding to #format */ ZONE_EXPORT void zone_log( zone_parser_t *parser, uint32_t priority, const char *format, ...) zone_nonnull((1,3)) zone_format_printf(3,4); /** * @brief Write error message to active log handler. * @hideinitializer * * Shorthand to write out error message via @ref zone_log if error messages are * not to be discarded. * * @param[in] parser Zone parser * @param[in] format Format string * @param[in] ... Variadic arguments corresponding to #format */ #define zone_error(parser, ...) \ (((parser)->options.log.mask & ZONE_ERROR) ? \ (void)0 : zone_log((parser), ZONE_ERROR, __VA_ARGS__)) /** * @brief Write warning message to active log handler. * @hideinitializer * * Shorthand to write out warning message via @ref zone_log if warning messages * are not to be discarded. * * @param[in] parser Zone parser * @param[in] format Format string compatible with printf. * @param[in] ... Variadic arguments corresponding to @format. */ #define zone_warning(parser, ...) \ (((parser)->options.mask & ZONE_WARNING) ? \ (void)0 : zone_log((parser), ZONE_WARNING, __VA_ARGS__)) /** * @brief Write informational message to active log handler. * @hideinitializer * * Shorthand to write out informational message via @ref zone_log if * informational messages are not be discarded. * * @param[in] parser Zone parser. * @param[in] format Format string compatible with printf. * @param[in] ... Variadic arguments corresponding to @format. */ #define zone_info(parser, ...) \ (((parser)->options.mask & ZONE_INFO) ? \ (void)0 : zone_log((parser), ZONE_INFO, __VA_ARGS__)) #if defined(__cplusplus) } #endif #endif // ZONE_H nsd-4.12.0/simdzone/configure.ac0000644000175000017500000000754515002373055016127 0ustar mozziemozzie# # configure.ac -- Autoconf script for simdzone # # Copyright (c) 2022-2023, NLnet Labs. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # This file is intended for inclusion by configure.ac in NSD. Support for any # platform not supported by NSD here is undesirable. Builds for standalone use # or development/testing are required to use CMake. AC_INIT([simdzone],[0.2.2],[https://github.com/NLnetLabs/simdzone/issues]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) m4_include(m4/ax_check_compile_flag.m4) m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC]) AC_CHECK_HEADERS([endian.h sys/endian.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_DECLS([bswap16,bswap32,bswap64], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_ENDIAN_H #include #endif #ifdef HAVE_SYS_ENDIAN_H #include #endif ]) AC_ARG_ENABLE(westmere, AS_HELP_STRING([--disable-westmere],[Disable Westmere (SSE4.2) kernel])) case "$enable_westmere" in no) enable_westmere=no ;; yes|*) enable_westmere=yes ;; esac AC_ARG_ENABLE(haswell, AS_HELP_STRING([--disable-haswell],[Disable Haswell (AVX2) kernel])) case "$enable_haswell" in no) enable_haswell=no ;; yes|*) enable_haswell=yes ;; esac # GCC and Clang AX_CHECK_COMPILE_FLAG([-MMD],DEPFLAGS="-MMD -MP") # Oracle Developer Studio (no -MP) AX_CHECK_COMPILE_FLAG([-xMMD],DEPFLAGS="-xMMD") AC_SUBST([DEPFLAGS]) # Figure out the canonical target architecture. AC_CANONICAL_TARGET # Multiple instruction sets may be supported by a specific architecture. # e.g. x86_64 may (or may not) support any of SSE42, AVX2 and AVX-512. The # best instruction set is automatically selected at runtime, but the compiler # may or may not support generating code for an instruction set. case "$target" in *amd64*) x86_64=yes ;; *x86_64*) x86_64=yes ;; *) x86_64=no ;; esac HAVE_WESTMERE=NO HAVE_HASWELL=NO if test $x86_64 = "yes"; then AC_CHECK_HEADER(immintrin.h,,,) AX_CHECK_COMPILE_FLAG([-march=westmere],,,[-Werror]) AX_CHECK_COMPILE_FLAG([-march=haswell],,,[-Werror]) # Check if the arch instruction set support includes the simd instructions. if test $enable_westmere != "no" -a \ $ax_cv_check_cflags__Werror__march_westmere = "yes" -a \ $ac_cv_header_immintrin_h = "yes" ; then AC_MSG_CHECKING(whether -march=westmere works) BAKCFLAGS="$CFLAGS" CFLAGS="-march=westmere $CFLAGS" AC_COMPILE_IFELSE([AC_LANG_SOURCE([ AC_INCLUDES_DEFAULT [ #include #include int main(int argc, char *argv[]) { (void)argv; uint64_t popcnt = _mm_popcnt_u64((uint64_t)argc); return popcnt == 11; } ]]) ],[ AC_DEFINE(HAVE_WESTMERE, 1, [Wether or not to compile support for SSE4.2]) HAVE_WESTMERE=WESTMERE AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) ]) CFLAGS="$BAKCFLAGS" fi if test $enable_haswell != "no" -a \ $ax_cv_check_cflags__Werror__march_haswell = "yes" -a \ $ac_cv_header_immintrin_h = "yes" ; then AC_MSG_CHECKING(whether -march=haswell works) BAKCFLAGS="$CFLAGS" CFLAGS="-march=haswell $CFLAGS" AC_COMPILE_IFELSE([AC_LANG_SOURCE([ AC_INCLUDES_DEFAULT [ #include #include int main(int argc, char *argv[]) { (void)argv; int argc32x8[8] = { argc, 0, 0, 0, 0, 0, 0, 0 }; __m256i argc256 = _mm256_loadu_si256((__m256i *)argc32x8); return _mm256_testz_si256(argc256, _mm256_set1_epi8(11)); } ]]) ],[ AC_DEFINE(HAVE_HASWELL, 1, [Wether or not to compile support for AVX2]) HAVE_HASWELL=HASWELL AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) ]) CFLAGS="$BAKCFLAGS" fi fi AC_CHECK_FUNCS([realpath],,[AC_MSG_ERROR([realpath is not available])]) AC_SUBST([HAVE_ENDIAN_H]) AC_SUBST([HAVE_WESTMERE]) AC_SUBST([HAVE_HASWELL]) AH_BOTTOM([ /* Defines _XOPEN_SOURCE and _POSIX_C_SOURCE implicitly in features.h */ #ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 #endif ]) AC_OUTPUT nsd-4.12.0/simdzone/compat/0000755000175000017500000000000015002373055015111 5ustar mozziemozziensd-4.12.0/simdzone/compat/getopt.h0000644000175000017500000000057015002373055016566 0ustar mozziemozzie/* * getopt.h -- getopt definitions for platform that are missing unistd.h * * Copyright (c) 2023, NLnet Labs. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef GETOPT_H #define GETOPT_H extern int opterr; extern int optind; extern int optopt; extern char *optarg; int getopt(int argc, char **argv, const char *opts); #endif /* GETOPT_H */ nsd-4.12.0/simdzone/compat/getopt.c0000644000175000017500000000427215002373055016564 0ustar mozziemozzie#include #include #include "getopt.h" /* * Here's something you've all been waiting for: the AT&T public domain * source for getopt(3). It is the code which was given out at the 1985 * UNIFORUM conference in Dallas. I obtained it by electronic mail * directly from AT&T. The people there assure me that it is indeed * in the public domain. * * There is no manual page. That is because the one they gave out at * UNIFORUM was slightly different from the current System V Release 2 * manual page. The difference apparently involved a note about the * famous rules 5 and 6, recommending using white space between an option * and its first argument, and not grouping options that have arguments. * Getopt itself is currently lenient about both of these things White * space is allowed, but not mandatory, and the last option in a group can * have an argument. That particular version of the man page evidently * has no official existence, and my source at AT&T did not send a copy. * The current SVR2 man page reflects the actual behavior of this getopt. * However, I am not about to post a copy of anything licensed by AT&T. */ #define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);} int opterr = 1; int optind = 1; int optopt; char *optarg; int getopt( int argc, char **argv, const char *opts) { static int sp = 1; register int c; register char *cp; if (sp == 1) { if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return (EOF); else if (strcmp(argv[optind], "--") == 0) { optind++; return (EOF); } } optopt = c = argv[optind][sp]; if (c == ':' || (cp = strchr(opts, c)) == NULL) { ERR(": illegal option -- ", c); if (argv[optind][++sp] == '\0') { optind++; sp = 1; } return ('?'); } if (*++cp == ':') { if (argv[optind][sp + 1] != '\0') optarg = &argv[optind++][sp + 1]; else if (++optind >= argc) { ERR(": option requires an argument -- ", c); sp = 1; return ('?'); } else optarg = argv[optind++]; sp = 1; } else { if (argv[optind][++sp] == '\0') { sp = 1; optind++; } optarg = NULL; } return (c); } nsd-4.12.0/simdzone/README.md0000644000175000017500000000715615002373055015116 0ustar mozziemozzie![Build Status](https://github.com/NLnetLabs/simdzone/actions/workflows/build-test.yml/badge.svg) [![Coverity Status](https://scan.coverity.com/projects/27509/badge.svg)](https://scan.coverity.com/projects/nlnetlabs-simdzone) [![Mastodon Follow](https://img.shields.io/mastodon/follow/109262826617293067?domain=https%3A%2F%2Ffosstodon.org&style=social)](https://fosstodon.org/@nlnetlabs) # simdzone: Parsing zone files really fast Fast and standards compliant DNS presentation format parser. DNS resource records (RRs) can be expressed in text form using the presentation format. The format is most frequently used to define a zone in master files, more commonly known as zone files, and is best considered a tabular serialization format with provisions for convenient editing. The format is originally defined in [RFC1035 section 5][rfc1035-section-5] and [RFC1034 section 3.6.1][rfc1034-section-3-6-1], but as the DNS is intentionally extensible, the format has been extended over time too. This project provides a lightning fast presentation format deserializer (and serializer eventually) for other projects to leverage. Learn more about simdzone by reading the [documentation](https://simdzone.docs.nlnetlabs.nl/). ## Research paper * Jeroen Koekkoek and Daniel Lemire, [Parsing Millions of DNS Records per Second](https://arxiv.org/abs/2411.12035), Software: Practice and Experience (to appear) ## Motivation Zone files can become quite large (.com ~24G, .se ~1.3G) and the parser in NSD left something to be desired. simdjson demonstrates that applying SIMD instructions for parsing structured text can significantly boost performance. simdzone, whose name is a play on [simdjson][simdjson], aims to achieve a similar performance boost for parsing zone data. > Currently SSE4.2 and AVX2 are supported, a fallback is used otherwise. > simdzone copies some code from the [simdjson][simdjson] project, with > permission to use and distribute it under the terms of > [The 3-Clause BSD License][bsd-3-clause]. [rfc1035-section-5]: https://datatracker.ietf.org/doc/html/rfc1035#section-5 [rfc1034-section-3-6-1]: https://datatracker.ietf.org/doc/html/rfc1034#section-3.6.1 [nsd]: https://nlnetlabs.nl/projects/nsd/about/ [simdjson]: https://github.com/simdjson/simdjson [bsd-3-clause]: https://opensource.org/license/bsd-3-clause/ ## Results Running `zone-bench` on my system (Intel Core i7-1065G7) against an older `.com` zone file of 12482791271 bytes under Linux (Fedora 39). clang version 17.0.6, release mode: ``` $ time ./zone-bench parse ../../zones/com.zone Selected target haswell Parsed 341535548 records real 0m13.533s user 0m12.355s sys 0m1.160s ``` There are bound to be bugs and quite possibly smarter ways of implementing some operations, but the results are promising. ## Compiling Make sure the following tools are installed: * C toolchain (the set of tools to compile C code) * [cmocka](https://cmocka.org/) (if configured with `-DBUILD_TESTING=on`) * [Doxygen](https://www.doxygen.nl/) (if configured with `-DBUILD_DOCUMENTATION=on`) * [Sphinx](https://www.sphinx-doc.org/en/master/) (if configured with `-DBUILD_DOCUMENTATION=on`) To compile in release mode: ``` $ cd zone-parser $ mkdir build $ cd build $ cmake -DCMAKE_BUILD_TYPE=Release .. $ cmake --build . ``` To compile in debug mode with testing: ``` $ cd zone-parser $ mkdir build $ cd build $ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=on .. $ cmake --build . ``` ## Contributing Contributions in any way, shape or form are very welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) to find out how you can help. Design decisions and notes on the [FORMAT](FORMAT.md). nsd-4.12.0/simdzone/Makefile.in0000644000175000017500000000434715002373055015703 0ustar mozziemozzie# # Makefile.in -- one file to make them all # # Copyright (c) 2022-2024, NLnet Labs. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # WESTMERE = @HAVE_WESTMERE@ HASWELL = @HAVE_HASWELL@ CC = @CC@ CPPFLAGS = @CPPFLAGS@ -Iinclude -I$(SOURCE)/include -I$(SOURCE)/src -I. CFLAGS = @CFLAGS@ DEPFLAGS = @DEPFLAGS@ VPATH = @srcdir@ SOURCE = @srcdir@ SOURCES = src/zone.c src/fallback/parser.c OBJECTS = $(SOURCES:.c=.o) WESTMERE_SOURCES = src/westmere/parser.c WESTMERE_OBJECTS = $(WESTMERE_SOURCES:.c=.o) HASWELL_SOURCES = src/haswell/parser.c HASWELL_OBJECTS = $(HASWELL_SOURCES:.c=.o) NO_OBJECTS = DEPENDS = $(SOURCES:.c=.d) $(WESTMERE_SOURCES:.c=.d) $(HASWELL_SOURCES:.c=.d) # The export header automatically defines visibility macros. These macros are # required for standalone builds on Windows. I.e., exported functions must be # declared with __declspec(dllexport) for dynamic link libraries (.dll) and # __declspec(dllimport) for statically linked libraries (.lib). Define dummy # macros for compatibility. EXPORT_HEADER = include/zone/export.h .PHONY: all clean all: libzone.a clean: @rm -f .depend @rm -f libzone.a $(OBJECTS) $(EXPORT_HEADER) @rm -f $($(WESTMERE)_OBJECTS) $($(HASWELL)_OBJECTS) distclean: clean @rm -f Makefile config.h config.log config.status realclean: distclean @rm -rf autom4te* maintainer-clean: realclean devclean: realclean @rm -rf config.h.in configure libzone.a: $(OBJECTS) $($(WESTMERE)_OBJECTS) $($(HASWELL)_OBJECTS) $(AR) rcs libzone.a $(OBJECTS) $($(WESTMERE)_OBJECTS) $($(HASWELL)_OBJECTS) $(EXPORT_HEADER): @mkdir -p include/zone @echo "#define ZONE_EXPORT" > $(EXPORT_HEADER) $(WESTMERE_OBJECTS): $(EXPORT_HEADER) .depend @mkdir -p src/westmere $(CC) $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) -march=westmere -o $@ -c $(SOURCE)/$(@:.o=.c) $(HASWELL_OBJECTS): $(EXPORT_HEADER) .depend @mkdir -p src/haswell $(CC) $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) -march=haswell -o $@ -c $(SOURCE)/$(@:.o=.c) $(OBJECTS): $(EXPORT_HEADER) .depend @mkdir -p src/fallback $(CC) $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) -o $@ -c $(SOURCE)/$(@:.o=.c) @touch $@ .depend: @cat /dev/null > $@ @for x in $(DEPENDS:.d=); do echo "$${x}.o: $(SOURCE)/$${x}.c $${x}.d" >> $@; done -include .depend $(DEPENDS): -include $(DEPENDS) nsd-4.12.0/simdzone/LICENSE0000644000175000017500000000275715002373055014646 0ustar mozziemozzieBSD 3-Clause License Copyright (c) 2022, NLnet Labs. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nsd-4.12.0/simdzone/FORMAT.md0000644000175000017500000003606315002373055015150 0ustar mozziemozzie# Zone files Zone files are text files that contain resource records (RRs) in text form. Zones can be defined by expressing them in the form of a list of RRs. Zone files were originally specified in RFC1035 Section 5, but the DNS has seen many additions since and the specification is rather ambiguous. Consequently, various name servers implement slightly different dialects. This document aims to clarify the format by listing (some of) the relevant specifications and then proceed to explain why certain design decisions were made in simdzone. * [RFC 1034 Section 3.6.1][rfc1034#3.6.1] * [RFC 1035 Section 5][rfc1035#5] * [RFC 2065 Section 4.5][rfc2065#4.5] * [RFC 2181 Section 8][rfc2181#8] * [RFC 2308 Section 4][rfc2308#4] * [RFC 3597 Section 5][rfc3597#5] * [RFC 9460 Section 2.1][rfc9460#2.1] ## Clarification (work-in-progress) > NOTE: BIND behavior is more-or-less considered the de facto standard. Historically, master files where edited by hand, which is reflected in the syntax. Consider the format a tabular serialization format with provisions for convenient editing. i.e. the owner, class and ttl fields may be omitted (provided the line starts with \ for the owner) and $INCLUDE directives can be used for templating. The format is NOT context-free. The field following the owner (if specified) may represent either a type, class or ttl and a symbolic constant, e.g. A or NS, may have a different meaning if specified as an RDATA field. The DNS is intentionally extensible. The specification is not explicit about how that affects syntax, but it explains why no specific notation for data-types can be enforced by RFC 1035. To make it easier for data-types to be added at a later stage the syntax cannot enforce a certain notation (or the scanner would need to be revised). Consequently, the scanner only identifies items (or fields) and structural characters, which can be expressed as either a contiguous set of characters without interior spaces, or as a quoted string. The format allows for including structural characters in fields by means of escaping the actual character or enclosing the field in quotes. The example provided by the specification here is using ASCII dots in domain name labels. The dot is normally a label separator, replaced by the length of the label on the wire. If a domain name includes an actual ASCII dot, the character must be escaped in the textual representation (`\X` or `\DDD`). Note that ASCII dot characters strictly speaking do not have to be escaped in a quoted string. RFC 1035 clearly states labels in domain names are expressed as character strings. However, behavior differs across implementations, so support for quoted labels is best dropped (see below). RFC 1035 states both \ and \ are \. Meaning, items can be either \ or \. Wether a specific item is interpreted as a \ depends on type of value for that item. E.g., TTLs are decimal integers and therefore cannot be expressed as \ as it is not a \. Similarly, base64 sequences are encoded binary blobs, not \s and therefore cannot be expressed as such. Escape sequences are valid only in \s. * Mnemonics are NOT character strings. > BIND does not accept quoted fields for A or NS RDATA. TTL values in SOA > RDATA, base64 Signature in DNSKEY RDATA, as well as type, class and TTL > header fields all result in a syntax error too if quoted. * Some integer fields allow for using mnemonics too. E.g., the algorithm field in RRSIG records. * RFC 1035 states: A freestanding @ denotes the current origin. There has been discussion in which locations @ is interpreted as the origin. e.g. how is a freestanding @ be interpreted in the RDATA section of a TXT RR. Note that there is no mention of text expansion in the original text. A freestanding @ denotes the origin. As such, it stands to reason that it's use is limited to locations where domain names are expressed, which also happens to be the most practical way to implement the functionality. > This also seems to be the behavior that other name servers implement (at > least BIND and PowerDNS). The BIND manual states: "When used in the label > (or name) field, the asperand or at-sign (@) symbol represents the current > origin. At the start of the zone file, it is the \, followed > by a trailing dot (.). > It may also make sense to interpret a quoted freestanding @ differently > than a non-quoted one. At least, BIND throws an error if a quoted > freestanding @ is encountered in the RDATA sections for CNAME and NS RRs. > However, a quoted freestanding @ is accepted and interpreted as origin > if specified as the OWNER. > Found mentions of what happens when a zone that uses freestanding @ in > RDATA is written to disk. Of course, this particular scenario rarely occurs > as it does not need to be written to disk when loaded on a primary and no > file exists if received over AXFR/IXFR. However, it may make sense to > implement optimistic compression of this form, and make it configurable. * Class and type names are mutually exclusive in practice. RFC1035 states: The RR begins with optional TTL and class fields, ... Therefore, if a type name matches a class name, the parser cannot distinguish between the two in text representation and must resort to generic notation (RFC3597) or, depending on the RDATA format for the record type, a look-ahead may be sufficient. Realistically, it is highly likely that because of this, no type name will ever match a class name. > This means both can reside in the same table. * The encoding is non-ASCII. Some characters have special meaning, but users are technically allowed to put in non-printable octets outside the ASCII range without custom encoding. Of course, this rarely occurs in practice and users are encouraged to use the \DDD encoding for "special". * Parenthesis may not be nested. * $ORIGIN must be an absolute domain. * Escape sequences must NOT be unescaped in the scanner as is common with programming languages like C that have a preprocessor. Instead, the original text is necessary in the parsing stage to distinguish between label separators (dots). * RFC 1035 specifies that the current origin should be restored after an $INCLUDE, but it is silent on whether the current domain name should also be restored. BIND 9 restores both of them. This could be construed as a deviation from RFC 1035, a feature, or both. * RFC 1035 states: and text literals can contain CRLF within the text. BIND, however, does not allow newlines in text (escaped or not). For performance reasons, we may adopt the same behavior as that would relieve the need to keep track of possibly embedded newlines. * From: http://www.zytrax.com/books/dns/ch8/include.html (mentioned in chat) > Source states: The RFC is silent on the topic of embedded `$INCLUDE`s in > `$INCLUDE`d files - BIND 9 documentation is similarly silent. Assume they > are not permitted. All implementations, including BIND, allow for embedded `$INCLUDE`s. The current implementation is such that (embedded) includes are allowed by default. However, `$INCLUDE` directives can be disabled, which is useful when parsing from an untrusted source. There is also protection against cyclic includes. > There is no maximum to the amount of embedded includes (yet). NSD limits > the number of includes to 10 by default (compile option). For security, it > must be possible to set a hard limit. * Default values for TTLs can be quite complicated. A [commit to ldns](https://github.com/NLnetLabs/ldns/commit/cb101c9) by @wtoorop nicely sums it up in code. RFC 1035 section 5.1: > Omitted class and TTL values are default to the last explicitly stated > values. This behavior is updated by RFC 2308 section 4: > All resource records appearing after the directive, and which do not > explicitly include a TTL value, have their TTL set to the TTL given > in the $TTL directive. SIG records without a explicit TTL get their > TTL from the "original TTL" of the SIG record [RFC 2065 Section 4.5]. The TTL rules for `SIG` RRs stated in RFC 2065 Section 4.5: > If the original TTL, which applies to the type signed, is the same as > the TTL of the SIG RR itself, it may be omitted. The date field > which follows it is larger than the maximum possible TTL so there is > no ambiguity. The same applies applies to `RRSIG` RRs, although not stated as explicitly in RFC 4034 Section 3: > The TTL value of an RRSIG RR MUST match the TTL value of the RRset it > covers. This is an exception to the [RFC2181] rules for TTL values > of individual RRs within a RRset: individual RRSIG RRs with the same > owner name will have different TTL values if the RRsets they cover > have different TTL values. Logic spanning RRs must not be handled during deserialization. The order in which RRs appear in the zone file is not relevant and keeping a possibly infinite backlog of RRs to handle it "automatically" is inefficient. As the name server retains RRs in a database already it seems most elegant to signal the TTL value was omitted and a default was used so that it may be updated in some post processing step. [RFC 2181 Section 8][rfc2181#8] contains additional notes on the maximum value for TTLs. During deserialization, any value exceeding 2147483647 is considered an error in primary mode, or a warning in secondary mode. [RFC 8767 Section 4][rfc8767#4] updates the text, but the update does not update handling during deserialization. [RFC 2181 Section 5][rfc2181#5.2] states the TTLs of all RRs in an RRSet must be the same. As with default values for `SIG` and `RRSIG` RRs, this must NOT be handled during deserialization. Presumably, the application should transparently fix TTLs (NLnetLabs/nsd#178). * Do NOT allow for quoted labels in domain names. [RFC 1035 Section 5][rfc1035#5] states: > The labels in the domain name are expressed as character strings and > separated by dots. [RFC 1035 section 5][rfc1035#5] states: > \ is expressed in one or two ways: as a contiguous set > of characters without interior spaces, or as string beginning with a " and > ending with a ". However, quoted labels in domain names are very uncommon and implementations handle quoted names both in OWNER and RDATA very differently. The Flex+Bison based parser used in NSD before was the only parser that got it right. * BIND * owner: yes, interpreted as quoted ``` dig @127.0.0.1 A quoted.example.com. ``` ``` quoted.example.com. xxx IN A x.x.x.x ``` * rdata: no, syntax error (even with `check-names master ignored;`) * Knot * owner: no, syntax error * rdata: no, syntax error * PowerDNS * owner: no, not interpreted as quoted ``` pdnsutil list-zone example.com. ``` ``` "quoted".example.com xxx IN A x.x.x.x ``` * rdata: no, not interpreted as quoted ``` dig @127.0.0.1 NS example.com. ``` ``` example.com. xxx IN NS \"quoted.example.com.\".example.com. ``` > [libzscanner](https://github.com/CZ-NIC/knot/tree/master/src/libzscanner), > the (standalone) zone parser used by Knot seems mosts consistent. Drop support for quoted labels or domain names for consistent behavior. * Should any domain names that are not valid host names as specified by RFC 1123 section 2, i.e. use characters not in the preferred naming syntax as specified by RFC 1035 section 2.3.1, be accepted? RFC 2181 section 11 is very specific on this topic, but it merely states that labels may contain characters outside the set on the wire, it does not address what is, or is not, allowed in zone files. BIND's zone parser throws a syntax error for any name that is not a valid hostname unless `check-names master ignored;` is specified. Knot additionally accepts `-`, `_` and `/` according to [NOTES](https://github.com/CZ-NIC/knot/blob/master/src/libzscanner/NOTES). * [RFC1035 Section 2.3.1][rfc1035#2.3.1] * [RFC1123 Section 2][rfc1123#2] * [RFC2181 Section 11][rfc2181#11] * RFC 1035 specifies two control directives "$INCLUDE" and "$ORIGIN". RFC 2308 specifies the "$TTL" directive. BIND additionally implements the "$DATE" and "$GENERATE" directives. Since "$" (dollar sign) is not reserved, both "$DATE" and "$GENERATE" (and "$TTL" before RFC2308) are considered valid domain names in other implementations (based on what is accepted for domain names, see earlier points). It seems "$" is better considered a reserved character (possibly limiting its special status to the start of the line), to allow for reliable extensibility in the future. > BIND seems to already throw an error if "$" is encountered, see > `lib/dns/master.c`. Presumably, the "$DATE" directive is written when the > zone is written to disk(?) In the code it is referred to as > __dump_time__ and later used to calculate __ttl_offset__. * BIND10 had a nice writeup on zone files, kindly provided by Shane Kerr. [Zone File Loading Requirements on Wayback Machine](https://web.archive.org/web/20140928215002/http://bind10.isc.org:80/wiki/ZoneLoadingRequirements) * `TYPE0` is sometimes used for debugging and therefore may occur in type bitmaps or as unknown RR type. * `pdns/master/regression-tests/zones/test.com` contains regression tests that may be useful for testing simdzone. * Some implementations (Knot, possibly PowerDNS) will silently split-up strings longer than 255 characters. Others (BIND, simdzone) will throw a syntax error. * How do we handle the corner case where the first record does not have a TTL when the file does not define a zone? (from @shane-kerr). At this point in time, the application provides a default TTL value before parsing. Whether that is the right approach is unclear, but it is what NSD did before. * Leading zeroes in integers appear to be allowed judging by the zone file generated for the [socket10kxfr][socket10kxfr.pre#L64] test in NSD. BIND and Knot parsed it without problems too. [rfc1034#3.6.1]: https://datatracker.ietf.org/doc/html/rfc1034#section-3.6.1 [rfc1035#5]: https://datatracker.ietf.org/doc/html/rfc1035#section-5 [rfc1035#2.3.1]: https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.1 [rfc1123#2]: https://datatracker.ietf.org/doc/html/rfc1123#section-2 [rfc2065#4.5]: https://datatracker.ietf.org/doc/html/rfc2065#section-4.5 [rfc2181#5.2]: https://datatracker.ietf.org/doc/html/rfc2181#section-5.2 [rfc2181#8]: https://datatracker.ietf.org/doc/html/rfc2181#section-8 [rfc2181#11]: https://datatracker.ietf.org/doc/html/rfc2181#section-11 [rfc2308#4]: https://datatracker.ietf.org/doc/html/rfc2308#section-4 [rfc3597#5]: https://datatracker.ietf.org/doc/html/rfc3597#section-5 [rfc8767#4]: https://www.rfc-editor.org/rfc/rfc8767#section-4 [rfc9460#2.1]: https://datatracker.ietf.org/doc/html/rfc9460#section-2.1 [socket10kxfr.pre#L64]: https://github.com/NLnetLabs/nsd/blob/86a6961f2ca64f169d7beece0ed8a5e1dd1cd302/tpkg/long/socket10kxfr.tdir/socket10kxfr.pre#L64 nsd-4.12.0/simdzone/CONTRIBUTING.md0000644000175000017500000000646315002373055016070 0ustar mozziemozzie# Contributing to simdzone The simdzone library is open source and made available under the permissive 3-clause BSD license. Contributions are very welcome! > The original specification in [RFC1035][1] is rather ambiguous and does not > cover additions from later RFCs. See [SYNTAX.md](SYNTAX.md) for a quick > summary of the format and interpretation in simdzone. [1]: https://datatracker.ietf.org/doc/html/rfc1035#section-5 ## Reference data 1. [Zone Data for .se and .nu][2] can be obtained via a DNS zone transfer. 2. The [Centralized Zone Data Service (CZDS)][3] provides access to zone data for participating gTLDs. > Downloading zone data via the browser can be problematic. The > [The CZDS API client in Java][4] can be used as a workaround. 3. The *Hint and Zone Files* can be obtained from Internet Assigned Numbers Authority (IANA) [Root Zone Management][5] page. [2]: https://internetstiftelsen.se/en/zone-data/ [3]: https://czds.icann.org/ [4]: https://github.com/icann/czds-api-client-java/ [5]: https://www.iana.org/domains/root ## Source layout `include` contains only headers required for consumption of the library. `src` contains the implementation and internal headers. The layout of `src` is (of course) inspired by the layout in simdjson. The structure is intentionally simple and without (too much) hierarchy, but as simdzone has very architecture specific code to maximize performance, there are some caveats. Processors may support multiple instruction sets. e.g. x86\_64 may support SSE4.2, AVX2 and AVX-512 instruction sets depending on the processor family. The preferred implementation is automatically selected at runtime. As a result, code may need to be compiled more than once. To improve code reuse, shared logic resides in headers rather than source files and is declared static to avoid name clashes. Bits and pieces are then mixed and matched in a `src//parser.c` compilation target to allow for multiple implementations to co-exist. Sources and headers common to all architectures that do not implement parsing for a specific data-type reside directly under `src`. Code specific to an architecture resides in a directory under `src`, e.g. `haswell` or `fallback`. `src/generic` contains scanner and parser code common to all implementations, but leans towards code shared by SIMD implementations. For example, SIMD-optimized scanner code resides in `src/generic/scanner.h`, abstractions for intrinsics reside in e.g. `src/haswell/simd.h` and `lex(...)`, which is used by all implementations, is implemented in `src/lexer.h`. A fallback scanner is implemented in `src/fallback/scanner.h`. A SIMD-optimized type parser is implemented in `src/generic/type.h`, a fallback type parser is implemented in `src/fallback/type.h`. Future versions are expected to add more optimized parsers for specific data types, even parsers that are tied to a specific instruction set. The layout accommodates these scenarios. e.g. an AVX2 optimized parser may reside in `src/haswell/.h`, an SSE4.2 optimized parser may reside in `src/westmere/.h`, etc. ## Symbol visibility All exported symbols, identifiers, etc must be prefixed with `zone_`, or `ZONE_` for macros. Non-exported symbols are generally not prefixed. e.g. `lex(...)` and `scan(...)` are declared static and as such are not required to be prefixed. nsd-4.12.0/simdzone/CHANGELOG.md0000644000175000017500000000521515002373055015442 0ustar mozziemozzie# Changelog All notable changes to simdzone will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.2.2] - 2025-04-24 ### Added - Support for EID, NIMLOC, SINK, TALINK, DSYNC, DOA, AMTRELAY and IPN RR types. ### Fixed - Empty base16 and base64 in CDS and CDNSKEY can be represented with a '0'. As specified in Section 4 of RFC 8078. - Initialise padding after the file buffer (#249). - Fix type NSAP-PTR (#250). - Fix LOC poweroften lookup (#251). ## [0.2.1] - 2025-01-17 ### Fixed - Cleanup westmere and haswell object files (#244) Thanks @fobser - Out of tree builds (NLnetLabs/nsd#415) - Fix function declarations for fallback detection routine in isadetection.h. ## [0.2.0] - 2024-12-12 ### Added - Add semantic checks for DS and ZONEMD digests (NLnetLabs/nsd#205). - Support registering a callback for $INCLUDE entries (NLnetLabs/nsd#229). - Add tls-supported-groups SvcParam support. - Check iana registries for unimplemented (new) RR types and SvcParamKeys. - Add support for NINFO, RKEY, RESINFO, WALLET, CLA and TA RR types. ### Fixed - Prepend -march to CFLAGS to fix architecture detection (NLnetLabs/nsd#372). - Fix propagation of implicit TTLs (NLnetLabs/nsd#375). - Fix detection of Westmere architecture by checking for CLMUL too. - Fix compilation on NetBSD (#233). - Fix reading specialized symbolic links (NLnetLabs/nsd#380). ## [0.1.1] - 2024-07-19 ### Added - Test to verify configure.ac and Makefile.in are correct. - Add support for reading from stdin if filename is "-". - Add support for building with Oracle Developer Studio 12.6. - Add support for "time" service for Well-Know Services (WKS) RR. ### Fixed - Fix makefile dependencies. - Fix makefile to use source directory for build dependencies. - Fix changelog to reflect v0.1.0 release. - Update makefile to not use target-specific variables. - Fix makefile clean targets. - Fix state keeping in fallback scanner for contiguous and quoted. - Fix bug in name scanner. - Fix type mnemonic parsing in fallback parser. - Fix endian.h to include machine/endian.h on OpenBSD releases before 5.6. - Fix use after free on buffer resize. - Fix parsing of numeric protocols in WKS RRs. - Make devclean target depend on realclean target. - Fix detection of AVX2 support by checking generic AVX support by the processor and operating system (#222). ### Changed - Make relative includes relative to current working directory. - Split Autoconf and CMake compiler tests for supported SIMD instructions. ## [0.1.0] - 2024-04-16 ### Added - Initial release. nsd-4.12.0/server.c0000644000175000017500000047526115002373054013466 0ustar mozziemozzie/* * server.c -- nsd(8) network input/output * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef USE_TCP_FASTOPEN #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_RANDOM_H #include #endif #ifndef SHUT_WR #define SHUT_WR 1 #endif #ifdef HAVE_MMAP #include #endif /* HAVE_MMAP */ #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_OPENSSL_SSL_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_OCSP_H #include #endif #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "axfr.h" #include "namedb.h" #include "netio.h" #include "xfrd.h" #include "xfrd-tcp.h" #include "xfrd-disk.h" #include "difffile.h" #include "nsec3.h" #include "ipc.h" #include "udb.h" #include "remote.h" #include "lookup3.h" #include "rrl.h" #include "ixfr.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif #include "verify.h" #include "util/proxy_protocol.h" #ifdef USE_METRICS #include "metrics.h" #endif /* USE_METRICS */ #define RELOAD_SYNC_TIMEOUT 25 /* seconds */ #ifdef USE_DNSTAP /* * log_addr() - the function to print sockaddr_in/sockaddr_in6 structures content * just like its done in Unbound via the same log_addr(VERB_LEVEL, const char*, sockaddr_storage*) */ static void log_addr(const char* descr, #ifdef INET6 struct sockaddr_storage* addr #else struct sockaddr_in* addr #endif ) { char str_buf[64]; if(verbosity < 6) return; if( #ifdef INET6 addr->ss_family == AF_INET #else addr->sin_family == AF_INET #endif ) { struct sockaddr_in* s = (struct sockaddr_in*)addr; inet_ntop(AF_INET, &s->sin_addr.s_addr, str_buf, sizeof(str_buf)); VERBOSITY(6, (LOG_INFO, "%s: address is: %s, port is: %d", descr, str_buf, ntohs(s->sin_port))); #ifdef INET6 } else { struct sockaddr_in6* s6 = (struct sockaddr_in6*)addr; inet_ntop(AF_INET6, &s6->sin6_addr.s6_addr, str_buf, sizeof(str_buf)); VERBOSITY(6, (LOG_INFO, "%s: address is: %s, port is: %d", descr, str_buf, ntohs(s6->sin6_port))); #endif } } #endif /* USE_DNSTAP */ #ifdef USE_TCP_FASTOPEN #define TCP_FASTOPEN_FILE "/proc/sys/net/ipv4/tcp_fastopen" #define TCP_FASTOPEN_SERVER_BIT_MASK 0x2 #endif /* header state for the PROXYv2 header (for TCP) */ enum pp2_header_state { /* no header encounter yet */ pp2_header_none = 0, /* read the static part of the header */ pp2_header_init, /* read the full header */ pp2_header_done }; /* * Data for the UDP handlers. */ struct udp_handler_data { struct nsd *nsd; struct nsd_socket *socket; struct event event; /* if set, PROXYv2 is expected on this connection */ int pp2_enabled; }; struct tcp_accept_handler_data { struct nsd *nsd; struct nsd_socket *socket; int event_added; struct event event; #ifdef HAVE_SSL /* handler accepts TLS connections on the dedicated port */ int tls_accept; int tls_auth_accept; #endif /* if set, PROXYv2 is expected on this connection */ int pp2_enabled; }; /* * These globals are used to enable the TCP accept handlers * when the number of TCP connection drops below the maximum * number of TCP connections. */ static size_t tcp_accept_handler_count; static struct tcp_accept_handler_data *tcp_accept_handlers; static struct event slowaccept_event; static int slowaccept; #ifdef HAVE_SSL static unsigned char *ocspdata = NULL; static long ocspdata_len = 0; #endif #ifdef NONBLOCKING_IS_BROKEN /* Define NUM_RECV_PER_SELECT to 1 (one) to avoid opportunistically trying to read multiple times from a socket when reported ready by select. */ # define NUM_RECV_PER_SELECT (1) #else /* !NONBLOCKING_IS_BROKEN */ # define NUM_RECV_PER_SELECT (100) #endif /* NONBLOCKING_IS_BROKEN */ #ifndef HAVE_MMSGHDR struct mmsghdr { struct msghdr msg_hdr; unsigned int msg_len; }; #endif static struct mmsghdr msgs[NUM_RECV_PER_SELECT]; static struct iovec iovecs[NUM_RECV_PER_SELECT]; static struct query *queries[NUM_RECV_PER_SELECT]; /* * Data for the TCP connection handlers. * * The TCP handlers use non-blocking I/O. This is necessary to avoid * blocking the entire server on a slow TCP connection, but does make * reading from and writing to the socket more complicated. * * Basically, whenever a read/write would block (indicated by the * EAGAIN errno variable) we remember the position we were reading * from/writing to and return from the TCP reading/writing event * handler. When the socket becomes readable/writable again we * continue from the same position. */ struct tcp_handler_data { /* * The region used to allocate all TCP connection related * data, including this structure. This region is destroyed * when the connection is closed. */ region_type* region; /* * The global nsd structure. */ struct nsd* nsd; /* * The current query data for this TCP connection. */ query_type* query; /* * The query_state is used to remember if we are performing an * AXFR, if we're done processing, or if we should discard the * query and connection. */ query_state_type query_state; /* * The event for the file descriptor and tcp timeout */ struct event event; /* * The bytes_transmitted field is used to remember the number * of bytes transmitted when receiving or sending a DNS * packet. The count includes the two additional bytes used * to specify the packet length on a TCP connection. */ size_t bytes_transmitted; /* If the query is restarted and needs a reset */ int query_needs_reset; /* * The number of queries handled by this specific TCP connection. */ int query_count; /* * The timeout in msec for this tcp connection */ int tcp_timeout; /* * If the connection is allowed to have further queries on it. */ int tcp_no_more_queries; #ifdef USE_DNSTAP /* the socket of the accept socket to find proper service (local) address the socket is bound to. */ struct nsd_socket *socket; #endif /* USE_DNSTAP */ /* if set, PROXYv2 is expected on this connection */ int pp2_enabled; /* header state for the PROXYv2 header (for TCP) */ enum pp2_header_state pp2_header_state; #ifdef HAVE_SSL /* * TLS objects. */ SSL* tls; SSL* tls_auth; /* * TLS handshake state. */ enum { tls_hs_none, tls_hs_read, tls_hs_write, tls_hs_read_event, tls_hs_write_event } shake_state; #endif /* list of connections, for service of remaining tcp channels */ struct tcp_handler_data *prev, *next; }; /* global that is the list of active tcp channels */ static struct tcp_handler_data *tcp_active_list = NULL; /* * Handle incoming queries on the UDP server sockets. */ static void handle_udp(int fd, short event, void* arg); /* * Handle incoming connections on the TCP sockets. These handlers * usually wait for the NETIO_EVENT_READ event (indicating an incoming * connection) but are disabled when the number of current TCP * connections is equal to the maximum number of TCP connections. * Disabling is done by changing the handler to wait for the * NETIO_EVENT_NONE type. This is done using the function * configure_tcp_accept_handlers. */ static void handle_tcp_accept(int fd, short event, void* arg); /* * Handle incoming queries on a TCP connection. The TCP connections * are configured to be non-blocking and the handler may be called * multiple times before a complete query is received. */ static void handle_tcp_reading(int fd, short event, void* arg); /* * Handle outgoing responses on a TCP connection. The TCP connections * are configured to be non-blocking and the handler may be called * multiple times before a complete response is sent. */ static void handle_tcp_writing(int fd, short event, void* arg); #ifdef HAVE_SSL /* Create SSL object and associate fd */ static SSL* incoming_ssl_fd(SSL_CTX* ctx, int fd); /* * Handle TLS handshake. May be called multiple times if incomplete. */ static int tls_handshake(struct tcp_handler_data* data, int fd, int writing); /* * Handle incoming queries on a TLS over TCP connection. The TLS * connections are configured to be non-blocking and the handler may * be called multiple times before a complete query is received. */ static void handle_tls_reading(int fd, short event, void* arg); /* * Handle outgoing responses on a TLS over TCP connection. The TLS * connections are configured to be non-blocking and the handler may * be called multiple times before a complete response is sent. */ static void handle_tls_writing(int fd, short event, void* arg); #endif /* * Send all children the quit nonblocking, then close pipe. */ static void send_children_quit(struct nsd* nsd); /* same, for shutdown time, waits for child to exit to avoid restart issues */ static void send_children_quit_and_wait(struct nsd* nsd); /* set childrens flags to send NSD_STATS to them */ #ifdef BIND8_STATS static void set_children_stats(struct nsd* nsd); #endif /* BIND8_STATS */ /* * Change the event types the HANDLERS are interested in to EVENT_TYPES. */ static void configure_handler_event_types(short event_types); static uint16_t *compressed_dname_offsets = 0; static uint32_t compression_table_capacity = 0; static uint32_t compression_table_size = 0; static domain_type* compressed_dnames[MAXRRSPP]; #ifdef USE_TCP_FASTOPEN /* Checks to see if the kernel value must be manually changed in order for TCP Fast Open to support server mode */ static void report_tcp_fastopen_config() { int tcp_fastopen_fp; uint8_t tcp_fastopen_value; if ( (tcp_fastopen_fp = open(TCP_FASTOPEN_FILE, O_RDONLY)) == -1 ) { log_msg(LOG_INFO,"Error opening " TCP_FASTOPEN_FILE ": %s\n", strerror(errno)); } if (read(tcp_fastopen_fp, &tcp_fastopen_value, 1) == -1 ) { log_msg(LOG_INFO,"Error reading " TCP_FASTOPEN_FILE ": %s\n", strerror(errno)); close(tcp_fastopen_fp); } if (!(tcp_fastopen_value & TCP_FASTOPEN_SERVER_BIT_MASK)) { log_msg(LOG_WARNING, "Error: TCP Fast Open support is available and configured in NSD by default.\n"); log_msg(LOG_WARNING, "However the kernel parameters are not configured to support TCP_FASTOPEN in server mode.\n"); log_msg(LOG_WARNING, "To enable TFO use the command:"); log_msg(LOG_WARNING, " 'sudo sysctl -w net.ipv4.tcp_fastopen=2' for pure server mode or\n"); log_msg(LOG_WARNING, " 'sudo sysctl -w net.ipv4.tcp_fastopen=3' for both client and server mode\n"); log_msg(LOG_WARNING, "NSD will not have TCP Fast Open available until this change is made.\n"); close(tcp_fastopen_fp); } close(tcp_fastopen_fp); } #endif /* * Remove the specified pid from the list of child pids. Returns -1 if * the pid is not in the list, child_num otherwise. The field is set to 0. */ static int delete_child_pid(struct nsd *nsd, pid_t pid) { size_t i; for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid == pid) { nsd->children[i].pid = 0; if(!nsd->children[i].need_to_exit) { if(nsd->children[i].child_fd != -1) close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; if(nsd->children[i].handler) nsd->children[i].handler->fd = -1; } return i; } } return -1; } /* * Restart child servers if necessary. */ static int restart_child_servers(struct nsd *nsd, region_type* region, netio_type* netio, int* xfrd_sock_p) { size_t i; int sv[2]; /* Fork the child processes... */ for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid <= 0) { if (nsd->children[i].child_fd != -1) close(nsd->children[i].child_fd); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { log_msg(LOG_ERR, "socketpair: %s", strerror(errno)); return -1; } nsd->children[i].child_fd = sv[0]; nsd->children[i].parent_fd = sv[1]; nsd->children[i].pid = fork(); switch (nsd->children[i].pid) { default: /* SERVER MAIN */ close(nsd->children[i].parent_fd); nsd->children[i].parent_fd = -1; if (fcntl(nsd->children[i].child_fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } if(!nsd->children[i].handler) { struct main_ipc_handler_data *ipc_data; ipc_data = (struct main_ipc_handler_data*) region_alloc( region, sizeof(struct main_ipc_handler_data)); ipc_data->nsd = nsd; ipc_data->child = &nsd->children[i]; nsd->children[i].handler = (struct netio_handler*) region_alloc( region, sizeof(struct netio_handler)); nsd->children[i].handler->fd = nsd->children[i].child_fd; nsd->children[i].handler->timeout = NULL; nsd->children[i].handler->user_data = ipc_data; nsd->children[i].handler->event_types = NETIO_EVENT_READ; nsd->children[i].handler->event_handler = parent_handle_child_command; netio_add_handler(netio, nsd->children[i].handler); } /* restart - update fd */ nsd->children[i].handler->fd = nsd->children[i].child_fd; break; case 0: /* CHILD */ #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(region); #endif nsd->pid = 0; 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; nsd->signal_hint_reload = 0; nsd->signal_hint_child = 0; nsd->signal_hint_quit = 0; nsd->signal_hint_shutdown = 0; nsd->signal_hint_stats = 0; nsd->signal_hint_statsusr = 0; close(*xfrd_sock_p); close(nsd->this_child->child_fd); nsd->this_child->child_fd = -1; if (fcntl(nsd->this_child->parent_fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } server_child(nsd); /* NOTREACH */ exit(0); case -1: log_msg(LOG_ERR, "fork failed: %s", strerror(errno)); return -1; } } } return 0; } #ifdef BIND8_STATS static void set_bind8_alarm(struct nsd* nsd) { /* resync so that the next alarm is on the next whole minute */ if(nsd->st_period > 0) /* % by 0 gives divbyzero error */ alarm(nsd->st_period - (time(NULL) % nsd->st_period)); } #endif /* set zone stat ids for zones initially read in */ static void zonestatid_tree_set(struct nsd* nsd) { struct radnode* n; for(n=radix_first(nsd->db->zonetree); n; n=radix_next(n)) { zone_type* zone = (zone_type*)n->elem; zone->zonestatid = getzonestatid(nsd->options, zone->opts); } } #ifdef USE_ZONE_STATS void server_zonestat_alloc(struct nsd* nsd) { size_t num = (nsd->options->zonestatnames->count==0?1: nsd->options->zonestatnames->count); size_t sz = sizeof(struct nsdst)*num; char tmpfile[256]; uint8_t z = 0; /* file names */ nsd->zonestatfname[0] = 0; nsd->zonestatfname[1] = 0; snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.0", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[0] = region_strdup(nsd->region, tmpfile); snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.1", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[1] = region_strdup(nsd->region, tmpfile); /* file descriptors */ nsd->zonestatfd[0] = open(nsd->zonestatfname[0], O_CREAT|O_RDWR, 0600); if(nsd->zonestatfd[0] == -1) { log_msg(LOG_ERR, "cannot create %s: %s", nsd->zonestatfname[0], strerror(errno)); exit(1); } nsd->zonestatfd[1] = open(nsd->zonestatfname[1], O_CREAT|O_RDWR, 0600); if(nsd->zonestatfd[0] == -1) { log_msg(LOG_ERR, "cannot create %s: %s", nsd->zonestatfname[1], strerror(errno)); close(nsd->zonestatfd[0]); unlink(nsd->zonestatfname[0]); exit(1); } #ifdef HAVE_MMAP if(lseek(nsd->zonestatfd[0], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[0], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[0], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[0], strerror(errno)); exit(1); } if(lseek(nsd->zonestatfd[1], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[1], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[1], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[1], strerror(errno)); exit(1); } nsd->zonestat[0] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[0], 0); if(nsd->zonestat[0] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } nsd->zonestat[1] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[1], 0); if(nsd->zonestat[1] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } memset(nsd->zonestat[0], 0, sz); memset(nsd->zonestat[1], 0, sz); nsd->zonestatsize[0] = num; nsd->zonestatsize[1] = num; nsd->zonestatdesired = num; nsd->zonestatsizenow = num; nsd->zonestatnow = nsd->zonestat[0]; #endif /* HAVE_MMAP */ } void zonestat_remap(struct nsd* nsd, int idx, size_t sz) { #ifdef HAVE_MMAP #ifdef MREMAP_MAYMOVE nsd->zonestat[idx] = (struct nsdst*)mremap(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx], sz, MREMAP_MAYMOVE); if(nsd->zonestat[idx] == MAP_FAILED) { log_msg(LOG_ERR, "mremap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE MREMAP */ if(msync(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx], MS_ASYNC) != 0) log_msg(LOG_ERR, "msync failed: %s", strerror(errno)); if(munmap(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx]) != 0) log_msg(LOG_ERR, "munmap failed: %s", strerror(errno)); nsd->zonestat[idx] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[idx], 0); if(nsd->zonestat[idx] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); exit(1); } #endif /* MREMAP */ #endif /* HAVE_MMAP */ } /* realloc the zonestat array for the one that is not currently in use, * to match the desired new size of the array (if applicable) */ void server_zonestat_realloc(struct nsd* nsd) { #ifdef HAVE_MMAP uint8_t z = 0; size_t sz; int idx = 0; /* index of the zonestat array that is not in use */ if(nsd->zonestatnow == nsd->zonestat[0]) idx = 1; if(nsd->zonestatsize[idx] == nsd->zonestatdesired) return; sz = sizeof(struct nsdst)*nsd->zonestatdesired; if(lseek(nsd->zonestatfd[idx], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[idx], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[idx], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[idx], strerror(errno)); exit(1); } zonestat_remap(nsd, idx, sz); /* zero the newly allocated region */ if(nsd->zonestatdesired > nsd->zonestatsize[idx]) { memset(((char*)nsd->zonestat[idx])+sizeof(struct nsdst) * nsd->zonestatsize[idx], 0, sizeof(struct nsdst) * (nsd->zonestatdesired - nsd->zonestatsize[idx])); } nsd->zonestatsize[idx] = nsd->zonestatdesired; #endif /* HAVE_MMAP */ } /* switchover to use the other array for the new children, that * briefly coexist with the old children. And we want to avoid them * both writing to the same statistics arrays. */ void server_zonestat_switch(struct nsd* nsd) { if(nsd->zonestatnow == nsd->zonestat[0]) { nsd->zonestatnow = nsd->zonestat[1]; nsd->zonestatsizenow = nsd->zonestatsize[1]; } else { nsd->zonestatnow = nsd->zonestat[0]; nsd->zonestatsizenow = nsd->zonestatsize[0]; } } #endif /* USE_ZONE_STATS */ #ifdef BIND8_STATS void server_stat_alloc(struct nsd* nsd) { char tmpfile[256]; size_t sz = sizeof(struct nsdst) * nsd->child_count * 2; uint8_t z = 0; /* file name */ nsd->statfname = 0; snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.stat", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->statfname = region_strdup(nsd->region, tmpfile); /* file descriptor */ nsd->statfd = open(nsd->statfname, O_CREAT|O_RDWR, 0600); if(nsd->statfd == -1) { log_msg(LOG_ERR, "cannot create %s: %s", nsd->statfname, strerror(errno)); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } #ifdef HAVE_MMAP if(lseek(nsd->statfd, (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->statfname, strerror(errno)); goto fail_exit; } if(write(nsd->statfd, &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->statfname, strerror(errno)); goto fail_exit; } nsd->stat_map = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->statfd, 0); if(nsd->stat_map == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); fail_exit: close(nsd->statfd); unlink(nsd->statfname); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } memset(nsd->stat_map, 0, sz); nsd->stats_per_child[0] = nsd->stat_map; nsd->stats_per_child[1] = &nsd->stat_map[nsd->child_count]; nsd->stat_current = 0; nsd->st = &nsd->stats_per_child[nsd->stat_current][0]; #endif /* HAVE_MMAP */ } #endif /* BIND8_STATS */ #ifdef BIND8_STATS void server_stat_free(struct nsd* nsd) { unlink(nsd->statfname); } #endif /* BIND8_STATS */ static void cleanup_dname_compression_tables(void *ptr) { free(ptr); compressed_dname_offsets = NULL; compression_table_capacity = 0; } static void initialize_dname_compression_tables(struct nsd *nsd) { size_t needed = domain_table_count(nsd->db->domains) + 1; needed += EXTRA_DOMAIN_NUMBERS; if(compression_table_capacity < needed) { if(compressed_dname_offsets) { region_remove_cleanup(nsd->db->region, cleanup_dname_compression_tables, compressed_dname_offsets); free(compressed_dname_offsets); } compressed_dname_offsets = (uint16_t *) xmallocarray( needed, sizeof(uint16_t)); region_add_cleanup(nsd->db->region, cleanup_dname_compression_tables, compressed_dname_offsets); compression_table_capacity = needed; compression_table_size=domain_table_count(nsd->db->domains)+1; } memset(compressed_dname_offsets, 0, needed * sizeof(uint16_t)); compressed_dname_offsets[0] = QHEADERSZ; /* The original query name */ } static int set_cloexec(struct nsd_socket *sock) { assert(sock != NULL); if(fcntl(sock->s, F_SETFD, FD_CLOEXEC) == -1) { const char *socktype = sock->addr.ai_family == SOCK_DGRAM ? "udp" : "tcp"; log_msg(LOG_ERR, "fcntl(..., O_CLOEXEC) failed for %s: %s", socktype, strerror(errno)); return -1; } return 1; } static int set_reuseport(struct nsd_socket *sock) { #ifdef SO_REUSEPORT int on = 1; #ifdef SO_REUSEPORT_LB /* FreeBSD 12 has SO_REUSEPORT_LB that does load balancing like * SO_REUSEPORT on Linux. This is what the users want with the config * option in nsd.conf; if we actually need local address and port reuse * they'll also need to have SO_REUSEPORT set for them, assume it was * _LB they want. */ int opt = SO_REUSEPORT_LB; static const char optname[] = "SO_REUSEPORT_LB"; #else /* !SO_REUSEPORT_LB */ int opt = SO_REUSEPORT; static const char optname[] = "SO_REUSEPORT"; #endif /* SO_REUSEPORT_LB */ if (0 == setsockopt(sock->s, SOL_SOCKET, opt, &on, sizeof(on))) { return 1; } else if(verbosity >= 3 || errno != ENOPROTOOPT) { log_msg(LOG_ERR, "setsockopt(..., %s, ...) failed: %s", optname, strerror(errno)); } return -1; #else (void)sock; #endif /* SO_REUSEPORT */ return 0; } static int set_reuseaddr(struct nsd_socket *sock) { #ifdef SO_REUSEADDR int on = 1; if(setsockopt(sock->s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == 0) { return 1; } log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); return -1; #endif /* SO_REUSEADDR */ return 0; } static int set_rcvbuf(struct nsd_socket *sock, int rcv) { #ifdef SO_RCVBUF #ifdef SO_RCVBUFFORCE if(0 == setsockopt( sock->s, SOL_SOCKET, SO_RCVBUFFORCE, &rcv, sizeof(rcv))) { return 1; } if(errno == EPERM || errno == ENOBUFS) { return 0; } log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUFFORCE, ...) failed: %s", strerror(errno)); return -1; #else /* !SO_RCVBUFFORCE */ if (0 == setsockopt( sock->s, SOL_SOCKET, SO_RCVBUF, &rcv, sizeof(rcv))) { return 1; } if(errno == ENOSYS || errno == ENOBUFS) { return 0; } log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUF, ...) failed: %s", strerror(errno)); return -1; #endif /* SO_RCVBUFFORCE */ #endif /* SO_RCVBUF */ return 0; } static int set_sndbuf(struct nsd_socket *sock, int snd) { #ifdef SO_SNDBUF #ifdef SO_SNDBUFFORCE if(0 == setsockopt( sock->s, SOL_SOCKET, SO_SNDBUFFORCE, &snd, sizeof(snd))) { return 1; } if(errno == EPERM || errno == ENOBUFS) { return 0; } log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUFFORCE, ...) failed: %s", strerror(errno)); return -1; #else /* !SO_SNDBUFFORCE */ if(0 == setsockopt( sock->s, SOL_SOCKET, SO_SNDBUF, &snd, sizeof(snd))) { return 1; } if(errno == ENOSYS || errno == ENOBUFS) { return 0; } log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUF, ...) failed: %s", strerror(errno)); return -1; #endif /* SO_SNDBUFFORCE */ #endif /* SO_SNDBUF */ return 0; } static int set_nonblock(struct nsd_socket *sock) { const char *socktype = sock->addr.ai_socktype == SOCK_DGRAM ? "udp" : "tcp"; if(fcntl(sock->s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fctnl(..., O_NONBLOCK) failed for %s: %s", socktype, strerror(errno)); return -1; } return 1; } #ifdef INET6 static int set_ipv6_v6only(struct nsd_socket *sock) { #ifdef IPV6_V6ONLY int on = 1; const char *socktype = sock->addr.ai_socktype == SOCK_DGRAM ? "udp" : "tcp"; if(0 == setsockopt( sock->s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed for %s: %s", socktype, strerror(errno)); return -1; #else (void)sock; #endif /* IPV6_V6ONLY */ return 0; } #endif /* INET6 */ #ifdef INET6 static int set_ipv6_use_min_mtu(struct nsd_socket *sock) { #if defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) #if defined(IPV6_USE_MIN_MTU) /* There is no fragmentation of IPv6 datagrams during forwarding in the * network. Therefore we do not send UDP datagrams larger than the * minimum IPv6 MTU of 1280 octets. The EDNS0 message length can be * larger if the network stack supports IPV6_USE_MIN_MTU. */ int opt = IPV6_USE_MIN_MTU; int optval = 1; static const char optname[] = "IPV6_USE_MIN_MTU"; #elif defined(IPV6_MTU) /* On Linux, PMTUD is disabled by default for datagrams so set the MTU * to the MIN MTU to get the same. */ int opt = IPV6_MTU; int optval = IPV6_MIN_MTU; static const char optname[] = "IPV6_MTU"; #endif if(0 == setsockopt( sock->s, IPPROTO_IPV6, opt, &optval, sizeof(optval))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., %s, ...) failed: %s", optname, strerror(errno)); return -1; #else (void)sock; #endif /* INET6 */ return 0; } #endif /* INET6 */ static int set_ipv4_no_pmtu_disc(struct nsd_socket *sock) { int ret = 0; #if defined(IP_MTU_DISCOVER) int opt = IP_MTU_DISCOVER; int optval; # if defined(IP_PMTUDISC_OMIT) /* Linux 3.15 has IP_PMTUDISC_OMIT which makes sockets ignore PMTU * information and send packets with DF=0. Fragmentation is allowed if * and only if the packet size exceeds the outgoing interface MTU or * the packet encounters smaller MTU link in network. This mitigates * DNS fragmentation attacks by preventing forged PMTU information. * FreeBSD already has same semantics without setting the option. */ optval = IP_PMTUDISC_OMIT; if(0 == setsockopt( sock->s, IPPROTO_IP, opt, &optval, sizeof(optval))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., %s, %s, ...) failed: %s", "IP_MTU_DISCOVER", "IP_PMTUDISC_OMIT", strerror(errno)); # endif /* IP_PMTUDISC_OMIT */ # if defined(IP_PMTUDISC_DONT) /* Use IP_PMTUDISC_DONT if IP_PMTUDISC_OMIT failed / undefined. */ optval = IP_PMTUDISC_DONT; if(0 == setsockopt( sock->s, IPPROTO_IP, opt, &optval, sizeof(optval))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., %s, %s, ...) failed: %s", "IP_MTU_DISCOVER", "IP_PMTUDISC_DONT", strerror(errno)); # endif ret = -1; #elif defined(IP_DONTFRAG) int off = 0; if (0 == setsockopt( sock->s, IPPROTO_IP, IP_DONTFRAG, &off, sizeof(off))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., IP_DONTFRAG, ...) failed: %s", strerror(errno)); ret = -1; #else (void)sock; #endif return ret; } static int set_ip_freebind(struct nsd_socket *sock) { #ifdef IP_FREEBIND int on = 1; const char *socktype = sock->addr.ai_socktype == SOCK_DGRAM ? "udp" : "tcp"; if(setsockopt(sock->s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) == 0) { return 1; } log_msg(LOG_ERR, "setsockopt(..., IP_FREEBIND, ...) failed for %s: %s", socktype, strerror(errno)); return -1; #else (void)sock; #endif /* IP_FREEBIND */ return 0; } static int set_ip_transparent(struct nsd_socket *sock) { /* The scandalous preprocessor blob here calls for some explanation :) POSIX does not specify an option to bind non-local IPs, so platforms developed several implementation-specific options, all set in the same way, but with different names. For additional complexity, some platform manage this setting differently for different address families (IPv4 vs IPv6). This scandalous preprocessor blob below abstracts such variability in the way which leaves the C code as lean and clear as possible. */ #if defined(IP_TRANSPARENT) # define NSD_SOCKET_OPTION_TRANSPARENT IP_TRANSPARENT # define NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL IPPROTO_IP # define NSD_SOCKET_OPTION_TRANSPARENT_NAME "IP_TRANSPARENT" // as of 2020-01, Linux does not support this on IPv6 programmatically #elif defined(SO_BINDANY) # define NSD_SOCKET_OPTION_TRANSPARENT SO_BINDANY # define NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL SOL_SOCKET # define NSD_SOCKET_OPTION_TRANSPARENT_NAME "SO_BINDANY" #elif defined(IP_BINDANY) # define NSD_SOCKET_OPTION_TRANSPARENT IP_BINDANY # define NSD_SOCKET_OPTION_TRANSPARENT6 IPV6_BINDANY # define NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL IPPROTO_IP # define NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL6 IPPROTO_IPV6 # define NSD_SOCKET_OPTION_TRANSPARENT_NAME "IP_BINDANY" #endif #ifndef NSD_SOCKET_OPTION_TRANSPARENT (void)sock; #else # ifndef NSD_SOCKET_OPTION_TRANSPARENT6 # define NSD_SOCKET_OPTION_TRANSPARENT6 NSD_SOCKET_OPTION_TRANSPARENT # endif # ifndef NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL6 # define NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL6 NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL # endif # ifndef NSD_SOCKET_OPTION_TRANSPARENT_NAME6 # define NSD_SOCKET_OPTION_TRANSPARENT_NAME6 NSD_SOCKET_OPTION_TRANSPARENT_NAME # endif int on = 1; const char *socktype = sock->addr.ai_socktype == SOCK_DGRAM ? "udp" : "tcp"; const int is_ip6 = (sock->addr.ai_family == AF_INET6); if(0 == setsockopt( sock->s, is_ip6 ? NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL6 : NSD_SOCKET_OPTION_TRANSPARENT_OPTLEVEL, is_ip6 ? NSD_SOCKET_OPTION_TRANSPARENT6 : NSD_SOCKET_OPTION_TRANSPARENT, &on, sizeof(on))) { return 1; } log_msg(LOG_ERR, "setsockopt(..., %s, ...) failed for %s: %s", is_ip6 ? NSD_SOCKET_OPTION_TRANSPARENT_NAME6 : NSD_SOCKET_OPTION_TRANSPARENT_NAME, socktype, strerror(errno)); return -1; #endif return 0; } static int set_tcp_maxseg(struct nsd_socket *sock, int mss) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss)) == 0) { return 1; } log_msg(LOG_ERR, "setsockopt(..., TCP_MAXSEG, ...) failed for tcp: %s", strerror(errno)); return -1; #else log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported"); #endif return 0; } #ifdef USE_TCP_FASTOPEN static int set_tcp_fastopen(struct nsd_socket *sock) { /* qlen specifies how many outstanding TFO requests to allow. Limit is * a defense against IP spoofing attacks as suggested in RFC7413. */ int qlen; #ifdef __APPLE__ /* macOS X implementation only supports qlen of 1 via this call. The * actual value is configured by the net.inet.tcp.fastopen_backlog * kernel parameter. */ qlen = 1; #else /* 5 is recommended on Linux. */ qlen = 5; #endif if (0 == setsockopt( sock->s, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen))) { return 1; } if (errno == EPERM) { log_msg(LOG_ERR, "Setting TCP Fast Open as server failed: %s " "; this could likely be because sysctl " "net.inet.tcp.fastopen.enabled, " "net.inet.tcp.fastopen.server_enable, or " "net.ipv4.tcp_fastopen is disabled", strerror(errno)); /* Squelch ENOPROTOOPT: FreeBSD server mode with kernel support * disabled, except when verbosity enabled for debugging */ } else if(errno != ENOPROTOOPT || verbosity >= 3) { log_msg(LOG_ERR, "Setting TCP Fast Open as server failed: %s", strerror(errno)); } return (errno == ENOPROTOOPT ? 0 : -1); } #endif /* USE_TCP_FASTOPEN */ static int set_bindtodevice(struct nsd_socket *sock) { #if defined(SO_BINDTODEVICE) if(setsockopt(sock->s, SOL_SOCKET, SO_BINDTODEVICE, sock->device, strlen(sock->device)) == -1) { log_msg(LOG_ERR, "setsockopt(..., %s, %s, ...) failed: %s", "SO_BINDTODEVICE", sock->device, strerror(errno)); return -1; } return 1; #else (void)sock; return 0; #endif } static int set_setfib(struct nsd_socket *sock) { #if defined(SO_SETFIB) if(setsockopt(sock->s, SOL_SOCKET, SO_SETFIB, (const void *)&sock->fib, sizeof(sock->fib)) == -1) { log_msg(LOG_ERR, "setsockopt(..., %s, %d, ...) failed: %s", "SO_SETFIB", sock->fib, strerror(errno)); return -1; } return 1; #else (void)sock; return 0; #endif } static int open_udp_socket(struct nsd *nsd, struct nsd_socket *sock, int *reuseport_works) { int rcv = 1*1024*1024, snd = 1*1024*1024; if(-1 == (sock->s = socket( sock->addr.ai_family, sock->addr.ai_socktype, 0))) { #ifdef INET6 if((sock->flags & NSD_SOCKET_IS_OPTIONAL) && (sock->addr.ai_family == AF_INET6) && (errno == EAFNOSUPPORT)) { log_msg(LOG_WARNING, "fallback to UDP4, no IPv6: " "not supported"); return 0; } #endif log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } set_cloexec(sock); if(nsd->reuseport && reuseport_works && *reuseport_works) *reuseport_works = (set_reuseport(sock) == 1); if(nsd->options->receive_buffer_size > 0) rcv = nsd->options->receive_buffer_size; if(set_rcvbuf(sock, rcv) == -1) return -1; if(nsd->options->send_buffer_size > 0) snd = nsd->options->send_buffer_size; if(set_sndbuf(sock, snd) == -1) return -1; #ifdef INET6 if(sock->addr.ai_family == AF_INET6) { if(set_ipv6_v6only(sock) == -1 || set_ipv6_use_min_mtu(sock) == -1) return -1; } else #endif /* INET6 */ if(sock->addr.ai_family == AF_INET) { if(set_ipv4_no_pmtu_disc(sock) == -1) return -1; } /* Set socket to non-blocking. Otherwise, on operating systems * with thundering herd problems, the UDP recv could block * after select returns readable. */ set_nonblock(sock); if(nsd->options->ip_freebind) (void)set_ip_freebind(sock); if(nsd->options->ip_transparent) (void)set_ip_transparent(sock); if((sock->flags & NSD_BIND_DEVICE) && set_bindtodevice(sock) == -1) return -1; if(sock->fib != -1 && set_setfib(sock) == -1) return -1; if(bind(sock->s, (struct sockaddr *)&sock->addr.ai_addr, sock->addr.ai_addrlen) == -1) { char buf[256]; addrport2str((void*)&sock->addr.ai_addr, buf, sizeof(buf)); log_msg(LOG_ERR, "can't bind udp socket %s: %s", buf, strerror(errno)); return -1; } return 1; } static int open_tcp_socket(struct nsd *nsd, struct nsd_socket *sock, int *reuseport_works) { #ifdef USE_TCP_FASTOPEN report_tcp_fastopen_config(); #endif (void)reuseport_works; if(-1 == (sock->s = socket( sock->addr.ai_family, sock->addr.ai_socktype, 0))) { #ifdef INET6 if((sock->flags & NSD_SOCKET_IS_OPTIONAL) && (sock->addr.ai_family == AF_INET6) && (errno == EAFNOSUPPORT)) { log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: " "not supported"); return 0; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } set_cloexec(sock); if(nsd->reuseport && reuseport_works && *reuseport_works) *reuseport_works = (set_reuseport(sock) == 1); (void)set_reuseaddr(sock); #ifdef INET6 if(sock->addr.ai_family == AF_INET6) { if (set_ipv6_v6only(sock) == -1 || set_ipv6_use_min_mtu(sock) == -1) return -1; } #endif if(nsd->tcp_mss > 0) set_tcp_maxseg(sock, nsd->tcp_mss); /* (StevensUNP p463), if TCP listening socket is blocking, then it may block in accept, even if select() says readable. */ (void)set_nonblock(sock); if(nsd->options->ip_freebind) (void)set_ip_freebind(sock); if(nsd->options->ip_transparent) (void)set_ip_transparent(sock); if((sock->flags & NSD_BIND_DEVICE) && set_bindtodevice(sock) == -1) return -1; if(sock->fib != -1 && set_setfib(sock) == -1) return -1; if(bind(sock->s, (struct sockaddr *)&sock->addr.ai_addr, sock->addr.ai_addrlen) == -1) { char buf[256]; addrport2str((void*)&sock->addr.ai_addr, buf, sizeof(buf)); log_msg(LOG_ERR, "can't bind tcp socket %s: %s", buf, strerror(errno)); return -1; } #ifdef USE_TCP_FASTOPEN (void)set_tcp_fastopen(sock); #endif if(listen(sock->s, TCP_BACKLOG) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); return -1; } return 1; } /* * Initialize the server, reuseport, create and bind the sockets. */ int server_init(struct nsd *nsd) { size_t i; int reuseport = 1; /* Determine if REUSEPORT works. */ /* open server interface ports */ for(i = 0; i < nsd->ifs; i++) { if(open_udp_socket(nsd, &nsd->udp[i], &reuseport) == -1 || open_tcp_socket(nsd, &nsd->tcp[i], &reuseport) == -1) { return -1; } } if(nsd->reuseport && reuseport) { size_t ifs = nsd->ifs * nsd->reuseport; /* increase the size of the interface arrays, there are going * to be separate interface file descriptors for every server * instance */ region_remove_cleanup(nsd->region, free, nsd->udp); region_remove_cleanup(nsd->region, free, nsd->tcp); nsd->udp = xrealloc(nsd->udp, ifs * sizeof(*nsd->udp)); nsd->tcp = xrealloc(nsd->tcp, ifs * sizeof(*nsd->tcp)); region_add_cleanup(nsd->region, free, nsd->udp); region_add_cleanup(nsd->region, free, nsd->tcp); if(ifs > nsd->ifs) { memset(&nsd->udp[nsd->ifs], 0, (ifs-nsd->ifs)*sizeof(*nsd->udp)); memset(&nsd->tcp[nsd->ifs], 0, (ifs-nsd->ifs)*sizeof(*nsd->tcp)); } for(i = nsd->ifs; i < ifs; i++) { nsd->udp[i] = nsd->udp[i%nsd->ifs]; nsd->udp[i].s = -1; if(open_udp_socket(nsd, &nsd->udp[i], &reuseport) == -1) { return -1; } nsd->tcp[i] = nsd->tcp[i%nsd->ifs]; nsd->tcp[i].s = -1; if(open_tcp_socket(nsd, &nsd->tcp[i], &reuseport) == -1) { return -1; } } nsd->ifs = ifs; } else { nsd->reuseport = 0; } /* open server interface ports for verifiers */ for(i = 0; i < nsd->verify_ifs; i++) { if(open_udp_socket(nsd, &nsd->verify_udp[i], NULL) == -1 || open_tcp_socket(nsd, &nsd->verify_tcp[i], NULL) == -1) { return -1; } } return 0; } /* * Prepare the server for take off. * */ int server_prepare(struct nsd *nsd) { #ifdef RATELIMIT /* set secret modifier for hashing (rate limits) */ #ifdef HAVE_GETRANDOM uint32_t v; if(getrandom(&v, sizeof(v), 0) == -1) { log_msg(LOG_ERR, "getrandom failed: %s", strerror(errno)); exit(1); } hash_set_raninit(v); #elif defined(HAVE_ARC4RANDOM) hash_set_raninit(arc4random()); #else uint32_t v = getpid() ^ time(NULL); srandom((unsigned long)v); # ifdef HAVE_SSL if(RAND_status() && RAND_bytes((unsigned char*)&v, sizeof(v)) > 0) hash_set_raninit(v); else # endif hash_set_raninit(random()); #endif rrl_mmap_init(nsd->child_count, nsd->options->rrl_size, nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit, nsd->options->rrl_slip, nsd->options->rrl_ipv4_prefix_length, nsd->options->rrl_ipv6_prefix_length); #endif /* RATELIMIT */ /* Open the database... */ if ((nsd->db = namedb_open(nsd->options)) == NULL) { log_msg(LOG_ERR, "unable to open the database: %s", strerror(errno)); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef BIND8_STATS server_stat_free(nsd); #endif xfrd_del_tempdir(nsd); return -1; } /* check if zone files can be read */ /* NULL for taskudb because we send soainfo in a moment, batched up, * for all zones */ namedb_check_zonefiles(nsd, nsd->options, NULL, NULL); zonestatid_tree_set(nsd); compression_table_capacity = 0; initialize_dname_compression_tables(nsd); #ifdef BIND8_STATS /* Initialize times... */ time(&nsd->st->boot); set_bind8_alarm(nsd); #endif /* BIND8_STATS */ return 0; } /* * Fork the required number of servers. */ static int server_start_children(struct nsd *nsd, region_type* region, netio_type* netio, int* xfrd_sock_p) { size_t i; /* Start all child servers initially. */ for (i = 0; i < nsd->child_count; ++i) { nsd->children[i].pid = 0; } return restart_child_servers(nsd, region, netio, xfrd_sock_p); } static void server_close_socket(struct nsd_socket *sock) { if(sock->s != -1) { close(sock->s); sock->s = -1; } } void server_close_all_sockets(struct nsd_socket sockets[], size_t n) { size_t i; /* Close all the sockets... */ for (i = 0; i < n; ++i) { server_close_socket(&sockets[i]); } } /* * Close the sockets, shutdown the server and exit. * Does not return. */ void server_shutdown(struct nsd *nsd) { size_t i; server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); /* CHILD: close command channel to parent */ if(nsd->this_child && nsd->this_child->parent_fd != -1) { close(nsd->this_child->parent_fd); nsd->this_child->parent_fd = -1; } /* SERVER: close command channels to children */ if(!nsd->this_child) { for(i=0; i < nsd->child_count; ++i) if(nsd->children[i].child_fd != -1) { close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; } } tsig_finalize(); daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */ #ifdef USE_METRICS daemon_metrics_delete(nsd->metrics); #endif /* USE_METRICS */ #ifdef HAVE_SSL if (nsd->tls_ctx) SSL_CTX_free(nsd->tls_ctx); if (nsd->tls_auth_ctx) SSL_CTX_free(nsd->tls_auth_ctx); #endif #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_mmap_deinit_keep_mmap(); #endif #ifdef USE_DNSTAP dt_collector_destroy(nsd->dt_collector, nsd); #endif udb_base_free_keep_mmap(nsd->task[0]); udb_base_free_keep_mmap(nsd->task[1]); namedb_free_ixfr(nsd->db); namedb_close(nsd->db); nsd_options_destroy(nsd->options); region_destroy(nsd->region); #endif log_finalize(); exit(0); } void server_prepare_xfrd(struct nsd* nsd) { char tmpfile[256]; size_t i; /* create task mmaps */ nsd->mytask = 0; snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.0", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[0] = task_file_create(tmpfile); if(!nsd->task[0]) { #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef BIND8_STATS server_stat_free(nsd); #endif xfrd_del_tempdir(nsd); exit(1); } snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.1", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[1] = task_file_create(tmpfile); if(!nsd->task[1]) { unlink(nsd->task[0]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef BIND8_STATS server_stat_free(nsd); #endif xfrd_del_tempdir(nsd); exit(1); } assert(udb_base_get_userdata(nsd->task[0])->data == 0); assert(udb_base_get_userdata(nsd->task[1])->data == 0); /* create xfrd listener structure */ nsd->xfrd_listener = region_alloc(nsd->region, sizeof(netio_handler_type)); nsd->xfrd_listener->user_data = (struct ipc_handler_conn_data*) region_alloc(nsd->region, sizeof(struct ipc_handler_conn_data)); nsd->xfrd_listener->fd = -1; ((struct ipc_handler_conn_data*)nsd->xfrd_listener->user_data)->nsd = nsd; ((struct ipc_handler_conn_data*)nsd->xfrd_listener->user_data)->conn = xfrd_tcp_create(nsd->region, QIOBUFSZ); /* setup sockets to pass NOTIFY messages from the serve processes */ nsd->serve2xfrd_fd_send = region_alloc_array( nsd->region, 2 * nsd->child_count, sizeof(int)); nsd->serve2xfrd_fd_recv= region_alloc_array( nsd->region, 2 * nsd->child_count, sizeof(int)); for(i=0; i < 2 * nsd->child_count; i++) { int pipefd[2]; pipefd[0] = -1; /* For receiving by parent (xfrd) */ pipefd[1] = -1; /* For sending by child (server childs) */ if(pipe(pipefd) < 0) { log_msg(LOG_ERR, "fatal error: cannot create NOTIFY " "communication channel: %s", strerror(errno)); exit(1); } nsd->serve2xfrd_fd_recv[i] = pipefd[0]; nsd->serve2xfrd_fd_send[i] = pipefd[1]; } nsd->serve2xfrd_fd_swap = nsd->serve2xfrd_fd_send + nsd->child_count; } void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active) { pid_t pid; int sockets[2] = {0,0}; struct ipc_handler_conn_data *data; size_t i; if(nsd->xfrd_listener->fd != -1) close(nsd->xfrd_listener->fd); if(del_db) { /* recreate taskdb that xfrd was using, it may be corrupt */ /* we (or reload) use nsd->mytask, and xfrd uses the other */ char* tmpfile = nsd->task[1-nsd->mytask]->fname; nsd->task[1-nsd->mytask]->fname = NULL; /* free alloc already, so udb does not shrink itself */ udb_alloc_delete(nsd->task[1-nsd->mytask]->alloc); nsd->task[1-nsd->mytask]->alloc = NULL; udb_base_free(nsd->task[1-nsd->mytask]); /* create new file, overwrite the old one */ nsd->task[1-nsd->mytask] = task_file_create(tmpfile); free(tmpfile); } if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { log_msg(LOG_ERR, "startxfrd failed on socketpair: %s", strerror(errno)); return; } pid = fork(); switch (pid) { case -1: log_msg(LOG_ERR, "fork xfrd failed: %s", strerror(errno)); break; default: /* PARENT: close first socket, use second one */ close(sockets[0]); if (fcntl(sockets[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } if(del_db) xfrd_free_namedb(nsd); /* use other task than I am using, since if xfrd died and is * restarted, the reload is using nsd->mytask */ nsd->mytask = 1 - nsd->mytask; /* close the send site of the serve2xfrd fds */ assert(nsd->serve2xfrd_fd_send < nsd->serve2xfrd_fd_swap); for(i = 0; i < 2 * nsd->child_count; i++) { if(nsd->serve2xfrd_fd_send[i] != -1) { close(nsd->serve2xfrd_fd_send[i]); nsd->serve2xfrd_fd_send[i] = -1; } } #ifdef HAVE_SETPROCTITLE setproctitle("xfrd"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("xfrd"); #endif #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->xfrd_cpuset); } #endif xfrd_init(sockets[1], nsd, del_db, reload_active, pid); /* ENOTREACH */ break; case 0: /* CHILD: close second socket, use first one */ close(sockets[1]); if (fcntl(sockets[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } nsd->xfrd_listener->fd = sockets[0]; /* close the receive site of the serve2xfrd fds */ for(i = 0; i < 2 * nsd->child_count; i++) { if(nsd->serve2xfrd_fd_recv[i] != -1) { close(nsd->serve2xfrd_fd_recv[i]); nsd->serve2xfrd_fd_recv[i] = -1; } } #ifdef HAVE_SETPROCTITLE setproctitle("main"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("main"); #endif break; } /* server-parent only */ nsd->xfrd_listener->timeout = NULL; nsd->xfrd_listener->event_types = NETIO_EVENT_READ; nsd->xfrd_listener->event_handler = parent_handle_xfrd_command; /* clear ongoing ipc reads */ data = (struct ipc_handler_conn_data *) nsd->xfrd_listener->user_data; data->conn->is_reading = 0; } /** add all soainfo to taskdb */ static void add_all_soa_to_task(struct nsd* nsd, struct udb_base* taskudb) { struct radnode* n; udb_ptr task_last; /* last task, mytask is empty so NULL */ /* add all SOA INFO to mytask */ udb_ptr_init(&task_last, taskudb); for(n=radix_first(nsd->db->zonetree); n; n=radix_next(n)) { task_new_soainfo(taskudb, &task_last, (zone_type*)n->elem, 0); } udb_ptr_unlink(&task_last, taskudb); } void server_send_soa_xfrd(struct nsd* nsd, int shortsoa) { /* normally this exchanges the SOA from nsd->xfrd and the expire back. * parent fills one taskdb with soas, xfrd fills other with expires. * then they exchange and process. * shortsoa: xfrd crashes and needs to be restarted and one taskdb * may be in use by reload. Fill SOA in taskdb and give to xfrd. * expire notifications can be sent back via a normal reload later * (xfrd will wait for current running reload to finish if any). */ sig_atomic_t cmd = 0; pid_t mypid; int xfrd_sock = nsd->xfrd_listener->fd; struct udb_base* taskudb = nsd->task[nsd->mytask]; udb_ptr t; if(!shortsoa) { if(nsd->signal_hint_shutdown) { shutdown: log_msg(LOG_WARNING, "signal received, shutting down..."); server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); daemon_remote_close(nsd->rc); /* Unlink it if possible... */ unlinkpid(nsd->pidfile, nsd->username); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef BIND8_STATS server_stat_free(nsd); #endif server_shutdown(nsd); /* ENOTREACH */ exit(0); } } if(shortsoa) { /* put SOA in xfrd task because mytask may be in use */ taskudb = nsd->task[1-nsd->mytask]; } add_all_soa_to_task(nsd, taskudb); if(!shortsoa) { /* wait for xfrd to signal task is ready, RELOAD signal */ if(block_read(nsd, xfrd_sock, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD) { log_msg(LOG_ERR, "did not get start signal from xfrd"); exit(1); } if(nsd->signal_hint_shutdown) { goto shutdown; } } /* give xfrd our task, signal it with RELOAD_DONE */ task_process_sync(taskudb); cmd = NSD_RELOAD_DONE; if(!write_socket(xfrd_sock, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending soa end from reload %d to xfrd: %s", (int)nsd->pid, strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } if(!shortsoa) { /* process the xfrd task works (expiry data) */ nsd->mytask = 1 - nsd->mytask; taskudb = nsd->task[nsd->mytask]; task_remap(taskudb); udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); while(!udb_ptr_is_null(&t)) { task_process_expire(nsd->db, TASKLIST(&t)); udb_ptr_set_rptr(&t, taskudb, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, taskudb); task_clear(taskudb); /* tell xfrd that the task is emptied, signal with RELOAD_DONE */ cmd = NSD_RELOAD_DONE; if(!write_socket(xfrd_sock, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending soa end from reload %d to xfrd: %s", (int)nsd->pid, strerror(errno)); } } } #ifdef HAVE_SSL static void log_crypto_from_err(int level, const char* str, unsigned long err) { /* error:[error code]:[library name]:[function name]:[reason string] */ char buf[128]; unsigned long e; ERR_error_string_n(err, buf, sizeof(buf)); log_msg(level, "%s crypto %s", str, buf); while( (e=ERR_get_error()) ) { ERR_error_string_n(e, buf, sizeof(buf)); log_msg(level, "and additionally crypto %s", buf); } } void log_crypto_err(const char* str) { log_crypto_from_err(LOG_ERR, str, ERR_get_error()); } void log_crypto_warning(const char* str) { log_crypto_from_err(LOG_WARNING, str, ERR_get_error()); } /** true if the ssl handshake error has to be squelched from the logs */ static int squelch_err_ssl_handshake(unsigned long err) { if(verbosity >= 3) return 0; /* only squelch on low verbosity */ /* this is very specific, we could filter on ERR_GET_REASON() * (the third element in ERR_PACK) */ if(err == ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GET_RECORD, SSL_R_HTTPS_PROXY_REQUEST) || err == ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GET_RECORD, SSL_R_HTTP_REQUEST) || err == ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER) || err == ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_READ_BYTES, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE) #ifdef SSL_F_TLS_POST_PROCESS_CLIENT_HELLO || err == ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER) #endif #ifdef SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO || err == ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL) || err == ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, SSL_R_UNSUPPORTED_PROTOCOL) # ifdef SSL_R_VERSION_TOO_LOW || err == ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, SSL_R_VERSION_TOO_LOW) # endif #endif ) return 1; return 0; } void perform_openssl_init(void) { /* init SSL library */ #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); #endif #if defined(HAVE_ERR_LOAD_SSL_STRINGS) && !defined(DEPRECATED_ERR_LOAD_SSL_STRINGS) ERR_load_SSL_strings(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else OPENSSL_init_ssl(0, NULL); #endif if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); size_t i; v = seed; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); log_msg(LOG_WARNING, "warning: no entropy, seeding openssl PRNG with time"); } } static int get_ocsp(char *filename, unsigned char **ocsp) { BIO *bio; OCSP_RESPONSE *response; int len = -1; unsigned char *p, *buf; assert(filename); if ((bio = BIO_new_file(filename, "r")) == NULL) { log_crypto_err("get_ocsp: BIO_new_file failed"); return -1; } if ((response = d2i_OCSP_RESPONSE_bio(bio, NULL)) == NULL) { log_crypto_err("get_ocsp: d2i_OCSP_RESPONSE_bio failed"); BIO_free(bio); return -1; } if ((len = i2d_OCSP_RESPONSE(response, NULL)) <= 0) { log_crypto_err("get_ocsp: i2d_OCSP_RESPONSE #1 failed"); OCSP_RESPONSE_free(response); BIO_free(bio); return -1; } if ((buf = malloc((size_t) len)) == NULL) { log_msg(LOG_ERR, "get_ocsp: malloc failed"); OCSP_RESPONSE_free(response); BIO_free(bio); return -1; } p = buf; if ((len = i2d_OCSP_RESPONSE(response, &p)) <= 0) { log_crypto_err("get_ocsp: i2d_OCSP_RESPONSE #2 failed"); free(buf); OCSP_RESPONSE_free(response); BIO_free(bio); return -1; } OCSP_RESPONSE_free(response); BIO_free(bio); *ocsp = buf; return len; } /* further setup ssl ctx after the keys are loaded */ static void listen_sslctx_setup_2(void* ctxt) { SSL_CTX* ctx = (SSL_CTX*)ctxt; (void)ctx; #if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO if(!SSL_CTX_set_ecdh_auto(ctx,1)) { /* ENOTREACH */ log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); } #elif defined(HAVE_DECL_SSL_CTX_SET_TMP_ECDH) && defined(NID_X9_62_prime256v1) && defined(HAVE_EC_KEY_NEW_BY_CURVE_NAME) if(1) { EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); if (!ecdh) { log_crypto_err("could not find p256, not enabling ECDHE"); } else { if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); } EC_KEY_free (ecdh); } } #endif } static int add_ocsp_data_cb(SSL *s, void* ATTR_UNUSED(arg)) { if(ocspdata) { unsigned char *p; if ((p=malloc(ocspdata_len)) == NULL) { log_msg(LOG_ERR, "add_ocsp_data_cb: malloc failure"); return SSL_TLSEXT_ERR_NOACK; } memcpy(p, ocspdata, ocspdata_len); if ((SSL_set_tlsext_status_ocsp_resp(s, p, ocspdata_len)) != 1) { log_crypto_err("Error in SSL_set_tlsext_status_ocsp_resp"); free(p); return SSL_TLSEXT_ERR_NOACK; } return SSL_TLSEXT_ERR_OK; } else { return SSL_TLSEXT_ERR_NOACK; } } static int server_alpn_cb(SSL* ATTR_UNUSED(s), const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* ATTR_UNUSED(arg)) { static const unsigned char alpns[] = { 3, 'd', 'o', 't' }; unsigned char* tmp_out; SSL_select_next_proto(&tmp_out, outlen, alpns, sizeof(alpns), in, inlen); *out = tmp_out; return SSL_TLSEXT_ERR_OK; } SSL_CTX* server_tls_ctx_setup(char* key, char* pem, char* verifypem) { SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); if(!ctx) { log_crypto_err("could not SSL_CTX_new"); return NULL; } /* no SSLv2, SSLv3 because has defects */ #if SSL_OP_NO_SSLv2 != 0 if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2){ log_crypto_err("could not set SSL_OP_NO_SSLv2"); SSL_CTX_free(ctx); return NULL; } #endif if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3){ log_crypto_err("could not set SSL_OP_NO_SSLv3"); SSL_CTX_free(ctx); return 0; } #if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1) /* if we have tls 1.1 disable 1.0 */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1) != SSL_OP_NO_TLSv1){ log_crypto_err("could not set SSL_OP_NO_TLSv1"); SSL_CTX_free(ctx); return 0; } #endif #if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2) /* if we have tls 1.2 disable 1.1 */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1) != SSL_OP_NO_TLSv1_1){ log_crypto_err("could not set SSL_OP_NO_TLSv1_1"); SSL_CTX_free(ctx); return 0; } #endif #if defined(SSL_OP_NO_RENEGOTIATION) /* disable client renegotiation */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) & SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) { log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION"); SSL_CTX_free(ctx); return 0; } #endif #if defined(SSL_OP_IGNORE_UNEXPECTED_EOF) /* disable client renegotiation */ if((SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF) & SSL_OP_IGNORE_UNEXPECTED_EOF) != SSL_OP_IGNORE_UNEXPECTED_EOF) { log_crypto_warning("could not set SSL_OP_IGNORE_UNEXPECTED_EOF"); } #endif #if defined(SHA256_DIGEST_LENGTH) && defined(SSL_TXT_CHACHA20) /* if we detect system-wide crypto policies, use those */ if (access( "/etc/crypto-policies/config", F_OK ) != 0 ) { /* if we have sha256, set the cipher list to have no known vulns */ if(!SSL_CTX_set_cipher_list(ctx, "ECDHE+AESGCM:ECDHE+CHACHA20")) log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list"); } #endif if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) != SSL_OP_CIPHER_SERVER_PREFERENCE) { log_crypto_err("could not set SSL_OP_CIPHER_SERVER_PREFERENCE"); SSL_CTX_free(ctx); return 0; } #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL SSL_CTX_set_security_level(ctx, 0); #endif if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_msg(LOG_ERR, "error for cert file: %s", pem); log_crypto_err("error in SSL_CTX use_certificate_chain_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) { log_msg(LOG_ERR, "error for private key file: %s", key); log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); SSL_CTX_free(ctx); return NULL; } if(!SSL_CTX_check_private_key(ctx)) { log_msg(LOG_ERR, "error for key file: %s", key); log_crypto_err("Error in SSL_CTX check_private_key"); SSL_CTX_free(ctx); return NULL; } listen_sslctx_setup_2(ctx); if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { log_crypto_err("Error in SSL_CTX verify locations"); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(verifypem)); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); } SSL_CTX_set_alpn_select_cb(ctx, server_alpn_cb, NULL); return ctx; } SSL_CTX* server_tls_ctx_create(struct nsd* nsd, char* verifypem, char* ocspfile) { char *key, *pem; SSL_CTX *ctx; key = nsd->options->tls_service_key; pem = nsd->options->tls_service_pem; if(!key || key[0] == 0) { log_msg(LOG_ERR, "error: no tls-service-key file specified"); return NULL; } if(!pem || pem[0] == 0) { log_msg(LOG_ERR, "error: no tls-service-pem file specified"); return NULL; } /* NOTE:This mimics the existing code in Unbound 1.5.1 by supporting SSL but * raft-ietf-uta-tls-bcp-08 recommends only using TLSv1.2*/ ctx = server_tls_ctx_setup(key, pem, verifypem); if(!ctx) { log_msg(LOG_ERR, "could not setup server TLS context"); return NULL; } if(ocspfile && ocspfile[0]) { if ((ocspdata_len = get_ocsp(ocspfile, &ocspdata)) < 0) { log_crypto_err("Error reading OCSPfile"); SSL_CTX_free(ctx); return NULL; } else { VERBOSITY(2, (LOG_INFO, "ocspfile %s loaded", ocspfile)); if(!SSL_CTX_set_tlsext_status_cb(ctx, add_ocsp_data_cb)) { log_crypto_err("Error in SSL_CTX_set_tlsext_status_cb"); SSL_CTX_free(ctx); return NULL; } } } return ctx; } /* check if tcp_handler_accept_data created for TLS dedicated port */ int using_tls_port(struct sockaddr* addr, const char* tls_port) { in_port_t port = 0; if (addr->sa_family == AF_INET) port = ((struct sockaddr_in*)addr)->sin_port; #ifndef HAVE_STRUCT_SOCKADDR_IN6 else port = ((struct sockaddr_in6*)addr)->sin6_port; #endif /* HAVE_STRUCT_SOCKADDR_IN6 */ if (atoi(tls_port) == ntohs(port)) return 1; return 0; } #endif /* pass timeout=-1 for blocking. Returns size, 0, -1(err), or -2(timeout) */ ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout) { uint8_t* buf = (uint8_t*) p; ssize_t total = 0; struct pollfd fd; memset(&fd, 0, sizeof(fd)); fd.fd = s; fd.events = POLLIN; while( total < sz) { ssize_t ret; ret = poll(&fd, 1, (timeout==-1)?-1:timeout*1000); if(ret == -1) { if(errno == EAGAIN) /* blocking read */ continue; if(errno == EINTR) { if(nsd && (nsd->signal_hint_quit || nsd->signal_hint_shutdown)) return -1; /* other signals can be handled later */ continue; } /* some error */ return -1; } if(ret == 0) { /* operation timed out */ return -2; } ret = read(s, buf+total, sz-total); if(ret == -1) { if(errno == EAGAIN) /* blocking read */ continue; if(errno == EINTR) { if(nsd && (nsd->signal_hint_quit || nsd->signal_hint_shutdown)) return -1; /* other signals can be handled later */ continue; } /* some error */ return -1; } if(ret == 0) { /* closed connection! */ return 0; } total += ret; } return total; } static void reload_process_non_xfr_tasks(struct nsd* nsd, udb_ptr* xfrs2process, udb_ptr* last_task) { udb_ptr t, next, xfr_tail; udb_base* u = nsd->task[nsd->mytask]; udb_ptr_init(&next, u); udb_ptr_init(&xfr_tail, u); udb_ptr_new(&t, u, udb_base_get_userdata(u)); udb_base_set_userdata(u, 0); /* Execute all tasks except of type "task_apply_xfr". */ while(!udb_ptr_is_null(&t)) { /* store next in list so this one can be deleted or reused */ udb_ptr_set_rptr(&next, u, &TASKLIST(&t)->next); udb_rptr_zero(&TASKLIST(&t)->next, u); if(TASKLIST(&t)->task_type != task_apply_xfr) { /* process task t */ /* append results for task t and update last_task */ task_process_in_reload(nsd, u, last_task, &t); } else if(udb_ptr_is_null(xfrs2process)) { udb_ptr_set_ptr( xfrs2process, u, &t); udb_ptr_set_ptr(&xfr_tail, u, &t); } else { udb_rptr_set_ptr(&TASKLIST(&xfr_tail)->next, u, &t); udb_ptr_set_ptr(&xfr_tail, u, &t); } /* go to next */ udb_ptr_set_ptr(&t, u, &next); } /* t and next are already unlinked (because they are null) */ udb_ptr_unlink(&xfr_tail, u); } static size_t reload_process_xfr_tasks(struct nsd* nsd, int cmdsocket, udb_ptr* xfrs2process) { sig_atomic_t cmd = NSD_QUIT_SYNC; udb_ptr next; udb_base* u = nsd->task[nsd->mytask]; size_t xfrs_processed = 0; udb_ptr_init(&next, u); while(!udb_ptr_is_null(xfrs2process)) { /* store next in list so this one can be deleted or reused */ udb_ptr_set_rptr(&next, u, &TASKLIST(xfrs2process)->next); udb_rptr_zero(&TASKLIST(xfrs2process)->next, u); /* process xfr task at xfrs2process */ assert(TASKLIST(xfrs2process)->task_type == task_apply_xfr); task_process_apply_xfr(nsd, u, xfrs2process); xfrs_processed += 1; /* go to next */ udb_ptr_set_ptr(xfrs2process, u, &next); /* if the "old-main" has quit, we must quit too, poll the fd for cmds */ if(block_read(nsd, cmdsocket, &cmd, sizeof(cmd), 0) != sizeof(cmd)) ; /* pass */ else if (cmd != NSD_QUIT) DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from old-main %d", (int)cmd)); else { udb_ptr_unlink(&next, u); DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd")); /* unlink files of remainder of tasks */ while(!udb_ptr_is_null(xfrs2process)) { assert(TASKLIST(xfrs2process)->task_type == task_apply_xfr); xfrd_unlink_xfrfile(nsd, TASKLIST(xfrs2process)->yesno); udb_ptr_set_rptr(xfrs2process, u, &TASKLIST(xfrs2process)->next); } exit(0); } } /* xfrs2process and next are already unlinked (because they are null) */ return xfrs_processed; } static void server_verify(struct nsd *nsd, int cmdsocket, struct sigaction* old_sigchld); struct quit_sync_event_data { struct event_base* base; size_t read; union { uint8_t buf[sizeof(sig_atomic_t)]; sig_atomic_t cmd; } to_read; }; static void server_reload_handle_sigchld(int sig, short event, void* ATTR_UNUSED(arg)) { assert(sig == SIGCHLD); assert(event & EV_SIGNAL); /* reap the exited old-serve child(s) */ while(waitpid(-1, NULL, WNOHANG) > 0) { /* pass */ } } static void server_reload_handle_quit_sync_ack(int cmdsocket, short event, void* arg) { struct quit_sync_event_data* cb_data = (struct quit_sync_event_data*)arg; ssize_t r; if(event & EV_TIMEOUT) { sig_atomic_t cmd = NSD_QUIT_SYNC; DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending command from " "reload to old-main: %s", strerror(errno)); } /* Wait for cmdsocket to become readable or for next timeout, * (this works because event is added EV_TIMEOUT|EV_PERSIST). */ return; } assert(event & EV_READ); assert(cb_data->read < sizeof(cb_data->to_read.cmd)); r = read(cmdsocket, cb_data->to_read.buf + cb_data->read, sizeof(cb_data->to_read.cmd) - cb_data->read); if(r == 0) { DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "reload: old-main quit during quit sync")); cb_data->to_read.cmd = NSD_RELOAD; } else if(r == -1) { if(errno == EAGAIN || errno == EINTR) return; log_msg(LOG_ERR, "reload: could not wait for parent to quit: " "%s", strerror(errno)); cb_data->to_read.cmd = NSD_RELOAD; } else if (cb_data->read + r < sizeof(cb_data->to_read.cmd)) { /* More to read */ cb_data->read += r; return; } else { assert(cb_data->read + r == sizeof(cb_data->to_read.cmd)); DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d", (int)cb_data->to_read.cmd)); } /* Done */ event_base_loopexit(cb_data->base, NULL); } /* * Reload the database, stop parent, re-fork children and continue. * as server_main. */ static void server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, int cmdsocket, udb_ptr* xfrs2process, udb_ptr* last_task) { pid_t mypid; sig_atomic_t cmd; struct sigaction old_sigchld, ign_sigchld; struct radnode* node; zone_type* zone; enum soainfo_hint hint; struct quit_sync_event_data cb_data; struct event signal_event, cmd_event; struct timeval reload_sync_timeout; size_t xfrs_processed = 0; /* For swapping filedescriptors from the serve childs to the xfrd * and/or the dnstap collector */ int *swap_fd_send; /* ignore SIGCHLD from the previous server_main that used this pid */ memset(&ign_sigchld, 0, sizeof(ign_sigchld)); ign_sigchld.sa_handler = SIG_IGN; sigaction(SIGCHLD, &ign_sigchld, &old_sigchld); #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->cpuset); } #endif /* see what tasks we got from xfrd */ xfrs_processed = reload_process_xfr_tasks(nsd, cmdsocket, xfrs2process); #ifndef NDEBUG if(nsd_debug_level >= 1) region_log_stats(nsd->db->region); #endif /* NDEBUG */ initialize_dname_compression_tables(nsd); #ifdef BIND8_STATS /* Restart dumping stats if required. */ time(&nsd->st->boot); set_bind8_alarm(nsd); /* Switch to a different set of stat array for new server processes, * because they can briefly coexist with the old processes. They * have their own stat structure. */ nsd->stat_current = (nsd->stat_current==0?1:0); #endif #ifdef USE_ZONE_STATS server_zonestat_realloc(nsd); /* realloc for new children */ server_zonestat_switch(nsd); #endif if(nsd->options->verify_enable) { #ifdef RATELIMIT /* allocate resources for rate limiting. use a slot that is guaranteed not mapped to a file so no persistent data is overwritten */ rrl_init(nsd->child_count + 1); #endif /* spin-up server and execute verifiers for each zone */ server_verify(nsd, cmdsocket, &old_sigchld); #ifdef RATELIMIT /* deallocate rate limiting resources */ rrl_deinit(nsd->child_count + 1); #endif } if(xfrs_processed) for( node = radix_first(nsd->db->zonetree) ; node != NULL; node = radix_next(node)) { zone = (zone_type *)node->elem; if(zone->is_updated) { if(zone->is_bad) { nsd->mode = NSD_RELOAD_FAILED; hint = soainfo_bad; } else { hint = soainfo_ok; } /* update(s), verified or not, possibly with subsequent skipped update(s). skipped update(s) are picked up by failed update check in xfrd */ task_new_soainfo(nsd->task[nsd->mytask], last_task, zone, hint); } else if(zone->is_skipped) { /* corrupt or inconsistent update without preceding update(s), communicate soainfo_gone */ task_new_soainfo(nsd->task[nsd->mytask], last_task, zone, soainfo_gone); } zone->is_updated = 0; zone->is_skipped = 0; } if(nsd->mode == NSD_RELOAD_FAILED) { exit(NSD_RELOAD_FAILED); } /* listen for the signals of failed children again */ sigaction(SIGCHLD, &old_sigchld, NULL); #ifdef USE_DNSTAP if (nsd->dt_collector) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: swap dnstap collector pipes")); /* Swap fd_send with fd_swap so old serve child and new serve * childs will not write to the same pipe ends simultaneously */ swap_fd_send = nsd->dt_collector_fd_send; nsd->dt_collector_fd_send = nsd->dt_collector_fd_swap; nsd->dt_collector_fd_swap = swap_fd_send; } #endif swap_fd_send = nsd->serve2xfrd_fd_send; nsd->serve2xfrd_fd_send = nsd->serve2xfrd_fd_swap; nsd->serve2xfrd_fd_swap = swap_fd_send; /* Start new child processes */ if (server_start_children(nsd, server_region, netio, &nsd-> xfrd_listener->fd) != 0) { send_children_quit(nsd); exit(1); } /* if the old-main has quit, we must quit too, poll the fd for cmds */ if(block_read(nsd, cmdsocket, &cmd, sizeof(cmd), 0) == sizeof(cmd)) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", (int)cmd)); if(cmd == NSD_QUIT) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd")); send_children_quit(nsd); exit(0); } } /* Send quit command to old-main: blocking, wait for receipt. * The old-main process asks the old-serve processes to quit, however * if a reload succeeded before, this process is the parent of the * old-serve processes, so we need to reap the children for it. */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); cmd = NSD_QUIT_SYNC; if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending command from reload to oldnsd: %s", strerror(errno)); } reload_sync_timeout.tv_sec = RELOAD_SYNC_TIMEOUT; reload_sync_timeout.tv_usec = 0; cb_data.base = nsd_child_event_base(); cb_data.to_read.cmd = cmd; cb_data.read = 0; event_set(&signal_event, SIGCHLD, EV_SIGNAL|EV_PERSIST, server_reload_handle_sigchld, NULL); if(event_base_set(cb_data.base, &signal_event) != 0 || signal_add(&signal_event, NULL) != 0) { log_msg(LOG_ERR, "NSD quit sync: could not add signal event"); } event_set(&cmd_event, cmdsocket, EV_READ|EV_TIMEOUT|EV_PERSIST, server_reload_handle_quit_sync_ack, &cb_data); if(event_base_set(cb_data.base, &cmd_event) != 0 || event_add(&cmd_event, &reload_sync_timeout) != 0) { log_msg(LOG_ERR, "NSD quit sync: could not add command event"); } /* short-lived main loop */ event_base_dispatch(cb_data.base); /* remove command and signal event handlers */ event_del(&cmd_event); signal_del(&signal_event); /* restore the ordinary signal handler for SIGCHLD */ sigaction(SIGCHLD, &old_sigchld, NULL); event_base_free(cb_data.base); cmd = cb_data.to_read.cmd; if(cmd == NSD_QUIT) { /* small race condition possible here, parent got quit cmd. */ send_children_quit(nsd); exit(1); } assert(cmd == NSD_RELOAD); udb_ptr_set(last_task, nsd->task[nsd->mytask], 0); task_process_sync(nsd->task[nsd->mytask]); #ifdef USE_ZONE_STATS server_zonestat_realloc(nsd); /* realloc for next children */ #endif /* send soainfo to the xfrd process, signal it that reload is done, * it picks up the taskudb */ cmd = NSD_RELOAD_DONE; if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending reload_done xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } /* try to reopen file */ if (nsd->file_rotation_ok) log_reopen(nsd->log_filename, 1); /* exit reload, continue as new server_main */ } /* * Get the mode depending on the signal hints that have been received. * Multiple signal hints can be received and will be handled in turn. */ static sig_atomic_t server_signal_mode(struct nsd *nsd) { if(nsd->signal_hint_quit) { nsd->signal_hint_quit = 0; return NSD_QUIT; } else if(nsd->signal_hint_shutdown) { nsd->signal_hint_shutdown = 0; return NSD_SHUTDOWN; } else if(nsd->signal_hint_child) { nsd->signal_hint_child = 0; return NSD_REAP_CHILDREN; } else if(nsd->signal_hint_reload) { nsd->signal_hint_reload = 0; return NSD_RELOAD; } else if(nsd->signal_hint_reload_hup) { nsd->signal_hint_reload_hup = 0; return NSD_RELOAD_REQ; } else if(nsd->signal_hint_stats) { nsd->signal_hint_stats = 0; #ifdef BIND8_STATS set_bind8_alarm(nsd); #endif return NSD_STATS; } else if(nsd->signal_hint_statsusr) { nsd->signal_hint_statsusr = 0; return NSD_STATS; } return NSD_RUN; } /* * The main server simply waits for signals and child processes to * terminate. Child processes are restarted as necessary. */ void server_main(struct nsd *nsd) { region_type *server_region = region_create(xalloc, free); netio_type *netio = netio_create(server_region); netio_handler_type reload_listener; int reload_sockets[2] = {-1, -1}; /* pointer to the xfr tasks that will be processed in a second pass */ udb_ptr xfrs2process; /* pointer to results of task processing */ udb_ptr last_task; struct timespec timeout_spec; int status; pid_t child_pid; pid_t reload_pid = -1; sig_atomic_t mode; /* Ensure we are the main process */ assert(nsd->server_kind == NSD_SERVER_MAIN); /* Add listener for the XFRD process */ netio_add_handler(netio, nsd->xfrd_listener); #ifdef BIND8_STATS nsd->st = &nsd->stat_map[0]; nsd->st->db_disk = 0; nsd->st->db_mem = region_get_mem(nsd->db->region); #endif memset(&xfrs2process, 0, sizeof(xfrs2process)); memset(&last_task, 0, sizeof(last_task)); /* Start the child processes that handle incoming queries */ if (server_start_children(nsd, server_region, netio, &nsd->xfrd_listener->fd) != 0) { send_children_quit(nsd); exit(1); } reload_listener.fd = -1; /* This_child MUST be 0, because this is the parent process */ assert(nsd->this_child == 0); /* Run the server until we get a shutdown signal */ while ((mode = nsd->mode) != NSD_SHUTDOWN) { /* Did we receive a signal that changes our mode? */ if(mode == NSD_RUN) { nsd->mode = mode = server_signal_mode(nsd); } switch (mode) { case NSD_RUN: /* see if any child processes terminated */ while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { int is_child = delete_child_pid(nsd, child_pid); if (is_child != -1 && nsd->children[is_child].need_to_exit) { if(nsd->children[is_child].child_fd == -1) nsd->children[is_child].has_exited = 1; parent_check_all_children_exited(nsd); } else if(is_child != -1) { log_msg(LOG_WARNING, "server %d died unexpectedly with status %d, restarting", (int) child_pid, status); restart_child_servers(nsd, server_region, netio, &nsd->xfrd_listener->fd); } else if (child_pid == reload_pid) { sig_atomic_t cmd = NSD_RELOAD_FAILED; pid_t mypid; log_msg(LOG_WARNING, "Reload process %d failed with status %d, continuing with old database", (int) child_pid, status); #ifdef HAVE_SETPROCTITLE setproctitle("main"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("main"); #endif reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); netio_remove_handler(netio, &reload_listener); reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; task_process_sync(nsd->task[nsd->mytask]); /* inform xfrd reload attempt ended */ if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems " "sending SOAEND to xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } #ifdef USE_DNSTAP } else if(nsd->dt_collector && child_pid == nsd->dt_collector->dt_pid) { log_msg(LOG_WARNING, "dnstap-collector %d terminated with status %d", (int) child_pid, status); if(nsd->dt_collector) { dt_collector_close(nsd->dt_collector, nsd); dt_collector_destroy(nsd->dt_collector, nsd); nsd->dt_collector = NULL; } /* Only respawn a crashed (or exited) * dnstap-collector when not reloading, * to not induce a reload during a * reload (which would seriously * disrupt nsd procedures and lead to * unpredictable results)! * * This will *leave* a dnstap-collector * process terminated, but because * signalling of the reload process to * the main process to respawn in this * situation will be cumbersome, and * because this situation is so * specific (and therefore hopefully * extremely rare or non-existing at * all), plus the fact that we are left * with a perfectly function NSD * (besides not logging dnstap * messages), I consider it acceptable * to leave this unresolved. */ if(reload_pid == -1 && nsd->options->dnstap_enable) { nsd->dt_collector = dt_collector_create(nsd); dt_collector_start(nsd->dt_collector, nsd); nsd->mode = NSD_RELOAD_REQ; } #endif } else if(status != 0) { /* check for status, because we get * the old-servermain because reload * is the process-parent of old-main, * and we get older server-processes * that are exiting after a reload */ log_msg(LOG_WARNING, "process %d terminated with status %d", (int) child_pid, status); } } if (child_pid == -1) { if (errno == EINTR) { continue; } if (errno != ECHILD) log_msg(LOG_WARNING, "wait failed: %s", strerror(errno)); } if (nsd->mode != NSD_RUN) break; /* timeout to collect processes. In case no sigchild happens. */ timeout_spec.tv_sec = 1; timeout_spec.tv_nsec = 0; /* listen on ports, timeout for collecting terminated children */ if(netio_dispatch(netio, &timeout_spec, 0) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "netio_dispatch failed: %s", strerror(errno)); } } if(nsd->restart_children) { restart_child_servers(nsd, server_region, netio, &nsd->xfrd_listener->fd); nsd->restart_children = 0; } if(nsd->reload_failed) { sig_atomic_t cmd = NSD_RELOAD_FAILED; pid_t mypid; nsd->reload_failed = 0; log_msg(LOG_WARNING, "Reload process %d failed, continuing with old database", (int) reload_pid); #ifdef HAVE_SETPROCTITLE setproctitle("main"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("main"); #endif reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); netio_remove_handler(netio, &reload_listener); reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; task_process_sync(nsd->task[nsd->mytask]); /* inform xfrd reload attempt ended */ if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems " "sending SOAEND to xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } } break; case NSD_RELOAD_REQ: { sig_atomic_t cmd = NSD_RELOAD_REQ; log_msg(LOG_WARNING, "SIGHUP received, reloading..."); DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send reload_req to xfrd")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send " "reload_req to xfrd: %s", strerror(errno)); } nsd->mode = NSD_RUN; } break; case NSD_RELOAD: /* Continue to run nsd after reload */ nsd->mode = NSD_RUN; DEBUG(DEBUG_IPC,1, (LOG_INFO, "reloading...")); if (reload_pid != -1) { log_msg(LOG_WARNING, "Reload already in progress (pid = %d)", (int) reload_pid); break; } /* switch the mytask to keep track of who owns task*/ nsd->mytask = 1 - nsd->mytask; if (socketpair(AF_UNIX, SOCK_STREAM, 0, reload_sockets) == -1) { log_msg(LOG_ERR, "reload failed on socketpair: %s", strerror(errno)); reload_pid = -1; break; } /* Execute the tasks that cannot fail */ #ifdef HAVE_SETPROCTITLE setproctitle("load"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("load"); #endif /* Already process the non xfr tasks, so that a failed * transfer (which can exit) will not nullify the * effects of the other tasks that will not exit. */ task_remap(nsd->task[nsd->mytask]); udb_ptr_init(&xfrs2process, nsd->task[nsd->mytask]); udb_ptr_init(&last_task , nsd->task[nsd->mytask]); /* last_task and xfrs2process MUST be unlinked in all * possible branches of the fork() below. * server_reload() will unlink them, but for failed * fork and for the "old-main" (child) process, we MUST * unlink them in the case statement below. * Unlink by setting the value to 0, because * reload_process_non_xfr_tasks() may clear (and * implicitly unlink) xfrs2process. */ reload_process_non_xfr_tasks(nsd, &xfrs2process , &last_task); /* Do actual reload */ reload_pid = fork(); switch (reload_pid) { case -1: log_msg(LOG_ERR, "fork failed: %s", strerror(errno)); udb_ptr_set(&last_task, nsd->task[nsd->mytask], 0); udb_ptr_set(&xfrs2process, nsd->task[nsd->mytask], 0); break; default: /* PARENT */ close(reload_sockets[0]); server_reload(nsd, server_region, netio , reload_sockets[1] , &xfrs2process , &last_task); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload exited to become new main")); close(reload_sockets[1]); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload closed")); /* drop stale xfrd ipc data */ ((struct ipc_handler_conn_data*)nsd-> xfrd_listener->user_data) ->conn->is_reading = 0; reload_pid = -1; reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload resetup; run")); break; case 0: /* CHILD */ /* server_main keep running until NSD_QUIT_SYNC * received from reload. */ close(reload_sockets[1]); #ifdef HAVE_SETPROCTITLE setproctitle("old-main"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("old-main"); #endif udb_ptr_set(&last_task, nsd->task[nsd->mytask], 0); udb_ptr_set(&xfrs2process, nsd->task[nsd->mytask], 0); reload_listener.fd = reload_sockets[0]; reload_listener.timeout = NULL; reload_listener.user_data = nsd; reload_listener.event_types = NETIO_EVENT_READ; reload_listener.event_handler = parent_handle_reload_command; /* listens to Quit */ netio_add_handler(netio, &reload_listener); reload_pid = getppid(); break; } if(reload_pid == -1) { /* Reset proctitle after "load" process exited * or when fork() failed */ #ifdef HAVE_SETPROCTITLE setproctitle("main"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("main"); #endif } break; case NSD_QUIT_SYNC: /* synchronisation of xfrd, parent and reload */ if(!nsd->quit_sync_done && reload_listener.fd != -1) { sig_atomic_t cmd = NSD_RELOAD; /* stop xfrd ipc writes in progress */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send indication reload")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send reload " "indication to xfrd: %s", strerror(errno)); } /* wait for ACK from xfrd */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: wait ipc reply xfrd")); nsd->quit_sync_done = 1; } nsd->mode = NSD_RUN; break; case NSD_QUIT: /* silent shutdown during reload */ if(reload_listener.fd != -1) { /* acknowledge the quit, to sync reload that we will really quit now */ sig_atomic_t cmd = NSD_RELOAD; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc ack reload")); if(!write_socket(reload_listener.fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: " "could not ack quit: %s", strerror(errno)); } close(reload_listener.fd); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "server_main: shutdown sequence")); /* only quit children after xfrd has acked */ send_children_quit(nsd); #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(server_region); #endif server_shutdown(nsd); /* ENOTREACH */ break; case NSD_SHUTDOWN: break; case NSD_REAP_CHILDREN: /* continue; wait for child in run loop */ nsd->mode = NSD_RUN; break; case NSD_STATS: #ifdef BIND8_STATS set_children_stats(nsd); #endif nsd->mode = NSD_RUN; break; default: log_msg(LOG_WARNING, "NSD main server mode invalid: %d", (int)nsd->mode); nsd->mode = NSD_RUN; break; } } log_msg(LOG_WARNING, "signal received, shutting down..."); /* close opened ports to avoid race with restart of nsd */ server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); daemon_remote_close(nsd->rc); send_children_quit_and_wait(nsd); /* Unlink it if possible... */ unlinkpid(nsd->pidfile, nsd->username); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef BIND8_STATS server_stat_free(nsd); #endif #ifdef USE_DNSTAP dt_collector_close(nsd->dt_collector, nsd); #endif if(reload_listener.fd != -1) { sig_atomic_t cmd = NSD_QUIT; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send quit to reload-process")); if(!write_socket(reload_listener.fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send quit to reload: %s", strerror(errno)); } fsync(reload_listener.fd); close(reload_listener.fd); /* wait for reload to finish processing */ while(1) { if(waitpid(reload_pid, NULL, 0) == -1) { if(errno == EINTR) continue; if(errno == ECHILD) break; log_msg(LOG_ERR, "waitpid(reload %d): %s", (int)reload_pid, strerror(errno)); } break; } } if(nsd->xfrd_listener->fd != -1) { /* complete quit, stop xfrd */ sig_atomic_t cmd = NSD_QUIT; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send quit to xfrd")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send quit to xfrd: %s", strerror(errno)); } fsync(nsd->xfrd_listener->fd); close(nsd->xfrd_listener->fd); (void)kill(nsd->pid, SIGTERM); } #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(server_region); #endif server_shutdown(nsd); } static query_state_type server_process_query(struct nsd *nsd, struct query *query, uint32_t *now_p) { return query_process(query, nsd, now_p); } static query_state_type server_process_query_udp(struct nsd *nsd, struct query *query, uint32_t *now_p) { #ifdef RATELIMIT if(query_process(query, nsd, now_p) != QUERY_DISCARDED) { if(query->edns.cookie_status != COOKIE_VALID && query->edns.cookie_status != COOKIE_VALID_REUSE && rrl_process_query(query)) return rrl_slip(query); else return QUERY_PROCESSED; } return QUERY_DISCARDED; #else return query_process(query, nsd, now_p); #endif } const char* nsd_event_vs(void) { #ifdef USE_MINI_EVENT return ""; #else return event_get_version(); #endif } #if !defined(USE_MINI_EVENT) && defined(EV_FEATURE_BACKENDS) static const char* ub_ev_backend2str(int b) { switch(b) { case EVBACKEND_SELECT: return "select"; case EVBACKEND_POLL: return "poll"; case EVBACKEND_EPOLL: return "epoll"; case EVBACKEND_KQUEUE: return "kqueue"; case EVBACKEND_DEVPOLL: return "devpoll"; case EVBACKEND_PORT: return "evport"; } return "unknown"; } #endif const char* nsd_event_method(void) { #ifdef USE_MINI_EVENT return "select"; #else struct event_base* b = nsd_child_event_base(); const char* m; # ifdef EV_FEATURE_BACKENDS m = ub_ev_backend2str(ev_backend((struct ev_loop*)b)); # elif defined(HAVE_EVENT_BASE_GET_METHOD) m = event_base_get_method(b); # else m = "?"; # endif # ifdef MEMCLEAN event_base_free(b); # endif return m; #endif } struct event_base* nsd_child_event_base(void) { struct event_base* base; #ifdef USE_MINI_EVENT static time_t secs; static struct timeval now; base = event_init(&secs, &now); #else # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) /* libev */ base = (struct event_base *)ev_default_loop(EVFLAG_AUTO); # else /* libevent */ # ifdef HAVE_EVENT_BASE_NEW base = event_base_new(); # else base = event_init(); # endif # endif #endif return base; } static void add_udp_handler( struct nsd *nsd, struct nsd_socket *sock, struct udp_handler_data *data) { struct event *handler = &data->event; data->nsd = nsd; data->socket = sock; if(nsd->options->proxy_protocol_port && sockaddr_uses_proxy_protocol_port(nsd->options, (struct sockaddr *)&sock->addr.ai_addr)) { data->pp2_enabled = 1; } memset(handler, 0, sizeof(*handler)); event_set(handler, sock->s, EV_PERSIST|EV_READ, handle_udp, data); if(event_base_set(nsd->event_base, handler) != 0) log_msg(LOG_ERR, "nsd udp: event_base_set failed"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "nsd udp: event_add failed"); } void add_tcp_handler( struct nsd *nsd, struct nsd_socket *sock, struct tcp_accept_handler_data *data) { struct event *handler = &data->event; data->nsd = nsd; data->socket = sock; if(nsd->options->proxy_protocol_port && sockaddr_uses_proxy_protocol_port(nsd->options, (struct sockaddr *)&sock->addr.ai_addr)) { data->pp2_enabled = 1; } #ifdef HAVE_SSL if (nsd->tls_ctx && nsd->options->tls_port && using_tls_port((struct sockaddr *)&sock->addr.ai_addr, nsd->options->tls_port)) { data->tls_accept = 1; if(verbosity >= 2) { char buf[48]; addrport2str((void*)(struct sockaddr_storage*)&sock->addr.ai_addr, buf, sizeof(buf)); VERBOSITY(5, (LOG_NOTICE, "setup TCP for TLS service on interface %s", buf)); } } else { data->tls_accept = 0; } if (nsd->tls_auth_ctx && nsd->options->tls_auth_port && using_tls_port((struct sockaddr *)&sock->addr.ai_addr, nsd->options->tls_auth_port)) { data->tls_auth_accept = 1; if(verbosity >= 2) { char buf[48]; addrport2str((void*)(struct sockaddr_storage*)&sock->addr.ai_addr, buf, sizeof(buf)); VERBOSITY(4, (LOG_NOTICE, "setup TCP for TLS-AUTH service on interface %s", buf)); } } else { data->tls_auth_accept = 0; } #endif memset(handler, 0, sizeof(*handler)); event_set(handler, sock->s, EV_PERSIST|EV_READ, handle_tcp_accept, data); if(event_base_set(nsd->event_base, handler) != 0) log_msg(LOG_ERR, "nsd tcp: event_base_set failed"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "nsd tcp: event_add failed"); data->event_added = 1; } /* * Serve DNS request to verifiers (short-lived) */ static void server_verify(struct nsd *nsd, int cmdsocket, struct sigaction* old_sigchld) { size_t size = 0; struct event cmd_event, signal_event, exit_event; struct zone *zone; assert(nsd != NULL); zone = verify_next_zone(nsd, NULL); if(zone == NULL) return; nsd->server_region = region_create(xalloc, free); nsd->event_base = nsd_child_event_base(); nsd->next_zone_to_verify = zone; nsd->verifier_count = 0; nsd->verifier_limit = nsd->options->verifier_count; size = sizeof(struct verifier) * nsd->verifier_limit; if(pipe(nsd->verifier_pipe) == -1) { log_msg(LOG_ERR, "verify: could not create pipe: %s", strerror(errno)); goto fail_pipe; } fcntl(nsd->verifier_pipe[0], F_SETFD, FD_CLOEXEC); fcntl(nsd->verifier_pipe[1], F_SETFD, FD_CLOEXEC); nsd->verifiers = region_alloc_zero(nsd->server_region, size); for(size_t i = 0; i < nsd->verifier_limit; i++) { nsd->verifiers[i].nsd = nsd; nsd->verifiers[i].zone = NULL; nsd->verifiers[i].pid = -1; nsd->verifiers[i].output_stream.fd = -1; nsd->verifiers[i].output_stream.priority = LOG_INFO; nsd->verifiers[i].error_stream.fd = -1; nsd->verifiers[i].error_stream.priority = LOG_ERR; } event_set(&cmd_event, cmdsocket, EV_READ|EV_PERSIST, verify_handle_command, nsd); if(event_base_set(nsd->event_base, &cmd_event) != 0 || event_add(&cmd_event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add command event"); goto fail; } event_set(&signal_event, SIGCHLD, EV_SIGNAL|EV_PERSIST, verify_handle_signal, nsd); if(event_base_set(nsd->event_base, &signal_event) != 0 || signal_add(&signal_event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add signal event"); goto fail; } event_set(&exit_event, nsd->verifier_pipe[0], EV_READ|EV_PERSIST, verify_handle_exit, nsd); if(event_base_set(nsd->event_base, &exit_event) != 0 || event_add(&exit_event, NULL) != 0) { log_msg(LOG_ERR, "verify: could not add exit event"); goto fail; } memset(msgs, 0, sizeof(msgs)); for (int i = 0; i < NUM_RECV_PER_SELECT; i++) { queries[i] = query_create(nsd->server_region, compressed_dname_offsets, compression_table_size, compressed_dnames); query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_base = buffer_begin(queries[i]->packet); iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; msgs[i].msg_hdr.msg_name = &queries[i]->remote_addr; msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } for (size_t i = 0; i < nsd->verify_ifs; i++) { struct udp_handler_data *data; data = region_alloc_zero( nsd->server_region, sizeof(*data)); add_udp_handler(nsd, &nsd->verify_udp[i], data); } tcp_accept_handler_count = nsd->verify_ifs; tcp_accept_handlers = region_alloc_array(nsd->server_region, nsd->verify_ifs, sizeof(*tcp_accept_handlers)); for (size_t i = 0; i < nsd->verify_ifs; i++) { struct tcp_accept_handler_data *data; data = &tcp_accept_handlers[i]; memset(data, 0, sizeof(*data)); add_tcp_handler(nsd, &nsd->verify_tcp[i], data); } while(nsd->next_zone_to_verify != NULL && nsd->verifier_count < nsd->verifier_limit) { verify_zone(nsd, nsd->next_zone_to_verify); nsd->next_zone_to_verify = verify_next_zone(nsd, nsd->next_zone_to_verify); } /* short-lived main loop */ event_base_dispatch(nsd->event_base); /* remove command and exit event handlers */ event_del(&exit_event); event_del(&cmd_event); assert(nsd->next_zone_to_verify == NULL || nsd->mode == NSD_QUIT); assert(nsd->verifier_count == 0 || nsd->mode == NSD_QUIT); signal_del(&signal_event); fail: sigaction(SIGCHLD, old_sigchld, NULL); close(nsd->verifier_pipe[0]); close(nsd->verifier_pipe[1]); fail_pipe: event_base_free(nsd->event_base); region_destroy(nsd->server_region); nsd->event_base = NULL; nsd->server_region = NULL; nsd->verifier_limit = 0; nsd->verifier_pipe[0] = -1; nsd->verifier_pipe[1] = -1; nsd->verifiers = NULL; } /* * Serve DNS requests. */ void server_child(struct nsd *nsd) { size_t i, from, numifs; region_type *server_region = region_create(xalloc, free); struct event_base* event_base = nsd_child_event_base(); sig_atomic_t mode; #ifdef USE_LOG_PROCESS_ROLE static char child_name[20]; #endif if(!event_base) { log_msg(LOG_ERR, "nsd server could not create event base"); exit(1); } nsd->event_base = event_base; nsd->server_region = server_region; #ifdef RATELIMIT rrl_init(nsd->this_child->child_num); #endif assert(nsd->server_kind != NSD_SERVER_MAIN); #ifdef HAVE_SETPROCTITLE setproctitle("server %d", nsd->this_child->child_num + 1); #endif #ifdef USE_LOG_PROCESS_ROLE snprintf(child_name, sizeof(child_name), "srv%d", nsd->this_child->child_num + 1); log_set_process_role(child_name); #endif DEBUG(DEBUG_IPC, 2, (LOG_INFO, "child process started")); #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->this_child->cpuset); } #endif #ifdef BIND8_STATS nsd->st = &nsd->stats_per_child[nsd->stat_current] [nsd->this_child->child_num]; nsd->st->boot = nsd->stat_map[0].boot; memcpy(&nsd->stat_proc, nsd->st, sizeof(nsd->stat_proc)); #endif if (!(nsd->server_kind & NSD_SERVER_TCP)) { server_close_all_sockets(nsd->tcp, nsd->ifs); } if (!(nsd->server_kind & NSD_SERVER_UDP)) { server_close_all_sockets(nsd->udp, nsd->ifs); } if (nsd->this_child->parent_fd != -1) { struct event *handler; struct ipc_handler_conn_data* user_data = (struct ipc_handler_conn_data*)region_alloc( server_region, sizeof(struct ipc_handler_conn_data)); user_data->nsd = nsd; user_data->conn = xfrd_tcp_create(server_region, QIOBUFSZ); handler = (struct event*) region_alloc( server_region, sizeof(*handler)); memset(handler, 0, sizeof(*handler)); event_set(handler, nsd->this_child->parent_fd, EV_PERSIST| EV_READ, child_handle_parent_command, user_data); if(event_base_set(event_base, handler) != 0) log_msg(LOG_ERR, "nsd ipcchild: event_base_set failed"); if(event_add(handler, NULL) != 0) 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) { int child = nsd->this_child->child_num; memset(msgs, 0, sizeof(msgs)); for (i = 0; i < NUM_RECV_PER_SELECT; i++) { queries[i] = query_create(server_region, compressed_dname_offsets, compression_table_size, compressed_dnames); query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_base = buffer_begin(queries[i]->packet); iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; msgs[i].msg_hdr.msg_name = &queries[i]->remote_addr; msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } for (i = 0; i < nsd->ifs; i++) { int listen; struct udp_handler_data *data; listen = nsd_bitset_isset(nsd->udp[i].servers, child); if(i >= from && i < (from + numifs) && listen) { data = region_alloc_zero( nsd->server_region, sizeof(*data)); add_udp_handler(nsd, &nsd->udp[i], data); } else { /* close sockets intended for other servers */ server_close_socket(&nsd->udp[i]); } } } /* * Keep track of all the TCP accept handlers so we can enable * and disable them based on the current number of active TCP * connections. */ if (nsd->server_kind & NSD_SERVER_TCP) { int child = nsd->this_child->child_num; tcp_accept_handler_count = numifs; tcp_accept_handlers = region_alloc_array(server_region, numifs, sizeof(*tcp_accept_handlers)); for (i = 0; i < nsd->ifs; i++) { int listen; struct tcp_accept_handler_data *data; listen = nsd_bitset_isset(nsd->tcp[i].servers, child); if(i >= from && i < (from + numifs) && listen) { data = &tcp_accept_handlers[i-from]; memset(data, 0, sizeof(*data)); add_tcp_handler(nsd, &nsd->tcp[i], data); } else { /* close sockets intended for other servers */ server_close_socket(&nsd->tcp[i]); } } } else { tcp_accept_handler_count = 0; } /* The main loop... */ while ((mode = nsd->mode) != NSD_QUIT) { if(mode == NSD_RUN) nsd->mode = mode = server_signal_mode(nsd); /* Do we need to do the statistics... */ if (mode == NSD_STATS) { #ifdef BIND8_STATS int p = nsd->st_period; nsd->st_period = 1; /* force stats printout */ /* Dump the statistics */ bind8_stats(nsd); nsd->st_period = p; #else /* !BIND8_STATS */ log_msg(LOG_NOTICE, "Statistics support not enabled at compile time."); #endif /* BIND8_STATS */ nsd->mode = NSD_RUN; } else if (mode == NSD_REAP_CHILDREN) { /* got signal, notify parent. parent reaps terminated children. */ if (nsd->this_child->parent_fd != -1) { sig_atomic_t parent_notify = NSD_REAP_CHILDREN; if (write(nsd->this_child->parent_fd, &parent_notify, sizeof(parent_notify)) == -1) { log_msg(LOG_ERR, "problems sending command from %d to parent: %s", (int) nsd->this_child->pid, strerror(errno)); } } else /* no parent, so reap 'em */ while (waitpid(-1, NULL, WNOHANG) > 0) ; nsd->mode = NSD_RUN; } else if(mode == NSD_RUN) { /* Wait for a query... */ if(event_base_loop(event_base, EVLOOP_ONCE) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "dispatch failed: %s", strerror(errno)); break; } } } else if(mode == NSD_QUIT) { /* ignore here, quit */ } else { log_msg(LOG_ERR, "mode bad value %d, back to service.", (int)mode); nsd->mode = NSD_RUN; } } service_remaining_tcp(nsd); #ifdef BIND8_STATS bind8_stats(nsd); #endif /* BIND8_STATS */ #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_deinit(nsd->this_child->child_num); #endif event_base_free(event_base); region_destroy(server_region); #endif server_shutdown(nsd); } static void remaining_tcp_timeout(int ATTR_UNUSED(fd), short event, void* arg) { int* timed_out = (int*)arg; assert(event & EV_TIMEOUT); (void)event; /* wake up the service tcp thread, note event is no longer * registered */ *timed_out = 1; } void service_remaining_tcp(struct nsd* nsd) { struct tcp_handler_data* p; struct event_base* event_base; /* check if it is needed */ if(nsd->current_tcp_count == 0 || tcp_active_list == NULL) return; VERBOSITY(5, (LOG_INFO, "service remaining TCP connections")); #ifdef USE_DNSTAP /* remove dnstap collector, we cannot write there because the new * child process is using the file descriptor, or the child * process after that. */ dt_collector_destroy(nsd->dt_collector, nsd); nsd->dt_collector = NULL; #endif /* setup event base */ event_base = nsd_child_event_base(); if(!event_base) { log_msg(LOG_ERR, "nsd remain tcp could not create event base"); return; } /* register tcp connections */ for(p = tcp_active_list; p != NULL; p = p->next) { struct timeval timeout; int fd = p->event.ev_fd; #ifdef USE_MINI_EVENT short event = p->event.ev_flags & (EV_READ|EV_WRITE); #else short event = p->event.ev_events & (EV_READ|EV_WRITE); #endif void (*fn)(int, short, void*); #ifdef HAVE_SSL if(p->tls) { if((event&EV_READ)) fn = handle_tls_reading; else fn = handle_tls_writing; } else if(p->tls_auth) { if((event&EV_READ)) fn = handle_tls_reading; else fn = handle_tls_writing; } else { #endif if((event&EV_READ)) fn = handle_tcp_reading; else fn = handle_tcp_writing; #ifdef HAVE_SSL } #endif p->tcp_no_more_queries = 1; /* set timeout to 3 seconds (previously 1/10 second) */ if(p->tcp_timeout > 3000) p->tcp_timeout = 3000; timeout.tv_sec = p->tcp_timeout / 1000; timeout.tv_usec = (p->tcp_timeout % 1000)*1000; event_del(&p->event); memset(&p->event, 0, sizeof(p->event)); event_set(&p->event, fd, EV_PERSIST | event | EV_TIMEOUT, fn, p); if(event_base_set(event_base, &p->event) != 0) log_msg(LOG_ERR, "event base set failed"); if(event_add(&p->event, &timeout) != 0) log_msg(LOG_ERR, "event add failed"); } /* handle it */ while(nsd->current_tcp_count > 0) { mode_t m = server_signal_mode(nsd); struct event timeout; struct timeval tv; int timed_out = 0; if(m == NSD_QUIT || m == NSD_SHUTDOWN || m == NSD_REAP_CHILDREN) { /* quit */ break; } /* timer */ /* have to do something every 3 seconds */ tv.tv_sec = 3; tv.tv_usec = 0; memset(&timeout, 0, sizeof(timeout)); event_set(&timeout, -1, EV_TIMEOUT, remaining_tcp_timeout, &timed_out); if(event_base_set(event_base, &timeout) != 0) log_msg(LOG_ERR, "remaintcp timer: event_base_set failed"); if(event_add(&timeout, &tv) != 0) log_msg(LOG_ERR, "remaintcp timer: event_add failed"); /* service loop */ if(event_base_loop(event_base, EVLOOP_ONCE) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "dispatch failed: %s", strerror(errno)); break; } } if(!timed_out) { event_del(&timeout); } else { /* timed out, quit */ VERBOSITY(5, (LOG_INFO, "service remaining TCP connections: timed out, quit")); break; } } #ifdef MEMCLEAN event_base_free(event_base); #endif /* continue to quit after return */ } /* Implement recvmmsg and sendmmsg if the platform does not. These functions * are always used, even if nonblocking operations are broken, in which case * NUM_RECV_PER_SELECT is defined to 1 (one). */ #if defined(HAVE_RECVMMSG) #define nsd_recvmmsg recvmmsg #else /* !HAVE_RECVMMSG */ static int nsd_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { unsigned int vpos = 0; ssize_t rcvd; /* timeout is ignored, ensure caller does not expect it to work */ assert(timeout == NULL); (void)timeout; while(vpos < vlen) { rcvd = recvfrom(sockfd, msgvec[vpos].msg_hdr.msg_iov->iov_base, msgvec[vpos].msg_hdr.msg_iov->iov_len, flags, msgvec[vpos].msg_hdr.msg_name, &msgvec[vpos].msg_hdr.msg_namelen); if(rcvd < 0) { break; } else { assert((unsigned long long)rcvd <= (unsigned long long)UINT_MAX); msgvec[vpos].msg_len = (unsigned int)rcvd; vpos++; } } if(vpos) { /* error will be picked up next time */ return (int)vpos; } else if(errno == 0) { return 0; } else if(errno == EAGAIN) { return 0; } return -1; } #endif /* HAVE_RECVMMSG */ #ifdef HAVE_SENDMMSG #define nsd_sendmmsg(...) sendmmsg(__VA_ARGS__) #else /* !HAVE_SENDMMSG */ static int nsd_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) { unsigned int vpos = 0; ssize_t snd; while(vpos < vlen) { assert(msgvec[vpos].msg_hdr.msg_iovlen == 1); snd = sendto(sockfd, msgvec[vpos].msg_hdr.msg_iov->iov_base, msgvec[vpos].msg_hdr.msg_iov->iov_len, flags, msgvec[vpos].msg_hdr.msg_name, msgvec[vpos].msg_hdr.msg_namelen); if(snd < 0) { break; } else { msgvec[vpos].msg_len = (unsigned int)snd; vpos++; } } if(vpos) { return (int)vpos; } else if(errno == 0) { return 0; } return -1; } #endif /* HAVE_SENDMMSG */ static int port_is_zero( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif ) { #ifdef INET6 if(addr->ss_family == AF_INET6) { return (((struct sockaddr_in6 *)addr)->sin6_port) == 0; } else if(addr->ss_family == AF_INET) { return (((struct sockaddr_in *)addr)->sin_port) == 0; } return 0; #else if(addr->sin_family == AF_INET) { return addr->sin_port == 0; } return 0; #endif } /* Parses the PROXYv2 header from buf and updates the struct. * Returns 1 on success, 0 on failure. */ static int consume_pp2_header(struct buffer* buf, struct query* q, int stream) { size_t size; struct pp2_header* header; int err = pp2_read_header(buffer_begin(buf), buffer_remaining(buf)); if(err) { VERBOSITY(4, (LOG_ERR, "proxy-protocol: could not parse " "PROXYv2 header: %s", pp_lookup_error(err))); return 0; } header = (struct pp2_header*)buffer_begin(buf); size = PP2_HEADER_SIZE + read_uint16(&header->len); if(size > buffer_limit(buf)) { VERBOSITY(4, (LOG_ERR, "proxy-protocol: not enough buffer " "size to read PROXYv2 header")); return 0; } if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) { /* A connection from the proxy itself. * No need to do anything with addresses. */ goto done; } if(header->fam_prot == PP2_UNSPEC_UNSPEC) { /* Unspecified family and protocol. This could be used for * health checks by proxies. * No need to do anything with addresses. */ goto done; } /* Read the proxied address */ switch(header->fam_prot) { case PP2_INET_STREAM: case PP2_INET_DGRAM: { struct sockaddr_in* addr = (struct sockaddr_in*)&q->client_addr; addr->sin_family = AF_INET; memmove(&addr->sin_addr.s_addr, &header->addr.addr4.src_addr, 4); memmove(&addr->sin_port, &header->addr.addr4.src_port, 2); q->client_addrlen = (socklen_t)sizeof(struct sockaddr_in); } /* Ignore the destination address; it should be us. */ break; #ifdef INET6 case PP2_INET6_STREAM: case PP2_INET6_DGRAM: { struct sockaddr_in6* addr = (struct sockaddr_in6*)&q->client_addr; memset(addr, 0, sizeof(*addr)); addr->sin6_family = AF_INET6; memmove(&addr->sin6_addr, header->addr.addr6.src_addr, 16); memmove(&addr->sin6_port, &header->addr.addr6.src_port, 2); q->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6); } /* Ignore the destination address; it should be us. */ break; #endif /* INET6 */ default: VERBOSITY(2, (LOG_ERR, "proxy-protocol: unsupported " "family and protocol 0x%x", (int)header->fam_prot)); return 0; } q->is_proxied = 1; done: if(!stream) { /* We are reading a whole packet; * Move the rest of the data to overwrite the PROXYv2 header */ /* XXX can we do better to avoid memmove? */ memmove(header, ((char*)header)+size, buffer_limit(buf)-size); buffer_set_limit(buf, buffer_limit(buf)-size); } return 1; } static void handle_udp(int fd, short event, void* arg) { struct udp_handler_data *data = (struct udp_handler_data *) arg; int received, sent, recvcount, i; struct query *q; uint32_t now = 0; if (!(event & EV_READ)) { return; } recvcount = nsd_recvmmsg(fd, msgs, NUM_RECV_PER_SELECT, 0, NULL); /* this printf strangely gave a performance increase on Linux */ /* printf("recvcount %d \n", recvcount); */ if (recvcount == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvmmsg failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } /* Simply no data available */ return; } for (i = 0; i < recvcount; i++) { loopstart: received = msgs[i].msg_len; queries[i]->remote_addrlen = msgs[i].msg_hdr.msg_namelen; queries[i]->client_addrlen = (socklen_t)sizeof(queries[i]->client_addr); queries[i]->is_proxied = 0; q = queries[i]; if (received == -1) { log_msg(LOG_ERR, "recvmmsg %d failed %s", i, strerror( #if defined(HAVE_RECVMMSG) msgs[i].msg_hdr.msg_flags #else errno #endif )); STATUP(data->nsd, rxerr); /* No zone statup */ query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; goto swap_drop; } /* Account... */ #ifdef BIND8_STATS if (data->socket->addr.ai_family == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->addr.ai_family == AF_INET6) { STATUP(data->nsd, qudp6); } #endif buffer_skip(q->packet, received); buffer_flip(q->packet); if(data->pp2_enabled && !consume_pp2_header(q->packet, q, 0)) { VERBOSITY(2, (LOG_ERR, "proxy-protocol: could not " "consume PROXYv2 header")); goto swap_drop; } if(!q->is_proxied) { q->client_addrlen = q->remote_addrlen; memmove(&q->client_addr, &q->remote_addr, q->remote_addrlen); } #ifdef USE_DNSTAP /* * sending UDP-query with server address (local) and client address to dnstap process */ log_addr("query from client", &q->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); if(verbosity >= 6 && q->is_proxied) log_addr("query via proxy", &q->remote_addr); dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &q->client_addr, q->client_addrlen, q->tcp, q->packet); #endif /* USE_DNSTAP */ /* Process and answer the query... */ if (server_process_query_udp(data->nsd, q, &now) != QUERY_DISCARDED) { if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, q->zone, nona); } #ifdef USE_ZONE_STATS if (data->socket->addr.ai_family == AF_INET) { ZTATUP(data->nsd, q->zone, qudp); } else if (data->socket->addr.ai_family == AF_INET6) { ZTATUP(data->nsd, q->zone, qudp6); } #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd, &now); buffer_flip(q->packet); iovecs[i].iov_len = buffer_remaining(q->packet); #ifdef BIND8_STATS /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(data->nsd, q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(data->nsd, q->zone, truncated); } #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* * sending UDP-response with server address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); log_addr("response to client", &q->client_addr); if(verbosity >= 6 && q->is_proxied) log_addr("response via proxy", &q->remote_addr); dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &q->client_addr, q->client_addrlen, q->tcp, q->packet, q->zone); #endif /* USE_DNSTAP */ } else { query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; swap_drop: STATUP(data->nsd, dropped); ZTATUP(data->nsd, q->zone, dropped); if(i != recvcount-1) { /* swap with last and decrease recvcount */ struct mmsghdr mtmp = msgs[i]; struct iovec iotmp = iovecs[i]; recvcount--; msgs[i] = msgs[recvcount]; iovecs[i] = iovecs[recvcount]; queries[i] = queries[recvcount]; msgs[recvcount] = mtmp; iovecs[recvcount] = iotmp; queries[recvcount] = q; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[recvcount].msg_hdr.msg_iov = &iovecs[recvcount]; goto loopstart; } else { recvcount --; } } } /* send until all are sent */ i = 0; while(iremote_addr) && verbosity < 3)) { const char* es = strerror(errno); char a[64]; addrport2str((void*)&queries[i]->remote_addr, a, sizeof(a)); log_msg(LOG_ERR, "sendmmsg skip invalid argument [0]=%s count=%d failed: %s", a, (int)(recvcount-i), es); } i += 1; continue; } /* don't log transient network full errors, unless * on higher verbosity */ if(!(errno == ENOBUFS && verbosity < 1) && #ifdef EWOULDBLOCK errno != EWOULDBLOCK && #endif errno != EAGAIN) { const char* es = strerror(errno); char a[64]; addrport2str((void*)&queries[i]->remote_addr, a, sizeof(a)); log_msg(LOG_ERR, "sendmmsg [0]=%s count=%d failed: %s", a, (int)(recvcount-i), es); } #ifdef BIND8_STATS data->nsd->st->txerr += recvcount-i; #endif /* BIND8_STATS */ break; } i += sent; } for(i=0; ipacket); msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } } #ifdef HAVE_SSL /* * Setup an event for the tcp handler. */ static void tcp_handler_setup_event(struct tcp_handler_data* data, void (*fn)(int, short, void *), int fd, short event) { struct timeval timeout; struct event_base* ev_base; timeout.tv_sec = data->nsd->tcp_timeout; timeout.tv_usec = 0L; ev_base = data->event.ev_base; event_del(&data->event); memset(&data->event, 0, sizeof(data->event)); event_set(&data->event, fd, event, fn, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add failed"); } #endif /* HAVE_SSL */ static void cleanup_tcp_handler(struct tcp_handler_data* data) { event_del(&data->event); #ifdef HAVE_SSL if(data->tls) { SSL_shutdown(data->tls); SSL_free(data->tls); data->tls = NULL; } if(data->tls_auth) { SSL_shutdown(data->tls_auth); SSL_free(data->tls_auth); data->tls_auth = NULL; } #endif data->pp2_header_state = pp2_header_none; close(data->event.ev_fd); if(data->prev) data->prev->next = data->next; else tcp_active_list = data->next; if(data->next) data->next->prev = data->prev; /* * Enable the TCP accept handlers when the current number of * TCP connections is about to drop below the maximum number * of TCP connections. */ if (slowaccept || data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) { configure_handler_event_types(EV_READ|EV_PERSIST); if(slowaccept) { event_del(&slowaccept_event); slowaccept = 0; } } --data->nsd->current_tcp_count; assert(data->nsd->current_tcp_count >= 0); region_destroy(data->region); } /* Read more data into the buffer for tcp read. Pass the amount of additional * data required. Returns false if nothing needs to be done this event, or * true if the additional data is in the buffer. */ static int more_read_buf_tcp(int fd, struct tcp_handler_data* data, void* bufpos, size_t add_amount, ssize_t* received) { *received = read(fd, bufpos, add_amount); if (*received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more * data is available. */ return 0; } else { char buf[48]; addr2str(&data->query->remote_addr, buf, sizeof(buf)); #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); cleanup_tcp_handler(data); return 0; } } else if (*received == 0) { /* EOF */ cleanup_tcp_handler(data); return 0; } return 1; } static void handle_tcp_reading(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t received; struct event_base* ev_base; struct timeval timeout; uint32_t now = 0; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } if ((data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) || (data->query_count > 0 && data->tcp_no_more_queries)) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(data); return; } assert((event & EV_READ)); if (data->bytes_transmitted == 0 && data->query_needs_reset) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); data->query_needs_reset = 0; } if(data->pp2_enabled && data->pp2_header_state != pp2_header_done) { struct pp2_header* header = NULL; size_t want_read_size = 0; size_t current_read_size = 0; if(data->pp2_header_state == pp2_header_none) { want_read_size = PP2_HEADER_SIZE; if(buffer_remaining(data->query->packet) < want_read_size) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); cleanup_tcp_handler(data); return; } VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading fixed part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); current_read_size = want_read_size; if(data->bytes_transmitted < current_read_size) { if(!more_read_buf_tcp(fd, data, (void*)buffer_at(data->query->packet, data->bytes_transmitted), current_read_size - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if(data->bytes_transmitted != current_read_size) return; data->pp2_header_state = pp2_header_init; } } if(data->pp2_header_state == pp2_header_init) { int err; err = pp2_read_header(buffer_begin(data->query->packet), buffer_limit(data->query->packet)); if(err) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not parse PROXYv2 header: %s", pp_lookup_error(err))); cleanup_tcp_handler(data); return; } header = (struct pp2_header*)buffer_begin(data->query->packet); want_read_size = ntohs(header->len); if(buffer_limit(data->query->packet) < PP2_HEADER_SIZE + want_read_size) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); cleanup_tcp_handler(data); return; } VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading variable part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); current_read_size = PP2_HEADER_SIZE + want_read_size; if(want_read_size == 0) { /* nothing more to read; header is complete */ data->pp2_header_state = pp2_header_done; } else if(data->bytes_transmitted < current_read_size) { if(!more_read_buf_tcp(fd, data, (void*)buffer_at(data->query->packet, data->bytes_transmitted), current_read_size - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if(data->bytes_transmitted != current_read_size) return; data->pp2_header_state = pp2_header_done; } } if(data->pp2_header_state != pp2_header_done || !header) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: wrong state for the PROXYv2 header")); cleanup_tcp_handler(data); return; } buffer_flip(data->query->packet); if(!consume_pp2_header(data->query->packet, data->query, 1)) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not consume PROXYv2 header")); cleanup_tcp_handler(data); return; } /* Clear and reset the buffer to read the following * DNS packet(s). */ buffer_clear(data->query->packet); data->bytes_transmitted = 0; } /* * Check if we received the leading packet length bytes yet. */ if (data->bytes_transmitted < sizeof(uint16_t)) { if(!more_read_buf_tcp(fd, data, (char*) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(data); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(data); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ if(!more_read_buf_tcp(fd, data, buffer_current(data->query->packet), buffer_remaining(data->query->packet), &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifdef BIND8_STATS #ifndef INET6 STATUP(data->nsd, ctcp); #else if (data->query->remote_addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); } else if (data->query->remote_addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } #endif #endif /* BIND8_STATS */ /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); #ifdef USE_DNSTAP /* * and send TCP-query with found address (local) and client address to dnstap process */ log_addr("query from client", &data->query->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); if(verbosity >= 6 && data->query->is_proxied) log_addr("query via proxy", &data->query->remote_addr); dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, data->query->client_addrlen, data->query->tcp, data->query->packet); #endif /* USE_DNSTAP */ data->query_state = server_process_query(data->nsd, data->query, &now); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); ZTATUP(data->nsd, data->query->zone, dropped); cleanup_tcp_handler(data); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, data->query->zone, nona); } #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS #ifndef INET6 ZTATUP(data->nsd, data->query->zone, ctcp); #else if (data->query->remote_addr.ss_family == AF_INET) { ZTATUP(data->nsd, data->query->zone, ctcp); } else if (data->query->remote_addr.ss_family == AF_INET6) { ZTATUP(data->nsd, data->query->zone, ctcp6); } #endif #endif /* USE_ZONE_STATS */ query_add_optional(data->query, data->nsd, &now); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); #ifdef BIND8_STATS /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(data->query->packet)); ZTATUP2(data->nsd, data->query->zone, rcode, RCODE(data->query->packet)); if (TC(data->query->packet)) { STATUP(data->nsd, truncated); ZTATUP(data->nsd, data->query->zone, truncated); } #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* * sending TCP-response with found (earlier) address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); log_addr("response to client", &data->query->client_addr); if(verbosity >= 6 && data->query->is_proxied) log_addr("response via proxy", &data->query->remote_addr); dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, data->query->client_addrlen, data->query->tcp, data->query->packet, data->query->zone); #endif /* USE_DNSTAP */ data->bytes_transmitted = 0; timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); memset(&data->event, 0, sizeof(data->event)); event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, handle_tcp_writing, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpr failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpr failed"); /* see if we can write the answer right away(usually so,EAGAIN ifnot)*/ handle_tcp_writing(fd, EV_WRITE, data); } static void handle_tcp_writing(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t sent; struct query *q = data->query; struct timeval timeout; struct event_base* ev_base; uint32_t now = 0; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } assert((event & EV_WRITE)); if (data->bytes_transmitted < sizeof(q->tcplen)) { /* Writing the response packet length. */ uint16_t n_tcplen = htons(q->tcplen); #ifdef HAVE_WRITEV struct iovec iov[2]; iov[0].iov_base = (uint8_t*)&n_tcplen + data->bytes_transmitted; iov[0].iov_len = sizeof(n_tcplen) - data->bytes_transmitted; iov[1].iov_base = buffer_begin(q->packet); iov[1].iov_len = buffer_limit(q->packet); sent = writev(fd, iov, 2); #else /* HAVE_WRITEV */ sent = write(fd, (const char *) &n_tcplen + data->bytes_transmitted, sizeof(n_tcplen) - data->bytes_transmitted); #endif /* HAVE_WRITEV */ if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(data); return; } } data->bytes_transmitted += sent; if (data->bytes_transmitted < sizeof(q->tcplen)) { /* * Writing not complete, wait until socket * becomes writable again. */ return; } #ifdef HAVE_WRITEV sent -= sizeof(n_tcplen); /* handle potential 'packet done' code */ goto packet_could_be_done; #endif } sent = write(fd, buffer_current(q->packet), buffer_remaining(q->packet)); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(data); return; } } data->bytes_transmitted += sent; #ifdef HAVE_WRITEV packet_could_be_done: #endif buffer_skip(q->packet, sent); if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR || data->query_state == QUERY_IN_IXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); if(data->query_state == QUERY_IN_AXFR) data->query_state = query_axfr(data->nsd, q, 0); else data->query_state = query_ixfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd, &now); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); memset(&data->event, 0, sizeof(data->event)); event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, handle_tcp_writing, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpw failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpw failed"); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if ((data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) || data->tcp_no_more_queries) { (void) shutdown(fd, SHUT_WR); } data->bytes_transmitted = 0; data->query_needs_reset = 1; timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); memset(&data->event, 0, sizeof(data->event)); event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpw failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpw failed"); } #ifdef HAVE_SSL /** create SSL object and associate fd */ static SSL* incoming_ssl_fd(SSL_CTX* ctx, int fd) { SSL* ssl = SSL_new((SSL_CTX*)ctx); if(!ssl) { log_crypto_err("could not SSL_new"); return NULL; } SSL_set_accept_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) { log_crypto_err("could not SSL_set_fd"); SSL_free(ssl); return NULL; } return ssl; } /** TLS handshake to upgrade TCP connection */ static int tls_handshake(struct tcp_handler_data* data, int fd, int writing) { int r; if(data->shake_state == tls_hs_read_event) { /* read condition satisfied back to writing */ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE); data->shake_state = tls_hs_none; return 1; } if(data->shake_state == tls_hs_write_event) { /* write condition satisfied back to reading */ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ); data->shake_state = tls_hs_none; return 1; } /* (continue to) setup the TLS connection */ ERR_clear_error(); if(data->tls_auth) r = SSL_do_handshake(data->tls_auth); else r = SSL_do_handshake(data->tls); if(r != 1) { int want; if(data->tls_auth) want = SSL_get_error(data->tls_auth, r); else want = SSL_get_error(data->tls, r); if(want == SSL_ERROR_WANT_READ) { if(data->shake_state == tls_hs_read) { /* try again later */ return 1; } data->shake_state = tls_hs_read; /* switch back to reading mode */ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ); return 1; } else if(want == SSL_ERROR_WANT_WRITE) { if(data->shake_state == tls_hs_write) { /* try again later */ return 1; } data->shake_state = tls_hs_write; /* switch back to writing mode */ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE); return 1; } else { if(r == 0) VERBOSITY(5, (LOG_ERR, "TLS handshake: connection closed prematurely")); else { unsigned long err = ERR_get_error(); if(!squelch_err_ssl_handshake(err)) { char a[64], s[256]; addr2str(&data->query->remote_addr, a, sizeof(a)); snprintf(s, sizeof(s), "TLS handshake failed from %s", a); log_crypto_from_err(LOG_ERR, s, err); } } cleanup_tcp_handler(data); return 0; } } /* Use to log successful upgrade for testing - could be removed*/ if(data->tls_auth) VERBOSITY(5, (LOG_INFO, "TLS-AUTH handshake succeeded.")); else VERBOSITY(5, (LOG_INFO, "TLS handshake succeeded.")); /* set back to the event we need to have when reading (or writing) */ if(data->shake_state == tls_hs_read && writing) { tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE); } else if(data->shake_state == tls_hs_write && !writing) { tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ); } data->shake_state = tls_hs_none; return 1; } /* Read more data into the buffer for tls read. Pass the amount of additional * data required. Returns false if nothing needs to be done this event, or * true if the additional data is in the buffer. */ static int more_read_buf_tls(int fd, struct tcp_handler_data* data, void* bufpos, size_t add_amount, ssize_t* received) { int r; ERR_clear_error(); if(data->tls_auth) r = (*received=SSL_read(data->tls_auth, bufpos, add_amount)); else r = (*received=SSL_read(data->tls, bufpos, add_amount)); if(r <= 0) { int want; if(data->tls_auth) want = SSL_get_error(data->tls_auth, *received); else want = SSL_get_error(data->tls, *received); if(want == SSL_ERROR_ZERO_RETURN) { cleanup_tcp_handler(data); return 0; /* shutdown, closed */ } else if(want == SSL_ERROR_WANT_READ) { /* wants to be called again */ return 0; } else if(want == SSL_ERROR_WANT_WRITE) { /* switch to writing */ data->shake_state = tls_hs_write_event; tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); return 0; } cleanup_tcp_handler(data); log_crypto_err("could not SSL_read"); return 0; } return 1; } /** handle TLS reading of incoming query */ static void handle_tls_reading(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t received; uint32_t now = 0; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } if ((data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) || (data->query_count > 0 && data->tcp_no_more_queries)) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(data); return; } assert((event & EV_READ)); if (data->bytes_transmitted == 0 && data->query_needs_reset) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); data->query_needs_reset = 0; } if(data->shake_state != tls_hs_none) { if(!tls_handshake(data, fd, 0)) return; if(data->shake_state != tls_hs_none) return; } if(data->pp2_enabled && data->pp2_header_state != pp2_header_done) { struct pp2_header* header = NULL; size_t want_read_size = 0; size_t current_read_size = 0; if(data->pp2_header_state == pp2_header_none) { want_read_size = PP2_HEADER_SIZE; if(buffer_remaining(data->query->packet) < want_read_size) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); cleanup_tcp_handler(data); return; } VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading fixed part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); current_read_size = want_read_size; if(data->bytes_transmitted < current_read_size) { if(!more_read_buf_tls(fd, data, buffer_at(data->query->packet, data->bytes_transmitted), current_read_size - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if(data->bytes_transmitted != current_read_size) return; data->pp2_header_state = pp2_header_init; } } if(data->pp2_header_state == pp2_header_init) { int err; err = pp2_read_header(buffer_begin(data->query->packet), buffer_limit(data->query->packet)); if(err) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not parse PROXYv2 header: %s", pp_lookup_error(err))); cleanup_tcp_handler(data); return; } header = (struct pp2_header*)buffer_begin(data->query->packet); want_read_size = ntohs(header->len); if(buffer_limit(data->query->packet) < PP2_HEADER_SIZE + want_read_size) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); cleanup_tcp_handler(data); return; } VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading variable part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); current_read_size = PP2_HEADER_SIZE + want_read_size; if(want_read_size == 0) { /* nothing more to read; header is complete */ data->pp2_header_state = pp2_header_done; } else if(data->bytes_transmitted < current_read_size) { if(!more_read_buf_tls(fd, data, buffer_at(data->query->packet, data->bytes_transmitted), current_read_size - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if(data->bytes_transmitted != current_read_size) return; data->pp2_header_state = pp2_header_done; } } if(data->pp2_header_state != pp2_header_done || !header) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: wrong state for the PROXYv2 header")); cleanup_tcp_handler(data); return; } buffer_flip(data->query->packet); if(!consume_pp2_header(data->query->packet, data->query, 1)) { VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not consume PROXYv2 header")); cleanup_tcp_handler(data); return; } /* Clear and reset the buffer to read the following * DNS packet(s). */ buffer_clear(data->query->packet); data->bytes_transmitted = 0; } /* * Check if we received the leading packet length bytes yet. */ if(data->bytes_transmitted < sizeof(uint16_t)) { if(!more_read_buf_tls(fd, data, (char *) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted, &received)) return; data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(data); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(data); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ if(!more_read_buf_tls(fd, data, buffer_current(data->query->packet), buffer_remaining(data->query->packet), &received)) return; data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifndef INET6 STATUP(data->nsd, ctls); #else if (data->query->remote_addr.ss_family == AF_INET) { STATUP(data->nsd, ctls); } else if (data->query->remote_addr.ss_family == AF_INET6) { STATUP(data->nsd, ctls6); } #endif /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); #ifdef USE_DNSTAP /* * and send TCP-query with found address (local) and client address to dnstap process */ log_addr("query from client", &data->query->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); if(verbosity >= 6 && data->query->is_proxied) log_addr("query via proxy", &data->query->remote_addr); dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, data->query->client_addrlen, data->query->tcp, data->query->packet); #endif /* USE_DNSTAP */ data->query_state = server_process_query(data->nsd, data->query, &now); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); ZTATUP(data->nsd, data->query->zone, dropped); cleanup_tcp_handler(data); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, data->query->zone, nona); } #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS #ifndef INET6 ZTATUP(data->nsd, data->query->zone, ctls); #else if (data->query->remote_addr.ss_family == AF_INET) { ZTATUP(data->nsd, data->query->zone, ctls); } else if (data->query->remote_addr.ss_family == AF_INET6) { ZTATUP(data->nsd, data->query->zone, ctls6); } #endif #endif /* USE_ZONE_STATS */ query_add_optional(data->query, data->nsd, &now); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); #ifdef BIND8_STATS /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(data->query->packet)); ZTATUP2(data->nsd, data->query->zone, rcode, RCODE(data->query->packet)); if (TC(data->query->packet)) { STATUP(data->nsd, truncated); ZTATUP(data->nsd, data->query->zone, truncated); } #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* * sending TCP-response with found (earlier) address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); log_addr("response to client", &data->query->client_addr); if(verbosity >= 6 && data->query->is_proxied) log_addr("response via proxy", &data->query->remote_addr); dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, data->query->client_addrlen, data->query->tcp, data->query->packet, data->query->zone); #endif /* USE_DNSTAP */ data->bytes_transmitted = 0; tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); /* see if we can write the answer right away(usually so,EAGAIN ifnot)*/ handle_tls_writing(fd, EV_WRITE, data); } /** handle TLS writing of outgoing response */ static void handle_tls_writing(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t sent; struct query *q = data->query; /* static variable that holds reassembly buffer used to put the * TCP length in front of the packet, like writev. */ static buffer_type* global_tls_temp_buffer = NULL; buffer_type* write_buffer; uint32_t now = 0; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } assert((event & EV_WRITE)); if(data->shake_state != tls_hs_none) { if(!tls_handshake(data, fd, 1)) return; if(data->shake_state != tls_hs_none) return; } if(data->tls_auth) (void)SSL_set_mode(data->tls_auth, SSL_MODE_ENABLE_PARTIAL_WRITE); else (void)SSL_set_mode(data->tls, SSL_MODE_ENABLE_PARTIAL_WRITE); /* If we are writing the start of a message, we must include the length * this is done with a copy into write_buffer. */ write_buffer = NULL; if (data->bytes_transmitted == 0) { if(!global_tls_temp_buffer) { /* gets deallocated when nsd shuts down from * nsd.region */ global_tls_temp_buffer = buffer_create(nsd.region, QIOBUFSZ + sizeof(q->tcplen)); if (!global_tls_temp_buffer) { return; } } write_buffer = global_tls_temp_buffer; buffer_clear(write_buffer); buffer_write_u16(write_buffer, q->tcplen); buffer_write(write_buffer, buffer_current(q->packet), (int)buffer_remaining(q->packet)); buffer_flip(write_buffer); } else { write_buffer = q->packet; } /* Write the response */ ERR_clear_error(); if(data->tls_auth) sent = SSL_write(data->tls_auth, buffer_current(write_buffer), buffer_remaining(write_buffer)); else sent = SSL_write(data->tls, buffer_current(write_buffer), buffer_remaining(write_buffer)); if(sent <= 0) { int want; if(data->tls_auth) want = SSL_get_error(data->tls_auth, sent); else want = SSL_get_error(data->tls, sent); if(want == SSL_ERROR_ZERO_RETURN) { cleanup_tcp_handler(data); /* closed */ } else if(want == SSL_ERROR_WANT_READ) { /* switch back to reading */ data->shake_state = tls_hs_read_event; tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT); } else if(want != SSL_ERROR_WANT_WRITE) { cleanup_tcp_handler(data); log_crypto_err("could not SSL_write"); } return; } buffer_skip(write_buffer, sent); if(buffer_remaining(write_buffer) != 0) { /* If not all sent, sync up the real buffer if it wasn't used.*/ if (data->bytes_transmitted == 0 && (ssize_t)sent > (ssize_t)sizeof(q->tcplen)) { buffer_skip(q->packet, (ssize_t)sent - (ssize_t)sizeof(q->tcplen)); } } data->bytes_transmitted += sent; if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR || data->query_state == QUERY_IN_IXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); if(data->query_state == QUERY_IN_AXFR) data->query_state = query_axfr(data->nsd, q, 0); else data->query_state = query_ixfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd, &now); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset to writing mode. */ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if ((data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) || data->tcp_no_more_queries) { (void) shutdown(fd, SHUT_WR); } data->bytes_transmitted = 0; data->query_needs_reset = 1; tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT); } #endif static void handle_slowaccept_timeout(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) { if(slowaccept) { configure_handler_event_types(EV_PERSIST | EV_READ); slowaccept = 0; } } static int perform_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) { #ifndef HAVE_ACCEPT4 int s = accept(fd, addr, addrlen); if (s != -1) { if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); close(s); s = -1; errno=EINTR; /* stop error printout as error in accept4 by setting this errno, it omits printout, in later code that calls nsd_accept4 */ } } return s; #else return accept4(fd, addr, addrlen, SOCK_NONBLOCK); #endif /* HAVE_ACCEPT4 */ } /* * Handle an incoming TCP connection. The connection is accepted and * a new TCP reader event handler is added. The TCP handler * is responsible for cleanup when the connection is closed. */ static void handle_tcp_accept(int fd, short event, void* arg) { struct tcp_accept_handler_data *data = (struct tcp_accept_handler_data *) arg; int s; int reject = 0; struct tcp_handler_data *tcp_data; region_type *tcp_region; #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; struct timeval timeout; if (!(event & EV_READ)) { return; } if (data->nsd->current_tcp_count >= data->nsd->maximum_tcp_count) { reject = data->nsd->options->tcp_reject_overflow; if (!reject) { return; } } /* Accept it... */ addrlen = sizeof(addr); s = perform_accept(fd, (struct sockaddr *) &addr, &addrlen); if (s == -1) { /** * EMFILE and ENFILE is a signal that the limit of open * file descriptors has been reached. Pause accept(). * EINTR is a signal interrupt. The others are various OS ways * of saying that the client has closed the connection. */ if (errno == EMFILE || errno == ENFILE) { if (!slowaccept) { /* disable accept events */ struct timeval tv; configure_handler_event_types(0); tv.tv_sec = SLOW_ACCEPT_TIMEOUT; tv.tv_usec = 0L; memset(&slowaccept_event, 0, sizeof(slowaccept_event)); event_set(&slowaccept_event, -1, EV_TIMEOUT, handle_slowaccept_timeout, NULL); (void)event_base_set(data->event.ev_base, &slowaccept_event); (void)event_add(&slowaccept_event, &tv); slowaccept = 1; /* We don't want to spam the logs here */ } } else if (errno != EINTR && errno != EWOULDBLOCK #ifdef ECONNABORTED && errno != ECONNABORTED #endif /* ECONNABORTED */ #ifdef EPROTO && errno != EPROTO #endif /* EPROTO */ ) { log_msg(LOG_ERR, "accept failed: %s", strerror(errno)); } return; } if (reject) { shutdown(s, SHUT_RDWR); close(s); return; } /* * This region is deallocated when the TCP connection is * closed by the TCP handler. */ tcp_region = region_create(xalloc, free); tcp_data = (struct tcp_handler_data *) region_alloc( tcp_region, sizeof(struct tcp_handler_data)); tcp_data->region = tcp_region; tcp_data->query = query_create(tcp_region, compressed_dname_offsets, compression_table_size, compressed_dnames); tcp_data->nsd = data->nsd; tcp_data->query_count = 0; #ifdef HAVE_SSL tcp_data->shake_state = tls_hs_none; /* initialize both incase of dangling pointers */ tcp_data->tls = NULL; tcp_data->tls_auth = NULL; #endif tcp_data->query_needs_reset = 1; tcp_data->pp2_enabled = data->pp2_enabled; tcp_data->pp2_header_state = pp2_header_none; tcp_data->prev = NULL; tcp_data->next = NULL; tcp_data->query_state = QUERY_PROCESSED; tcp_data->bytes_transmitted = 0; memcpy(&tcp_data->query->remote_addr, &addr, addrlen); tcp_data->query->remote_addrlen = addrlen; /* Copy remote_address to client_address. * Simplest way/time for streams to do that. */ memcpy(&tcp_data->query->client_addr, &addr, addrlen); tcp_data->query->client_addrlen = addrlen; tcp_data->query->is_proxied = 0; tcp_data->tcp_no_more_queries = 0; tcp_data->tcp_timeout = data->nsd->tcp_timeout * 1000; if (data->nsd->current_tcp_count > data->nsd->maximum_tcp_count/2) { /* very busy, give smaller timeout */ tcp_data->tcp_timeout = 200; } memset(&tcp_data->event, 0, sizeof(tcp_data->event)); timeout.tv_sec = tcp_data->tcp_timeout / 1000; timeout.tv_usec = (tcp_data->tcp_timeout % 1000)*1000; #ifdef USE_DNSTAP /* save the address of the connection */ tcp_data->socket = data->socket; #endif /* USE_DNSTAP */ #ifdef HAVE_SSL if (data->tls_accept) { tcp_data->tls = incoming_ssl_fd(tcp_data->nsd->tls_ctx, s); if(!tcp_data->tls) { close(s); return; } tcp_data->query->tls = tcp_data->tls; tcp_data->shake_state = tls_hs_read; memset(&tcp_data->event, 0, sizeof(tcp_data->event)); event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tls_reading, tcp_data); } else if (data->tls_auth_accept) { tcp_data->tls_auth = incoming_ssl_fd(tcp_data->nsd->tls_auth_ctx, s); if(!tcp_data->tls_auth) { close(s); return; } tcp_data->query->tls_auth = tcp_data->tls_auth; tcp_data->shake_state = tls_hs_read; memset(&tcp_data->event, 0, sizeof(tcp_data->event)); event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tls_reading, tcp_data); } else { #endif memset(&tcp_data->event, 0, sizeof(tcp_data->event)); event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, tcp_data); #ifdef HAVE_SSL } #endif if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) { log_msg(LOG_ERR, "cannot set tcp event base"); close(s); region_destroy(tcp_region); return; } if(event_add(&tcp_data->event, &timeout) != 0) { log_msg(LOG_ERR, "cannot add tcp to event base"); close(s); region_destroy(tcp_region); return; } if(tcp_active_list) { tcp_active_list->prev = tcp_data; tcp_data->next = tcp_active_list; } tcp_active_list = tcp_data; /* * Keep track of the total number of TCP handlers installed so * we can stop accepting connections when the maximum number * of simultaneous TCP connections is reached. * * If tcp-reject-overflow is enabled, however, then we do not * change the handler event type; we keep it as-is and accept * overflow TCP connections only so that we can forcibly kill * them off. */ ++data->nsd->current_tcp_count; if (!data->nsd->options->tcp_reject_overflow && data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) { configure_handler_event_types(0); } } static void send_children_command(struct nsd* nsd, sig_atomic_t command, int timeout) { size_t i; assert(nsd->server_kind == NSD_SERVER_MAIN && nsd->this_child == 0); for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid > 0 && nsd->children[i].child_fd != -1) { if (write(nsd->children[i].child_fd, &command, sizeof(command)) == -1) { if(errno != EAGAIN && errno != EINTR) log_msg(LOG_ERR, "problems sending command %d to server %d: %s", (int) command, (int) nsd->children[i].pid, strerror(errno)); } else if (timeout > 0) { (void)block_read(NULL, nsd->children[i].child_fd, &command, sizeof(command), timeout); } fsync(nsd->children[i].child_fd); close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; } } } static void send_children_quit(struct nsd* nsd) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "send children quit")); send_children_command(nsd, NSD_QUIT, 0); } static void send_children_quit_and_wait(struct nsd* nsd) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "send children quit and wait")); send_children_command(nsd, NSD_QUIT_CHILD, 3); } #ifdef BIND8_STATS static void set_children_stats(struct nsd* nsd) { size_t i; assert(nsd->server_kind == NSD_SERVER_MAIN && nsd->this_child == 0); DEBUG(DEBUG_IPC, 1, (LOG_INFO, "parent set stats to send to children")); for (i = 0; i < nsd->child_count; ++i) { nsd->children[i].need_to_send_STATS = 1; nsd->children[i].handler->event_types |= NETIO_EVENT_WRITE; } } #endif /* BIND8_STATS */ static void configure_handler_event_types(short event_types) { size_t i; for (i = 0; i < tcp_accept_handler_count; ++i) { struct event* handler = &tcp_accept_handlers[i].event; if(event_types) { /* reassign */ int fd = handler->ev_fd; struct event_base* base = handler->ev_base; if(tcp_accept_handlers[i].event_added) event_del(handler); memset(handler, 0, sizeof(*handler)); event_set(handler, fd, event_types, handle_tcp_accept, &tcp_accept_handlers[i]); if(event_base_set(base, handler) != 0) log_msg(LOG_ERR, "conhand: cannot event_base"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "conhand: cannot event_add"); tcp_accept_handlers[i].event_added = 1; } else { /* remove */ if(tcp_accept_handlers[i].event_added) { event_del(handler); tcp_accept_handlers[i].event_added = 0; } } } } nsd-4.12.0/rrl.h0000644000175000017500000000464015002373054012751 0ustar mozziemozzie/* rrl.h - Response Rate Limiting for NSD. * By W.C.A. Wijngaards * Copyright 2012, NLnet Labs. * BSD, see LICENSE. */ #ifndef RRL_H #define RRL_H #include "query.h" /** the classification types for the rrl */ enum rrl_type { /* classification types */ rrl_type_nxdomain = 0x01, rrl_type_error = 0x02, rrl_type_referral = 0x04, rrl_type_any = 0x08, rrl_type_wildcard = 0x10, rrl_type_nodata = 0x20, rrl_type_dnskey = 0x40, rrl_type_positive = 0x80, rrl_type_rrsig = 0x100, /* all classification types */ rrl_type_all = 0x1ff, /* to distinguish between ip4 and ip6 netblocks, used in code */ rrl_ip6 = 0x8000 }; /** Number of buckets */ #define RRL_BUCKETS 1000000 /** default rrl limit, in 2x qps , the default is 200 qps */ #define RRL_LIMIT 400 /** default slip */ #define RRL_SLIP 2 /** default prefix lengths */ #define RRL_IPV4_PREFIX_LENGTH 24 #define RRL_IPV6_PREFIX_LENGTH 64 /** default whitelist rrl limit, in 2x qps, default is thus 2000 qps */ #define RRL_WLIST_LIMIT 4000 /** * Initialize for n children (optional, otherwise no mmaps used) * ratelimits lm and wlm are in qps (this routines x2s them for internal use). * plf and pls are in prefix lengths. */ void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm, size_t plf, size_t pls); /** * Initialize rate limiting (for this child server process) */ void rrl_init(size_t ch); /** deinit (for this child server process) */ void rrl_deinit(size_t ch); /** deinit mmaps for n children */ void rrl_mmap_deinit(void); /** frees memory but keeps mmap in place (for other processes) */ void rrl_mmap_deinit_keep_mmap(void); /** * Process query that happens, the query structure contains the * information about the query and the answer. * returns true if the query is ratelimited. */ int rrl_process_query(query_type* query); /** * Deny the query, with slip. * Returns DISCARD or PROCESSED(with TC flag). */ query_state_type rrl_slip(query_type* query); /** convert classification type to string */ const char* rrltype2str(enum rrl_type c); /** convert string to classification type */ enum rrl_type rrlstr2type(const char* s); /** for unit test, update rrl bucket; return rate */ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, uint16_t flags, int32_t now, uint32_t lm); /** set the rate limit counters, pass variables in qps */ void rrl_set_limit(size_t lm, size_t wlm, size_t sm); #endif /* RRL_H */ nsd-4.12.0/rrl.c0000644000175000017500000003426415002373054012751 0ustar mozziemozzie /* rrl.c - Response Rate Limiting for NSD. * By W.C.A. Wijngaards * Copyright 2012, NLnet Labs. * BSD, see LICENSE. */ #include "config.h" #include #include "rrl.h" #include "util.h" #include "lookup3.h" #include "options.h" #ifdef RATELIMIT #ifdef HAVE_MMAP #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #endif /* HAVE_MMAP */ /** * The rate limiting data structure bucket, this represents one rate of * packets from a single source. * Smoothed average rates. */ struct rrl_bucket { /* the source netmask */ uint64_t source; /* rate, in queries per second, which due to rate=r(t)+r(t-1)/2 is * equal to double the queries per second */ uint32_t rate; /* the full hash */ uint32_t hash; /* counter for queries arrived in this second */ uint32_t counter; /* timestamp, which time is the time of the counter, the rate is from * one timestep before that. */ int32_t stamp; /* flags for the source mask and type */ uint16_t flags; }; /* the (global) array of RRL buckets */ static struct rrl_bucket* rrl_array = NULL; static size_t rrl_array_size = RRL_BUCKETS; static uint32_t rrl_ratelimit = RRL_LIMIT; /* 2x qps */ static uint8_t rrl_slip_ratio = RRL_SLIP; static uint8_t rrl_ipv4_prefixlen = RRL_IPV4_PREFIX_LENGTH; static uint8_t rrl_ipv6_prefixlen = RRL_IPV6_PREFIX_LENGTH; static uint64_t rrl_ipv6_mask; /* max prefixlen 64 */ static uint32_t rrl_whitelist_ratelimit = RRL_WLIST_LIMIT; /* 2x qps */ /* the array of mmaps for the children (saved between reloads) */ static void** rrl_maps = NULL; static size_t rrl_maps_num = 0; void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm, size_t plf, size_t pls) { #ifdef HAVE_MMAP size_t i; #endif if(numbuck != 0) rrl_array_size = numbuck; rrl_ratelimit = lm*2; rrl_slip_ratio = sm; rrl_ipv4_prefixlen = plf; rrl_ipv6_prefixlen = pls; if (pls <= 32) { rrl_ipv6_mask = ((uint64_t) htonl(0xffffffff << (32-pls))) << 32; } else { rrl_ipv6_mask = ((uint64_t) htonl(0xffffffff << (64-pls))) | (((uint64_t)0xffffffff)<<32); } rrl_whitelist_ratelimit = wlm*2; #ifdef HAVE_MMAP /* allocate the ratelimit hashtable in a memory map so it is * preserved across reforks (every child its own table) */ rrl_maps_num = (size_t)numch; rrl_maps = (void**)xmallocarray(rrl_maps_num, sizeof(void*)); for(i=0; i= rrl_maps_num) rrl_array = xalloc_array_zero(sizeof(struct rrl_bucket), rrl_array_size); #ifdef HAVE_MMAP else rrl_array = (struct rrl_bucket*)rrl_maps[ch]; #endif } void rrl_deinit(size_t ch) { if(!rrl_maps || ch >= rrl_maps_num) free(rrl_array); rrl_array = NULL; } /** return the source netblock of the query, this is the genuine source * for genuine queries and the target for reflected packets */ static uint64_t rrl_get_source(query_type* query, uint16_t* c2) { /* note there is an IPv6 subnet, that maps * to the same buckets as IPv4 space, but there is a flag in c2 * that makes the hash different */ #ifdef INET6 if( ((struct sockaddr_in*)&query->client_addr)->sin_family == AF_INET) { *c2 = 0; return ((struct sockaddr_in*)&query->client_addr)-> sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); } else { uint64_t s; *c2 = rrl_ip6; memmove(&s, &((struct sockaddr_in6*)&query->client_addr)->sin6_addr, sizeof(s)); return s & rrl_ipv6_mask; } #else *c2 = 0; return query->client_addr.sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); #endif } /** debug source to string */ static const char* rrlsource2str(uint64_t s, uint16_t c2) { static char buf[64]; struct in_addr a4; #ifdef INET6 if(c2) { /* IPv6 */ struct in6_addr a6; memset(&a6, 0, sizeof(a6)); memmove(&a6, &s, sizeof(s)); if(!inet_ntop(AF_INET6, &a6, buf, sizeof(buf))) strlcpy(buf, "[ip6 ntop failed]", sizeof(buf)); else { static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv6_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } return buf; } #else (void)c2; #endif /* ipv4 */ a4.s_addr = (uint32_t)s; if(!inet_ntop(AF_INET, &a4, buf, sizeof(buf))) strlcpy(buf, "[ip4 ntop failed]", sizeof(buf)); else { static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv4_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } return buf; } enum rrl_type rrlstr2type(const char* s) { if(strcmp(s, "nxdomain")==0) return rrl_type_nxdomain; else if(strcmp(s, "error")==0) return rrl_type_error; else if(strcmp(s, "referral")==0) return rrl_type_referral; else if(strcmp(s, "any")==0) return rrl_type_any; else if(strcmp(s, "wildcard")==0) return rrl_type_wildcard; else if(strcmp(s, "nodata")==0) return rrl_type_nodata; else if(strcmp(s, "dnskey")==0) return rrl_type_dnskey; else if(strcmp(s, "positive")==0) return rrl_type_positive; else if(strcmp(s, "rrsig")==0) return rrl_type_rrsig; else if(strcmp(s, "all")==0) return rrl_type_all; return 0; /* unknown */ } const char* rrltype2str(enum rrl_type c) { switch(c & 0x0fff) { case rrl_type_nxdomain: return "nxdomain"; case rrl_type_error: return "error"; case rrl_type_referral: return "referral"; case rrl_type_any: return "any"; case rrl_type_wildcard: return "wildcard"; case rrl_type_nodata: return "nodata"; case rrl_type_dnskey: return "dnskey"; case rrl_type_positive: return "positive"; case rrl_type_rrsig: return "rrsig"; case rrl_type_all: return "all"; } return "unknown"; } /** classify the query in a number of different types, each has separate * ratelimiting, so that positive queries are not impeded by others */ static uint16_t rrl_classify(query_type* query, const uint8_t** d, size_t* d_len) { if(RCODE(query->packet) == RCODE_NXDOMAIN) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_nxdomain; } if(RCODE(query->packet) != RCODE_OK) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_error; } if(query->delegation_domain) { *d = dname_name(domain_dname(query->delegation_domain)); *d_len = domain_dname(query->delegation_domain)->name_size; return rrl_type_referral; } if(query->qtype == TYPE_ANY) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_any; } if(query->qtype == TYPE_RRSIG) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_rrsig; } if(query->wildcard_domain) { *d = dname_name(domain_dname(query->wildcard_domain)); *d_len = domain_dname(query->wildcard_domain)->name_size; return rrl_type_wildcard; } if(ANCOUNT(query->packet) == 0) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_nodata; } if(query->qtype == TYPE_DNSKEY) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_dnskey; } /* positive */ if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_positive; } /** Examine the query and return hash and source of netblock. */ static void examine_query(query_type* query, uint32_t* hash, uint64_t* source, uint16_t* flags, uint32_t* lm) { /* compile a binary string representing the query */ uint16_t c, c2; /* size with 16 bytes to spare */ uint8_t buf[MAXDOMAINLEN + sizeof(*source) + sizeof(c) + 16]; const uint8_t* dname = NULL; size_t dname_len = 0; uint32_t r = 0x267fcd16; *source = rrl_get_source(query, &c2); c = rrl_classify(query, &dname, &dname_len); if(query->zone && query->zone->opts && (query->zone->opts->pattern->rrl_whitelist & c)) *lm = rrl_whitelist_ratelimit; if(*lm == 0) return; c |= c2; *flags = c; memmove(buf, source, sizeof(*source)); memmove(buf+sizeof(*source), &c, sizeof(c)); DEBUG(DEBUG_QUERY, 1, (LOG_INFO, "rrl_examine type %s name %s", rrltype2str(c), dname?wiredname2str(dname):"NULL")); /* and hash it */ if(dname && dname_len <= MAXDOMAINLEN) { memmove(buf+sizeof(*source)+sizeof(c), dname, dname_len); *hash = hashlittle(buf, sizeof(*source)+sizeof(c)+dname_len, r); } else *hash = hashlittle(buf, sizeof(*source)+sizeof(c), r); } /* age the bucket because elapsed time steps have gone by */ static void rrl_attenuate_bucket(struct rrl_bucket* b, int32_t elapsed) { if(elapsed > 16) { b->rate = 0; } else { /* divide rate /2 for every elapsed time step, because * the counters in the inbetween steps were 0 */ /* r(t) = 0 + 0/2 + 0/4 + .. + oldrate/2^dt */ b->rate >>= elapsed; /* we know that elapsed >= 2 */ b->rate += (b->counter>>(elapsed-1)); } } /** log a message about ratelimits */ static void rrl_msg(query_type* query, const char* str) { uint16_t c, c2, wl = 0; const uint8_t* d = NULL; size_t d_len; uint64_t s; char address[128]; if(verbosity < 1) return; addr2str(&query->client_addr, address, sizeof(address)); s = rrl_get_source(query, &c2); c = rrl_classify(query, &d, &d_len) | c2; if(query->zone && query->zone->opts && (query->zone->opts->pattern->rrl_whitelist & c)) wl = 1; log_msg(LOG_INFO, "ratelimit %s %s type %s%s target %s query %s %s", str, d?wiredname2str(d):"", rrltype2str(c), wl?"(whitelisted)":"", rrlsource2str(s, c2), address, rrtype_to_string(query->qtype)); } /** true if the query used to be blocked by the ratelimit */ static int used_to_block(uint32_t rate, uint32_t counter, uint32_t lm) { return rate >= lm || counter+rate/2 >= lm; } /** update the rate in a ratelimit bucket, return actual rate */ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, uint16_t flags, int32_t now, uint32_t lm) { struct rrl_bucket* b = &rrl_array[hash % rrl_array_size]; DEBUG(DEBUG_QUERY, 1, (LOG_INFO, "source %llx hash %x oldrate %d oldcount %d stamp %d", (long long unsigned)source, hash, b->rate, b->counter, b->stamp)); /* check if different source */ if(b->source != source || b->flags != flags || b->hash != hash) { /* initialise */ /* potentially the wrong limit here, used lower nonwhitelim */ if(verbosity >= 1 && used_to_block(b->rate, b->counter, rrl_ratelimit)) { char address[128]; addr2str(&query->client_addr, address, sizeof(address)); log_msg(LOG_INFO, "ratelimit unblock ~ type %s target %s query %s %s (%s collision)", rrltype2str(b->flags), rrlsource2str(b->source, b->flags), address, rrtype_to_string(query->qtype), (b->hash!=hash?"bucket":"hash")); } b->hash = hash; b->source = source; b->flags = flags; b->counter = 1; b->rate = 0; b->stamp = now; return 1; } /* this is the same source */ /* check if old, zero or smooth it */ /* circular arith for time */ if(now - b->stamp == 1) { /* very busy bucket and time just stepped one step */ int oldblock = used_to_block(b->rate, b->counter, lm); b->rate = b->rate/2 + b->counter; if(oldblock && b->rate < lm) rrl_msg(query, "unblock"); b->counter = 1; b->stamp = now; } else if(now - b->stamp > 0) { /* older bucket */ int olderblock = used_to_block(b->rate, b->counter, lm); rrl_attenuate_bucket(b, now - b->stamp); if(olderblock && b->rate < lm) rrl_msg(query, "unblock"); b->counter = 1; b->stamp = now; } else if(now != b->stamp) { /* robust, timestamp from the future */ if(used_to_block(b->rate, b->counter, lm)) rrl_msg(query, "unblock"); b->rate = 0; b->counter = 1; b->stamp = now; } else { /* bucket is from the current timestep, update counter */ b->counter ++; /* log what is blocked for operational debugging */ if(b->counter + b->rate/2 == lm && b->rate < lm) rrl_msg(query, "block"); } /* return max from current rate and projected next-value for rate */ /* so that if the rate increases suddenly very high, it is * stopped halfway into the time step */ if(b->counter > b->rate/2) return b->counter + b->rate/2; return b->rate; } int rrl_process_query(query_type* query) { uint64_t source; uint32_t hash; /* we can use circular arithmetic here, so int32 works after 2038 */ int32_t now = (int32_t)time(NULL); uint32_t lm = rrl_ratelimit; uint16_t flags; if(rrl_ratelimit == 0 && rrl_whitelist_ratelimit == 0) return 0; /* examine query */ examine_query(query, &hash, &source, &flags, &lm); if(lm == 0) return 0; /* no limit for this */ /* update rate */ return (rrl_update(query, hash, source, flags, now, lm) >= lm); } query_state_type rrl_slip(query_type* query) { /* discard number the packets, randomly */ #ifdef HAVE_ARC4RANDOM_UNIFORM if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random_uniform(rrl_slip_ratio)) == 0))) { #elif HAVE_ARC4RANDOM if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random() % rrl_slip_ratio) == 0))) { #else if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((random() % rrl_slip_ratio) == 0))) { #endif /* set TC on the rest */ TC_SET(query->packet); ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); if(query->qname) /* header, type, class, qname */ buffer_set_position(query->packet, QHEADERSZ+4+query->qname->name_size); else buffer_set_position(query->packet, QHEADERSZ); return QUERY_PROCESSED; } return QUERY_DISCARDED; } #endif /* RATELIMIT */ nsd-4.12.0/remote.h0000644000175000017500000001572115002373054013447 0ustar mozziemozzie/* * remote.h - remote control for the NSD daemon. * * Copyright (c) 2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains the remote control functionality for the daemon. * The remote control can be performed using either the commandline * nsd-control tool, or a SSLv3/TLS capable web browser. * The channel is secured using SSLv3 or TLSv1, and certificates. * Both the server and the client(control tool) have their own keys. */ #ifndef DAEMON_REMOTE_H #define DAEMON_REMOTE_H struct xfrd_state; struct nsd_options; #ifdef BIND8_STATS struct nsdst; struct remote_stream; struct evbuffer; #endif /* BIND8_STATS */ /* private, defined in remote.c to keep ssl.h out of this header */ struct daemon_remote; /* the remote control needs less backlog than the tcp53 service */ #define TCP_BACKLOG_REMOTE 16 /* listen() tcp backlog */ /** * Create new remote control state for the daemon. * Also setups the control port. * @param cfg: config file with key file settings. * @return new state, or NULL on failure. */ struct daemon_remote* daemon_remote_create(struct nsd_options* cfg); /** * remote control state to delete. * @param rc: state to delete. */ void daemon_remote_delete(struct daemon_remote* rc); /** * Close remote control ports. Clears up busy connections. * Does not delete the rc itself, or the ssl context (with its keys). * @param rc: state to close. */ void daemon_remote_close(struct daemon_remote* rc); /** * Open and create listening ports for remote control. * @param rc: rc state that contains list of accept port sockets. * @param cfg: config options. * @return false on failure. */ int daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg); /** * Setup comm points for accepting remote control connections. * @param rc: state * @param xfrd: the process that hosts the control connection. * The rc is attached to its event base. */ void daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd); /** * Create and bind local listening socket * @param path: path to the socket. * @param noproto: on error, this is set true if cause is that local sockets * are not supported. * @return: the socket. -1 on error. */ int create_local_accept_sock(const char* path, int* noproto); void xfrd_reload_config(struct xfrd_state *xfrd); #ifdef BIND8_STATS /** * Allocate stats temp arrays, for taking a coherent snapshot of the * statistics values at that time. * @param xfrd: the process that hosts the control connection. * @param stats: where to store the stats pointer * @param zonestats: where to store the zonestats pointer */ void process_stats_alloc(struct xfrd_state* xfrd, struct nsdst** stats, struct nsdst** zonestats); /** * Grab a copy of the statistics, at this particular time. * @param xfrd: the process that hosts the control connection. * @param stattime: where to write the timeofday * @param stats: where to copy the stats to * @param zonestats: where to copy the zonestats to */ void process_stats_grab(struct xfrd_state* xfrd, struct timeval* stattime, struct nsdst* stats, struct nsdst** zonestats); /** * Add the old and new processes stat values into the first part of the * array of stats * @param xfrd: the process that hosts the control connection. * @param stats: the stats pointer */ void process_stats_add_old_new(struct xfrd_state* xfrd, struct nsdst* stats); /** * Manage clearing of stats, a cumulative count of cleared statistics * @param xfrd: the process that hosts the control connection. * @param stats: the stats pointer * @param peek: whether to reset the stats time (0) or not (1) */ void process_stats_manage_clear(struct xfrd_state* xfrd, struct nsdst* stats, int peek); /** * Add up the statistics to get the total over the server children. * @param xfrd: the process that hosts the control connection. * @param total: where to store the total data * @param stats: the stats pointer */ void process_stats_add_total(struct xfrd_state* xfrd, struct nsdst* total, struct nsdst* stats); /** * Process the statistics and output them * @param ssl: the remote stream to write normal remote-control output to * @param evbuf: the HTTP buffer to write prometheus metrics output to * @param xfrd: the process that hosts the control connection. * @param peek: whether to reset the stats time (0) or not (1) */ void process_stats(struct remote_stream* ssl, struct evbuffer* evbuf, struct xfrd_state* xfrd, int peek); #ifdef USE_ZONE_STATS /** * Process the zonestat statistics and output them * @param ssl: the remote stream to write normal remote-control output to * @param evbuf: the HTTP buffer to write prometheus metrics output to * @param xfrd: the process that hosts the control connection. * @param clear: whether to reset the stats time * @param zonestats: the zonestats pointer */ void zonestat_print(struct remote_stream *ssl, struct evbuffer *evbuf, struct xfrd_state *xfrd, int clear, struct nsdst **zonestats); #endif /*USE_ZONE_STATS*/ const char* opcode2str(int o); void timeval_subtract(struct timeval *d, const struct timeval *end, const struct timeval *start); #endif /* BIND8_STATS */ #endif /* DAEMON_REMOTE_H */ nsd-4.12.0/remote.c0000644000175000017500000026735715002373054013460 0ustar mozziemozzie/* * remote.c - remote control for the NSD daemon. * * Copyright (c) 2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains the remote control functionality for the daemon. * The remote control can be performed using either the commandline * nsd-control tool, or a TLS capable web browser. * The channel is secured using TLSv1, and certificates. * Both the server and the client(control tool) have their own keys. */ #include "config.h" #ifdef HAVE_SSL #ifdef HAVE_OPENSSL_SSL_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #endif /* HAVE_SSL */ #include #include #include #include #include #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "util.h" #include "xfrd.h" #include "xfrd-catalog-zones.h" #include "xfrd-notify.h" #include "xfrd-tcp.h" #include "nsd.h" #include "options.h" #include "difffile.h" #include "ipc.h" #include "remote.h" #ifdef USE_METRICS #include "metrics.h" #endif /* USE_METRICS */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif /** number of seconds timeout on incoming remote control handshake */ #define REMOTE_CONTROL_TCP_TIMEOUT 120 /** repattern to master or slave */ #define REPAT_SLAVE 1 #define REPAT_MASTER 2 #define REPAT_CATALOG_CONSUMER 4 #define REPAT_CATALOG_CONSUMER_DEINIT 8 /** if you want zero to be inhibited in stats output. * it omits zeroes for types that have no acronym and unused-rcodes */ const int inhibit_zero = 1; /** * a busy control command connection, SSL state * Defined here to keep the definition private, and keep SSL out of the .h */ struct rc_state { /** the next item in list */ struct rc_state* next, *prev; /* if the event was added to the event_base */ int event_added; /** the commpoint */ struct event c; /** timeout for this state */ struct timeval tval; /** in the handshake part */ enum { rc_none, rc_hs_read, rc_hs_write } shake_state; #ifdef HAVE_SSL /** the ssl state */ SSL* ssl; #endif /** file descriptor */ int fd; /** the rc this is part of */ struct daemon_remote* rc; /** stats list next item */ struct rc_state* stats_next; }; /** * list of events for accepting connections */ struct acceptlist { struct acceptlist* next; int event_added; struct event c; char* ident; struct daemon_remote* rc; }; /** * The remote control state. */ struct daemon_remote { /** the master process for this remote control */ struct xfrd_state* xfrd; /** commpoints for accepting remote control connections */ struct acceptlist* accept_list; /* if certificates are used */ int use_cert; /** number of active commpoints that are handling remote control */ int active; /** max active commpoints */ int max_active; /** current commpoints busy; double linked, malloced */ struct rc_state* busy_list; /** last time stats was reported */ struct timeval stats_time, boot_time; #ifdef HAVE_SSL /** the SSL context for creating new SSL streams */ SSL_CTX* ctx; #endif }; /** * Connection to print to, either SSL or plain over fd */ struct remote_stream { #ifdef HAVE_SSL /** SSL structure, nonNULL if using SSL */ SSL* ssl; #endif /** file descriptor for plain transfer */ int fd; }; typedef struct remote_stream RES; /** * Print fixed line of text over ssl connection in blocking mode * @param res: print to * @param text: the text. * @return false on connection failure. */ static int ssl_print_text(RES* res, const char* text); /** * printf style printing to the ssl connection * @param res: the RES connection to print to. Blocking. * @param format: printf style format string. * @return success or false on a network failure. */ static int ssl_printf(RES* res, const char* format, ...) ATTR_FORMAT(printf, 2, 3); /** * Read until \n is encountered * If stream signals EOF, the string up to then is returned (without \n). * @param res: the RES connection to read from. blocking. * @param buf: buffer to read to. * @param max: size of buffer. * @return false on connection failure. */ static int ssl_read_line(RES* res, char* buf, size_t max); /** perform the accept of a new remote control connection */ static void remote_accept_callback(int fd, short event, void* arg); /** perform remote control */ static void remote_control_callback(int fd, short event, void* arg); /** ---- end of private defines ---- **/ #ifdef HAVE_SSL /** log ssl crypto err */ static void log_crypto_err(const char* str) { /* error:[error code]:[library name]:[function name]:[reason string] */ char buf[128]; unsigned long e; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); log_msg(LOG_ERR, "%s crypto %s", str, buf); while( (e=ERR_get_error()) ) { ERR_error_string_n(e, buf, sizeof(buf)); log_msg(LOG_ERR, "and additionally crypto %s", buf); } } #endif /* HAVE_SSL */ #ifdef BIND8_STATS /** subtract timers and the values do not overflow or become negative */ void timeval_subtract(struct timeval* d, const struct timeval* end, const struct timeval* start) { #ifndef S_SPLINT_S time_t end_usec = end->tv_usec; d->tv_sec = end->tv_sec - start->tv_sec; if(end_usec < start->tv_usec) { end_usec += 1000000; d->tv_sec--; } d->tv_usec = end_usec - start->tv_usec; #endif } #endif /* BIND8_STATS */ #ifdef HAVE_SSL static int remote_setup_ctx(struct daemon_remote* rc, struct nsd_options* cfg) { char* s_cert = cfg->server_cert_file; char* s_key = cfg->server_key_file; rc->ctx = server_tls_ctx_setup(s_key, s_cert, s_cert); if(!rc->ctx) { log_msg(LOG_ERR, "could not setup remote control TLS context"); return 0; } return 1; } #endif /* HAVE_SSL */ struct daemon_remote* daemon_remote_create(struct nsd_options* cfg) { struct daemon_remote* rc = (struct daemon_remote*)xalloc_zero( sizeof(*rc)); rc->max_active = 10; assert(cfg->control_enable); if(options_remote_is_address(cfg)) { #ifdef HAVE_SSL if(!remote_setup_ctx(rc, cfg)) { daemon_remote_delete(rc); return NULL; } rc->use_cert = 1; #else log_msg(LOG_ERR, "Could not setup remote control: NSD was compiled without SSL."); #endif /* HAVE_SSL */ } else { struct ip_address_option* o; #ifdef HAVE_SSL rc->ctx = NULL; #endif rc->use_cert = 0; for(o = cfg->control_interface; o; o = o->next) { if(o->address && o->address[0] != '/') log_msg(LOG_WARNING, "control-interface %s is not using TLS, but plain transfer, because first control-interface in config file is a local socket (starts with a /).", o->address); } } /* and try to open the ports */ if(!daemon_remote_open_ports(rc, cfg)) { log_msg(LOG_ERR, "could not open remote control port"); daemon_remote_delete(rc); return NULL; } if(gettimeofday(&rc->boot_time, NULL) == -1) log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); rc->stats_time = rc->boot_time; return rc; } void daemon_remote_close(struct daemon_remote* rc) { struct rc_state* p, *np; struct acceptlist* h, *nh; if(!rc) return; /* close listen sockets */ h = rc->accept_list; while(h) { nh = h->next; if(h->event_added) event_del(&h->c); close(h->c.ev_fd); free(h->ident); free(h); h = nh; } rc->accept_list = NULL; /* close busy connection sockets */ p = rc->busy_list; while(p) { np = p->next; if(p->event_added) event_del(&p->c); #ifdef HAVE_SSL if(p->ssl) SSL_free(p->ssl); #endif close(p->c.ev_fd); free(p); p = np; } rc->busy_list = NULL; rc->active = 0; } void daemon_remote_delete(struct daemon_remote* rc) { if(!rc) return; daemon_remote_close(rc); #ifdef HAVE_SSL if(rc->ctx) { SSL_CTX_free(rc->ctx); } #endif free(rc); } static int create_tcp_accept_sock(struct addrinfo* addr, int* noproto) { #if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU))) int on = 1; #endif int s; *noproto = 0; if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) { *noproto = 1; log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); return -1; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } #ifdef SO_REUSEADDR if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); } #endif /* SO_REUSEADDR */ #if defined(INET6) && defined(IPV6_V6ONLY) if (addr->ai_family == AF_INET6 && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); close(s); return -1; } #endif /* set it nonblocking */ /* (StevensUNP p463), if tcp listening socket is blocking, then it may block in accept, even if select() says readable. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno)); } /* Bind it... */ if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); close(s); return -1; } /* Listen to it... */ if (listen(s, TCP_BACKLOG_REMOTE) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); close(s); return -1; } return s; } /** * Add and open a new control port * @param rc: rc with result list. * @param ip: ip str * @param nr: port nr * @param noproto_is_err: if lack of protocol support is an error. * @return false on failure. */ static int add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip, int nr, int noproto_is_err) { struct addrinfo hints; struct addrinfo* res; struct acceptlist* hl; int noproto = 0; int fd, r; char port[15]; snprintf(port, sizeof(port), "%d", nr); port[sizeof(port)-1]=0; memset(&hints, 0, sizeof(hints)); assert(ip); if(ip[0] == '/') { /* This looks like a local socket */ fd = create_local_accept_sock(ip, &noproto); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same * group as the user we run as. */ if(fd != -1) { #ifdef HAVE_CHOWN if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) { VERBOSITY(3, (LOG_INFO, "cannot chmod control socket %s: %s", ip, strerror(errno))); } if (cfg->username && cfg->username[0] && nsd.uid != (uid_t)-1) { if(chown(ip, nsd.uid, nsd.gid) == -1) VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s", (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror(errno))); } #else (void)cfg; #endif } } else { hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; /* if we had no interface ip name, "default" is what we * would do getaddrinfo for. */ if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { log_msg(LOG_ERR, "control interface %s:%s getaddrinfo: %s %s", ip, port, gai_strerror(r), #ifdef EAI_SYSTEM r==EAI_SYSTEM?(char*)strerror(errno):"" #else "" #endif ); return 0; } /* open fd */ fd = create_tcp_accept_sock(res, &noproto); freeaddrinfo(res); } if(fd == -1 && noproto) { if(!noproto_is_err) return 1; /* return success, but do nothing */ log_msg(LOG_ERR, "cannot open control interface %s %d : " "protocol not supported", ip, nr); return 0; } if(fd == -1) { log_msg(LOG_ERR, "cannot open control interface %s %d", ip, nr); return 0; } /* alloc */ hl = (struct acceptlist*)xalloc_zero(sizeof(*hl)); hl->rc = rc; hl->ident = strdup(ip); if(!hl->ident) { log_msg(LOG_ERR, "malloc failure"); close(fd); free(hl); return 0; } hl->next = rc->accept_list; rc->accept_list = hl; hl->c.ev_fd = fd; hl->event_added = 0; return 1; } int daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg) { assert(cfg->control_enable && cfg->control_port); if(cfg->control_interface) { ip_address_option_type* p; for(p = cfg->control_interface; p; p = p->next) { if(!add_open(rc, cfg, p->address, cfg->control_port, 1)) { return 0; } } } else { /* defaults */ if(cfg->do_ip6 && !add_open(rc, cfg, "::1", cfg->control_port, 0)) { return 0; } if(cfg->do_ip4 && !add_open(rc, cfg, "127.0.0.1", cfg->control_port, 1)) { return 0; } } return 1; } void daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd) { int fd; struct acceptlist* p; if(!rc) return; rc->xfrd = xfrd; for(p = rc->accept_list; p; p = p->next) { /* add event */ fd = p->c.ev_fd; memset(&p->c, 0, sizeof(p->c)); event_set(&p->c, fd, EV_PERSIST|EV_READ, remote_accept_callback, p); if(event_base_set(xfrd->event_base, &p->c) != 0) log_msg(LOG_ERR, "remote: cannot set event_base"); if(event_add(&p->c, NULL) != 0) log_msg(LOG_ERR, "remote: cannot add event"); p->event_added = 1; } } static void remote_accept_callback(int fd, short event, void* arg) { struct acceptlist *hl = (struct acceptlist*)arg; struct daemon_remote *rc = hl->rc; #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; int newfd; struct rc_state* n; if (!(event & EV_READ)) { return; } /* perform the accept */ addrlen = sizeof(addr); #ifndef HAVE_ACCEPT4 newfd = accept(fd, (struct sockaddr*)&addr, &addrlen); #else newfd = accept4(fd, (struct sockaddr*)&addr, &addrlen, SOCK_NONBLOCK); #endif if(newfd == -1) { if ( errno != EINTR && errno != EWOULDBLOCK #ifdef ECONNABORTED && errno != ECONNABORTED #endif /* ECONNABORTED */ #ifdef EPROTO && errno != EPROTO #endif /* EPROTO */ ) { log_msg(LOG_ERR, "accept failed: %s", strerror(errno)); } return; } /* create new commpoint unless we are servicing already */ if(rc->active >= rc->max_active) { log_msg(LOG_WARNING, "drop incoming remote control: " "too many connections"); close_exit: close(newfd); return; } #ifndef HAVE_ACCEPT4 if (fcntl(newfd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); goto close_exit; } #endif /* setup state to service the remote control command */ n = (struct rc_state*)calloc(1, sizeof(*n)); if(!n) { log_msg(LOG_ERR, "out of memory"); goto close_exit; } n->tval.tv_sec = REMOTE_CONTROL_TCP_TIMEOUT; n->tval.tv_usec = 0L; n->fd = newfd; memset(&n->c, 0, sizeof(n->c)); event_set(&n->c, newfd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, n); if(event_base_set(xfrd->event_base, &n->c) != 0) { log_msg(LOG_ERR, "remote_accept: cannot set event_base"); free(n); goto close_exit; } if(event_add(&n->c, &n->tval) != 0) { log_msg(LOG_ERR, "remote_accept: cannot add event"); free(n); goto close_exit; } n->event_added = 1; if(2 <= verbosity) { if(hl->ident && hl->ident[0] == '/') { VERBOSITY(2, (LOG_INFO, "new control connection from %s", hl->ident)); } else { char s[128]; addr2str(&addr, s, sizeof(s)); VERBOSITY(2, (LOG_INFO, "new control connection from %s", s)); } } #ifdef HAVE_SSL if(rc->ctx) { n->shake_state = rc_hs_read; n->ssl = SSL_new(rc->ctx); if(!n->ssl) { log_crypto_err("could not SSL_new"); if(n->event_added) event_del(&n->c); free(n); goto close_exit; } SSL_set_accept_state(n->ssl); (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(n->ssl, newfd)) { log_crypto_err("could not SSL_set_fd"); if(n->event_added) event_del(&n->c); SSL_free(n->ssl); free(n); goto close_exit; } } else { n->ssl = NULL; } #endif /* HAVE_SSL */ n->rc = rc; n->stats_next = NULL; n->prev = NULL; n->next = rc->busy_list; if(n->next) n->next->prev = n; rc->busy_list = n; rc->active ++; /* perform the first nonblocking read already, for windows, * so it can return wouldblock. could be faster too. */ remote_control_callback(newfd, EV_READ, n); } /** delete from list */ static void state_list_remove_elem(struct rc_state** list, struct rc_state* todel) { if(todel->prev) todel->prev->next = todel->next; else *list = todel->next; if(todel->next) todel->next->prev = todel->prev; } /** decrease active count and remove commpoint from busy list */ static void clean_point(struct daemon_remote* rc, struct rc_state* s) { state_list_remove_elem(&rc->busy_list, s); rc->active --; if(s->event_added) event_del(&s->c); #ifdef HAVE_SSL if(s->ssl) { SSL_shutdown(s->ssl); SSL_free(s->ssl); } #endif /* HAVE_SSL */ close(s->c.ev_fd); free(s); } static int ssl_print_text(RES* res, const char* text) { if(!res) return 0; #ifdef HAVE_SSL if(res->ssl) { int r; ERR_clear_error(); if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { VERBOSITY(2, (LOG_WARNING, "in SSL_write, peer " "closed connection")); return 0; } log_crypto_err("could not SSL_write"); return 0; } } else { #endif /* HAVE_SSL */ if(write_socket(res->fd, text, strlen(text)) <= 0) { log_msg(LOG_ERR, "could not write: %s", strerror(errno)); return 0; } #ifdef HAVE_SSL } #endif /* HAVE_SSL */ return 1; } /** print text over the ssl connection */ static int ssl_print_vmsg(RES* ssl, const char* format, va_list args) { char msg[1024]; vsnprintf(msg, sizeof(msg), format, args); return ssl_print_text(ssl, msg); } /** printf style printing to the ssl connection */ static int ssl_printf(RES* ssl, const char* format, ...) { va_list args; int ret; va_start(args, format); ret = ssl_print_vmsg(ssl, format, args); va_end(args); return ret; } static int ssl_read_line(RES* res, char* buf, size_t max) { size_t len = 0; if(!res) return 0; while(len < max) { buf[len] = 0; /* terminate for safety and please checkers */ /* this byte is written if we read a byte from the input */ #ifdef HAVE_SSL if(res->ssl) { int r; ERR_clear_error(); if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { buf[len] = 0; return 1; } log_crypto_err("could not SSL_read"); return 0; } } else { #endif /* HAVE_SSL */ while(1) { ssize_t rr = read(res->fd, buf+len, 1); if(rr <= 0) { if(rr == 0) { buf[len] = 0; return 1; } if(errno == EINTR || errno == EAGAIN) continue; log_msg(LOG_ERR, "could not read: %s", strerror(errno)); return 0; } break; } #ifdef HAVE_SSL } #endif /* HAVE_SSL */ if(buf[len] == '\n') { /* return string without \n */ buf[len] = 0; return 1; } len++; } buf[max-1] = 0; log_msg(LOG_ERR, "control line too long (%d): %s", (int)max, buf); return 0; } /** skip whitespace, return new pointer into string */ static char* skipwhite(char* str) { /* EOS \0 is not a space */ while( isspace((unsigned char)*str) ) str++; return str; } /** send the OK to the control client */ static void send_ok(RES* ssl) { (void)ssl_printf(ssl, "ok\n"); } /** get zone argument (if any) or NULL, false on error */ static int get_zone_arg(RES* ssl, xfrd_state_type* xfrd, char* arg, struct zone_options** zo) { const dname_type* dname; if(!arg[0]) { /* no argument present, return NULL */ *zo = NULL; return 1; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name '%s'\n", arg); *zo = NULL; return 0; } *zo = zone_options_find(xfrd->nsd->options, dname); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); if(!*zo) { (void)ssl_printf(ssl, "error zone %s not configured\n", arg); return 0; } return 1; } /** do the stop command */ static void do_stop(RES* ssl, xfrd_state_type* xfrd) { xfrd->need_to_send_shutdown = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } send_ok(ssl); } /** do the log_reopen command, it only needs reload_now */ static void do_log_reopen(RES* ssl, xfrd_state_type* xfrd) { xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the reload command */ static void do_reload(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the write command */ static void do_write(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the notify command */ static void do_notify(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { struct notify_zone* n = (struct notify_zone*)rbtree_search( xfrd->notify_zones, (const dname_type*)zo->node.key); if(n) { xfrd_notify_start(n, xfrd); send_ok(ssl); } else { (void)ssl_printf(ssl, "error zone does not have notify\n"); } } else { struct notify_zone* n; RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones) { xfrd_notify_start(n, xfrd); } send_ok(ssl); } } /** do the transfer command */ static void do_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; xfrd_zone_type* zone; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); if(zone) { xfrd_handle_notify_and_start_xfr(zone, NULL); send_ok(ssl); } else { (void)ssl_printf(ssl, "error zone not secondary\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { xfrd_handle_notify_and_start_xfr(zone, NULL); } (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); } } /** force transfer a zone */ static void force_transfer_zone(xfrd_zone_type* zone) { /* if in TCP transaction, stop it immediately. */ if(zone->tcp_conn != -1) xfrd_tcp_release(xfrd->tcp_set, zone); else if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); /* pretend we not longer have it and force any * zone to be downloaded (even same serial, w AXFR) */ zone->soa_disk_acquired = 0; zone->soa_nsd_acquired = 0; xfrd_handle_notify_and_start_xfr(zone, NULL); } /** do the force transfer command */ static void do_force_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; xfrd_zone_type* zone; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); if(zone) { force_transfer_zone(zone); send_ok(ssl); } else { (void)ssl_printf(ssl, "error zone not secondary\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { force_transfer_zone(zone); } (void)ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); } } static int print_soa_status(RES* ssl, const char* str, xfrd_soa_type* soa, time_t acq) { if(acq) { if(!ssl_printf(ssl, " %s: \"%u since %s\"\n", str, (unsigned)ntohl(soa->serial), xfrd_pretty_time(acq))) return 0; } else { if(!ssl_printf(ssl, " %s: none\n", str)) return 0; } return 1; } /** print zonestatus for one domain */ static int print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo) { xfrd_zone_type* xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); struct notify_zone* nz = (struct notify_zone*)rbtree_search( xfrd->notify_zones, (const dname_type*)zo->node.key); if(!ssl_printf(ssl, "zone: %s\n", zo->name)) return 0; if(!zo->part_of_config) { if(!ssl_printf(ssl, " pattern: %s\n", zo->pattern->pname)) return 0; } if(zone_is_catalog_consumer(zo)) { zone_type* zone = namedb_find_zone(xfrd->nsd->db, (const dname_type*)zo->node.key); struct xfrd_catalog_consumer_zone* consumer_zone = (struct xfrd_catalog_consumer_zone*) rbtree_search( xfrd->catalog_consumer_zones , zo->node.key); if(!ssl_printf(ssl, " catalog: consumer")) return 0; if(zone && zone->soa_rrset && zone->soa_rrset->rrs && zone->soa_rrset->rrs[0].rdata_count > 2 && rdata_atom_size(zone->soa_rrset->rrs[0].rdatas[2]) == sizeof(uint32_t)) { if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n", read_uint32(rdata_atom_data( zone->soa_rrset->rrs[0].rdatas[2])), consumer_zone ? consumer_zone->member_ids.count : 0)) return 0; } else if(!ssl_printf(ssl, "\n")) return 0; if(invalid_catalog_consumer_zone(zo)) { if(!ssl_printf(ssl, " catalog-invalid: %s\n", invalid_catalog_consumer_zone(zo))) return 0; } } if(zone_is_catalog_producer(zo)) { struct xfrd_catalog_producer_zone* producer_zone = (struct xfrd_catalog_producer_zone*) rbtree_search( xfrd->catalog_producer_zones , zo->node.key); if(!ssl_printf(ssl, " catalog: producer")) return 0; if(producer_zone) { if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n", (unsigned)producer_zone->serial, producer_zone->member_ids.count)) return 0; } else if(!ssl_printf(ssl, "\n")) return 0; if (zone_is_slave(zo)) { if(!ssl_printf(ssl, " catalog-invalid: a catalog " "producer cannot be a secondary zone")) return 0; } } if(zone_is_catalog_member(zo)) { if(!ssl_printf(ssl, " catalog-member-id: %s\n", as_catalog_member_zone(zo)->member_id ? dname_to_string(as_catalog_member_zone(zo)->member_id, NULL) : "ERROR member-id is missing!")) return 0; } if(nz) { if(nz->is_waiting) { if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n")) return 0; } else if(nz->notify_send_enable || nz->notify_send6_enable) { int i; if(!ssl_printf(ssl, " notify: \"send")) return 0; for(i=0; ipkts[i].dest) continue; if(!ssl_printf(ssl, " %s", nz->pkts[i].dest->ip_address_spec)) return 0; } if(!ssl_printf(ssl, " with serial %u\"\n", (unsigned)ntohl(nz->current_soa->serial))) return 0; } } if(!xz) { if(!ssl_printf(ssl, " state: primary\n")) return 0; return 1; } if(!ssl_printf(ssl, " state: %s\n", xz->state == xfrd_zone_expired ? "expired" : xz->state != xfrd_zone_ok ? "refreshing" : !xz->soa_nsd_acquired || !xz->soa_disk_acquired || xz->soa_nsd.serial == xz->soa_disk.serial ? "ok" : compare_serial( ntohl(xz->soa_nsd.serial) , ntohl(xz->soa_disk.serial)) < 0 ? "old-serial" : "future-serial")) return 0; if(!print_soa_status(ssl, "served-serial", &xz->soa_nsd, xz->soa_nsd_acquired)) return 0; if(!print_soa_status(ssl, "commit-serial", &xz->soa_disk, xz->soa_disk_acquired)) return 0; if(xz->round_num != -1) { if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified, xz->soa_notified_acquired)) return 0; } else if(xz->event_added) { if(!ssl_printf(ssl, "\twait: \"%lu sec between attempts\"\n", (unsigned long)xz->timeout.tv_sec)) return 0; } /* UDP */ if(xz->udp_waiting) { if(!ssl_printf(ssl, " transfer: \"waiting-for-UDP-fd\"\n")) return 0; } else if(xz->zone_handler.ev_fd != -1 && xz->tcp_conn == -1) { if(!ssl_printf(ssl, " transfer: \"sent UDP to %s\"\n", xz->master->ip_address_spec)) return 0; } /* TCP */ if(xz->tcp_waiting) { if(!ssl_printf(ssl, " transfer: \"waiting-for-TCP-fd\"\n")) return 0; } else if(xz->tcp_conn != -1) { if(!ssl_printf(ssl, " transfer: \"TCP connected to %s\"\n", xz->master->ip_address_spec)) return 0; } return 1; } /** do the zonestatus command */ static void do_zonestatus(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) (void)print_zonestatus(ssl, xfrd, zo); else { RBTREE_FOR(zo, struct zone_options*, xfrd->nsd->options->zone_options) { if(!print_zonestatus(ssl, xfrd, zo)) return; } } } /** do the verbosity command */ static void do_verbosity(RES* ssl, char* str) { int val = atoi(str); if(strcmp(str, "") == 0) { (void)ssl_printf(ssl, "verbosity %d\n", verbosity); return; } if(val == 0 && strcmp(str, "0") != 0) { (void)ssl_printf(ssl, "error in verbosity number syntax: %s\n", str); return; } verbosity = val; task_new_set_verbosity(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, val); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** find second argument, modifies string */ static int find_arg2(RES* ssl, char* arg, char** arg2) { char* as = strrchr(arg, ' '); if(as) { as[0]=0; *arg2 = as+1; while(isspace((unsigned char)*as) && as > arg) as--; as[0]=0; return 1; } *arg2 = NULL; (void)ssl_printf(ssl, "error could not find next argument " "after %s\n", arg); return 0; } /** find second and third arguments, modifies string, * does not print error for missing arg3 so that if it does not find an * arg3, the caller can use two arguments. */ static int find_arg3(RES* ssl, char* arg, char** arg2, char** arg3) { if(find_arg2(ssl, arg, arg2)) { char* as; *arg3 = *arg2; as = strrchr(arg, ' '); if(as) { as[0]=0; *arg2 = as+1; while(isspace((unsigned char)*as) && as > arg) as--; as[0]=0; return 1; } } *arg3 = NULL; return 0; } /** do the status command */ static void do_status(RES* ssl, xfrd_state_type* xfrd) { if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION)) return; if(!ssl_printf(ssl, "verbosity: %d\n", verbosity)) return; #ifdef RATELIMIT if(!ssl_printf(ssl, "ratelimit: %d\n", (int)xfrd->nsd->options->rrl_ratelimit)) return; #else (void)xfrd; #endif } /** do the stats command */ static void do_stats(RES* ssl, xfrd_state_type* xfrd, int peek) { #ifdef BIND8_STATS process_stats(ssl, NULL, xfrd, peek); #else (void)xfrd; (void)peek; (void)ssl_printf(ssl, "error no stats enabled at compile time\n"); #endif /* BIND8_STATS */ } /** see if we have more zonestatistics entries and it has to be incremented */ static void zonestat_inc_ifneeded(xfrd_state_type* xfrd) { #ifdef USE_ZONE_STATS if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe) task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, xfrd->nsd->options->zonestatnames->count); #else (void)xfrd; #endif /* USE_ZONE_STATS */ } /** perform the changezone command for one zone */ static int perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; char* arg2 = NULL; if(!find_arg2(ssl, arg, &arg2)) return 0; /* if we add it to the xfrd now, then xfrd could download AXFR and * store it and the NSD-reload would see it in the difffile before * it sees the add-config task. */ /* thus: AXFRs and IXFRs must store the pattern name in the * difffile, so that it can be added when the AXFR or IXFR is seen. */ /* check that the pattern exists */ if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { (void)ssl_printf(ssl, "error pattern %s does not exist\n", arg2); return 0; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if zone is a duplicate */ if( (zopt=zone_options_find(xfrd->nsd->options, dname)) ) { if(zopt->part_of_config) { (void)ssl_printf(ssl, "error zone defined in nsd.conf, " "cannot delete it in this manner: remove it from " "nsd.conf yourself and repattern\n"); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; return 0; } if(zone_is_catalog_consumer_member(zopt)) { (void)ssl_printf(ssl, "Error: Zone is a catalog " "consumer member zone with id %s\nRepattern in the " "catalog with a group property.\n", dname_to_string( as_catalog_member_zone(zopt)->member_id, NULL)); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; return 0; } /* found the zone, now delete it */ /* create deletion task */ /* this deletion task is processed before the addition task, * that is created below, in the same reload process, causing * a seamless change from one to the other, with no downtime * for the zone. */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete it in xfrd's catalog consumers list */ if(zone_is_catalog_consumer(zopt)) { xfrd_deinit_catalog_consumer_zone(xfrd, dname); } /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); } else { (void)ssl_printf(ssl, "zone %s did not exist, creating", arg); } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; /* add to zonelist and adds to config in memory */ zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2, xfrd_add_catalog_producer_member); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); return 0; } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, arg, arg2, getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); /* add to xfrd - catalog consumer zones */ if (zone_is_catalog_consumer(zopt)) { xfrd_init_catalog_consumer_zone(xfrd, zopt); } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } return 1; } /** perform the addzone command for one zone */ static int perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; char* arg2 = NULL; if(!find_arg2(ssl, arg, &arg2)) return 0; /* if we add it to the xfrd now, then xfrd could download AXFR and * store it and the NSD-reload would see it in the difffile before * it sees the add-config task. */ /* thus: AXFRs and IXFRs must store the pattern name in the * difffile, so that it can be added when the AXFR or IXFR is seen. */ /* check that the pattern exists */ if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { (void)ssl_printf(ssl, "error pattern %s does not exist\n", arg2); return 0; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if zone is a duplicate */ if( zone_options_find(xfrd->nsd->options, dname) ) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); (void)ssl_printf(ssl, "zone %s already exists\n", arg); return 1; } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; /* add to zonelist and adds to config in memory */ zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2, xfrd_add_catalog_producer_member); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); return 0; } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, arg, arg2, getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); /* add to xfrd - catalog consumer zones */ if (zone_is_catalog_consumer(zopt)) { xfrd_init_catalog_consumer_zone(xfrd, zopt); } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } return 1; } /** perform the delzone command for one zone */ static int perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; /* dont recycle dname when it becomes part of a xfrd_producer_member */ int recycle_dname = 1; dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if we have the zone in question */ zopt = zone_options_find(xfrd->nsd->options, dname); if(!zopt) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); /* nothing to do */ (void)ssl_printf(ssl, "warning zone %s not present\n", arg); return 0; } /* see if it can be deleted */ if(zopt->part_of_config) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); (void)ssl_printf(ssl, "error zone defined in nsd.conf, " "cannot delete it in this manner: remove it from " "nsd.conf yourself and repattern\n"); return 0; } if(zone_is_catalog_consumer_member(zopt) && as_catalog_member_zone(zopt)->member_id) { (void)ssl_printf(ssl, "Error: Zone is a catalog consumer " "member zone with id %s\nRemove the member id from the " "catalog to delete this zone.\n", dname_to_string( as_catalog_member_zone(zopt)->member_id, NULL)); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; return 0; } /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete it in xfrd's catalog consumers list */ if(zone_is_catalog_consumer(zopt)) { xfrd_deinit_catalog_consumer_zone(xfrd, dname); } else { recycle_dname = !xfrd_del_catalog_producer_member(xfrd, dname); } /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); if(recycle_dname) region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); return 1; } /** do the addzone command */ static void do_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_addzone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the delzone command */ static void do_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_delzone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the changezone command */ static void do_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_changezone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the addzones command */ static void do_addzones(RES* ssl, xfrd_state_type* xfrd) { char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { if(buf[0] == 0x04 && buf[1] == 0) break; /* end of transmission */ if(!perform_addzone(ssl, xfrd, buf)) { if(!ssl_printf(ssl, "error for input line '%s'\n", buf)) return; } else { if(!ssl_printf(ssl, "added: %s\n", buf)) return; num++; } } (void)ssl_printf(ssl, "added %d zones\n", num); } /** do the delzones command */ static void do_delzones(RES* ssl, xfrd_state_type* xfrd) { char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { if(buf[0] == 0x04 && buf[1] == 0) break; /* end of transmission */ if(!perform_delzone(ssl, xfrd, buf)) { if(!ssl_printf(ssl, "error for input line '%s'\n", buf)) return; } else { if(!ssl_printf(ssl, "removed: %s\n", buf)) return; num++; } } (void)ssl_printf(ssl, "deleted %d zones\n", num); } /** remove TSIG key from config and add task so that reload does too */ static void remove_key(xfrd_state_type* xfrd, const char* kname) { /* add task before deletion because the name string could be deleted */ task_new_del_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, kname); key_options_remove(xfrd->nsd->options, kname); xfrd_set_reload_now(xfrd); /* this is executed when the current control command ends, thus the entire config changes are bunched up */ } /** add TSIG key to config and add task so that reload does too */ static void add_key(xfrd_state_type* xfrd, struct key_options* k) { key_options_add_modify(xfrd->nsd->options, k); task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, k); xfrd_set_reload_now(xfrd); } /** check if keys have changed */ static void repat_keys(xfrd_state_type* xfrd, struct nsd_options* newopt) { struct nsd_options* oldopt = xfrd->nsd->options; struct key_options* k; /* find deleted keys */ k = (struct key_options*)rbtree_first(oldopt->keys); while((rbnode_type*)k != RBTREE_NULL) { struct key_options* next = (struct key_options*)rbtree_next( (rbnode_type*)k); if(!key_options_find(newopt, k->name)) remove_key(xfrd, k->name); k = next; } /* find added or changed keys */ RBTREE_FOR(k, struct key_options*, newopt->keys) { struct key_options* origk = key_options_find(oldopt, k->name); if(!origk) add_key(xfrd, k); else if(!key_options_equal(k, origk)) add_key(xfrd, k); } } /** find zone given the implicit pattern */ static const dname_type* parse_implicit_name(xfrd_state_type* xfrd,const char* pname) { if(strncmp(pname, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)) != 0) return NULL; return dname_parse(xfrd->region, pname + strlen(PATTERN_IMPLICIT_MARKER)); } /** remove cfgzone and add task so that reload does too */ static void remove_cfgzone(xfrd_state_type* xfrd, const char* pname) { /* dname and find the zone for the implicit pattern */ struct zone_options* zopt = NULL; const dname_type* dname = parse_implicit_name(xfrd, pname); if(!dname) { /* should have a parseable name, but it did not */ return; } /* find the zone entry for the implicit pattern */ zopt = zone_options_find(xfrd->nsd->options, dname); if(!zopt) { /* this should not happen; implicit pattern has zone entry */ region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); return; } /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete it in xfrd's catalog consumers list */ if(zone_is_catalog_consumer(zopt)) { xfrd_deinit_catalog_consumer_zone(xfrd, dname); } /* delete from zoneoptions */ zone_options_delete(xfrd->nsd->options, zopt); /* recycle parsed dname */ region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); } /** add cfgzone and add task so that reload does too */ static void add_cfgzone(xfrd_state_type* xfrd, const char* pname) { /* add to our zonelist */ struct zone_options* zopt = zone_options_create( xfrd->nsd->options->region); if(!zopt) return; zopt->part_of_config = 1; zopt->name = region_strdup(xfrd->nsd->options->region, pname + strlen(PATTERN_IMPLICIT_MARKER)); zopt->pattern = pattern_options_find(xfrd->nsd->options, pname); if(!zopt->name || !zopt->pattern) return; if(!nsd_options_insert_zone(xfrd->nsd->options, zopt)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", zopt->name, pname); } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zopt->name, pname, getzonestatid(xfrd->nsd->options, zopt)); /* zonestat_inc is done after the entire config file has been done */ xfrd_set_reload_now(xfrd); /* add to xfrd - catalog consumer zones */ if (zone_is_catalog_consumer(zopt)) { xfrd_init_catalog_consumer_zone(xfrd, zopt); } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } } /** remove pattern and add task so that reload does too */ static void remove_pat(xfrd_state_type* xfrd, const char* name) { /* add task before deletion, because name-string could be deleted */ task_new_del_pattern(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, name); pattern_options_remove(xfrd->nsd->options, name); xfrd_set_reload_now(xfrd); } /** add pattern and add task so that reload does too */ static void add_pat(xfrd_state_type* xfrd, struct pattern_options* p) { pattern_options_add_modify(xfrd->nsd->options, p); task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, p); xfrd_set_reload_now(xfrd); } /** interrupt zones that are using changed or removed patterns */ static void repat_interrupt_zones(xfrd_state_type* xfrd, struct nsd_options* newopt) { /* if masterlist changed: * interrupt slave zone (UDP or TCP) transfers. * slave zones reset master to start of list. */ xfrd_zone_type* xz; struct notify_zone* nz; RBTREE_FOR(xz, xfrd_zone_type*, xfrd->zones) { struct pattern_options* oldp = xz->zone_options->pattern; struct pattern_options* newp = pattern_options_find(newopt, oldp->pname); if(!newp || !acl_list_equal(oldp->request_xfr, newp->request_xfr)) { /* interrupt transfer */ if(xz->tcp_conn != -1) { xfrd_tcp_release(xfrd->tcp_set, xz); xfrd_set_refresh_now(xz); } else if(xz->zone_handler.ev_fd != -1) { xfrd_udp_release(xz); xfrd_set_refresh_now(xz); } xz->master = 0; xz->master_num = 0; xz->next_master = -1; xz->round_num = -1; /* fresh set of retries */ } } /* if notify list changed: * interrupt notify that is busy. * reset notify to start of list. (clear all other reset_notify) */ RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) { struct pattern_options* oldp = nz->options->pattern; struct pattern_options* newp = pattern_options_find(newopt, oldp->pname); if(!newp || !acl_list_equal(oldp->notify, newp->notify)) { /* interrupt notify */ if(nz->notify_send_enable) { notify_disable(nz); /* set to restart the notify after the * pattern has been changed. */ nz->notify_restart = 2; } else { nz->notify_restart = 1; } } else { nz->notify_restart = 0; } } } /** for notify, after the pattern changes, restart the affected notifies */ static void repat_interrupt_notify_start(xfrd_state_type* xfrd) { struct notify_zone* nz; RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) { if(nz->notify_restart) { if(nz->notify_current) nz->notify_current = nz->options->pattern->notify; if(nz->notify_restart == 2) { if(nz->notify_restart) xfrd_notify_start(nz, xfrd); } } } } /** check if patterns have changed */ static void repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) { /* zones that use changed patterns must have: * - their AXFR/IXFR interrupted: try again, acl may have changed. * if the old master/key still exists, OK, fix master-numptrs and * keep going. Otherwise, stop xfer and reset TSIG. * - send NOTIFY reset to start of NOTIFY list (and TSIG reset). */ struct nsd_options* oldopt = xfrd->nsd->options; struct pattern_options* p; int search_zones = 0; repat_interrupt_zones(xfrd, newopt); /* find deleted patterns */ p = (struct pattern_options*)rbtree_first(oldopt->patterns); while((rbnode_type*)p != RBTREE_NULL) { struct pattern_options* next = (struct pattern_options*) rbtree_next((rbnode_type*)p); if(!pattern_options_find(newopt, p->pname)) { if(p->implicit) { /* first remove its zone */ VERBOSITY(1, (LOG_INFO, "zone removed from config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER))); remove_cfgzone(xfrd, p->pname); } remove_pat(xfrd, p->pname); } p = next; } /* find added or changed patterns */ RBTREE_FOR(p, struct pattern_options*, newopt->patterns) { struct pattern_options* origp = pattern_options_find(oldopt, p->pname); if(!origp) { /* no zones can use it, no zone_interrupt needed */ add_pat(xfrd, p); if(p->implicit) { VERBOSITY(1, (LOG_INFO, "zone added to config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER))); add_cfgzone(xfrd, p->pname); } } else if(!pattern_options_equal(p, origp)) { uint8_t newstate = 0; if (p->request_xfr && !origp->request_xfr) { newstate = REPAT_SLAVE; } else if (!p->request_xfr && origp->request_xfr) { newstate = REPAT_MASTER; } if ( p->catalog_role == CATALOG_ROLE_CONSUMER && origp->catalog_role != CATALOG_ROLE_CONSUMER) { newstate |= REPAT_CATALOG_CONSUMER; } else if (p->catalog_role != CATALOG_ROLE_CONSUMER && origp->catalog_role == CATALOG_ROLE_CONSUMER) { newstate |= REPAT_CATALOG_CONSUMER_DEINIT; } add_pat(xfrd, p); if (p->implicit && newstate) { const dname_type* dname = parse_implicit_name(xfrd, p->pname); if (dname) { if (newstate & REPAT_SLAVE) { struct zone_options* zopt = zone_options_find( oldopt, dname); if (zopt) { xfrd_init_slave_zone( xfrd, zopt); } } else if (newstate & REPAT_MASTER) { xfrd_del_slave_zone(xfrd, dname); } if (newstate & REPAT_CATALOG_CONSUMER) { struct zone_options* zopt = zone_options_find( oldopt, dname); if (zopt) { xfrd_init_catalog_consumer_zone( xfrd, zopt); } } else if (newstate & REPAT_CATALOG_CONSUMER_DEINIT) { xfrd_deinit_catalog_consumer_zone( xfrd, dname); } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); } } else if(!p->implicit && newstate) { /* search all zones with this pattern */ search_zones = 1; origp->xfrd_flags = newstate; } } } if (search_zones) { struct zone_options* zone_opt; /* search in oldopt because 1) it contains zonelist zones, * and 2) you need oldopt(existing) to call xfrd_init */ RBTREE_FOR(zone_opt, struct zone_options*, oldopt->zone_options) { struct pattern_options* oldp = zone_opt->pattern; if (!oldp->implicit) { if (oldp->xfrd_flags & REPAT_SLAVE) { /* xfrd needs stable reference so get * it from the oldopt(modified) tree */ xfrd_init_slave_zone(xfrd, zone_opt); } else if (oldp->xfrd_flags & REPAT_MASTER) { xfrd_del_slave_zone(xfrd, (const dname_type*) zone_opt->node.key); } if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER) { xfrd_init_catalog_consumer_zone(xfrd, zone_opt); } else if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER_DEINIT) { xfrd_deinit_catalog_consumer_zone(xfrd, (const dname_type*) zone_opt->node.key); } oldp->xfrd_flags = 0; } } } repat_interrupt_notify_start(xfrd); } /** true if options are different that can be set via repat. */ static int repat_options_changed(xfrd_state_type* xfrd, struct nsd_options* newopt) { #ifdef RATELIMIT if(xfrd->nsd->options->rrl_ratelimit != newopt->rrl_ratelimit) return 1; if(xfrd->nsd->options->rrl_whitelist_ratelimit != newopt->rrl_whitelist_ratelimit) return 1; if(xfrd->nsd->options->rrl_slip != newopt->rrl_slip) return 1; #else (void)xfrd; (void)newopt; #endif return 0; } static int opt_str_changed(const char* old, const char* new) { return !old ? ( !new ? 0 : 1 ) : ( !new ? 1 : strcasecmp(old, new) ); } /** true if cookie options are different that can be set via repat. */ static int repat_cookie_options_changed(struct nsd_options* old, struct nsd_options* new) { return old->answer_cookie != new->answer_cookie || opt_str_changed( old->cookie_secret , new->cookie_secret) || opt_str_changed( old->cookie_staging_secret , new->cookie_staging_secret) || old->cookie_secret_file_is_default != new->cookie_secret_file_is_default || opt_str_changed( old->cookie_secret_file , new->cookie_secret_file); } /** check if global options have changed */ static void repat_options(xfrd_state_type* xfrd, struct nsd_options* newopt) { struct nsd_options* oldopt = xfrd->nsd->options; if(repat_options_changed(xfrd, newopt)) { /* update our options */ #ifdef RATELIMIT oldopt->rrl_ratelimit = newopt->rrl_ratelimit; oldopt->rrl_whitelist_ratelimit = newopt->rrl_whitelist_ratelimit; oldopt->rrl_slip = newopt->rrl_slip; #endif task_new_opt_change(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, newopt); xfrd_set_reload_now(xfrd); } if(repat_cookie_options_changed(oldopt, newopt)) { /* update our options */ oldopt->answer_cookie = newopt->answer_cookie; region_str_replace( oldopt->region , &oldopt->cookie_secret , newopt->cookie_secret); region_str_replace( oldopt->region , &oldopt->cookie_staging_secret , newopt->cookie_staging_secret); oldopt->cookie_secret_file_is_default = newopt->cookie_secret_file_is_default; region_str_replace( oldopt->region , &oldopt->cookie_secret_file , newopt->cookie_secret_file); xfrd->nsd->cookie_count = 0; xfrd->nsd->cookie_secrets_source = COOKIE_SECRETS_NONE; reconfig_cookies(xfrd->nsd, newopt); task_new_cookies( xfrd->nsd->task[xfrd->nsd->mytask] , xfrd->last_task , xfrd->nsd->do_answer_cookie , xfrd->nsd->cookie_count , xfrd->nsd->cookie_secrets); xfrd_set_reload_now(xfrd); } } /** print errors over ssl, gets pointer-to-pointer to ssl, so it can set * the pointer to NULL on failure and stop printing */ static void print_ssl_cfg_err(void* arg, const char* str) { RES** ssl = (RES**)arg; if(!*ssl) return; if(!ssl_printf(*ssl, "%s", str)) *ssl = NULL; /* failed, stop printing */ } /** do the repattern command: reread config file and apply keys, patterns */ static void do_repattern(RES* ssl, xfrd_state_type* xfrd) { region_type* region = region_create(xalloc, free); struct nsd_options* opt; const char* cfgfile = xfrd->nsd->options->configfile; /* check chroot and configfile, if possible to reread */ if(xfrd->nsd->chrootdir) { size_t l = strlen(xfrd->nsd->chrootdir); while(l>0 && xfrd->nsd->chrootdir[l-1] == '/') --l; if(strncmp(xfrd->nsd->chrootdir, cfgfile, l) != 0) { (void)ssl_printf(ssl, "error %s is not relative to %s: " "chroot prevents reread of config\n", cfgfile, xfrd->nsd->chrootdir); region_destroy(region); return; } cfgfile += l; } (void)ssl_printf(ssl, "reconfig start, read %s\n", cfgfile); opt = nsd_options_create(region); if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl, xfrd->nsd->options)) { /* error already printed */ region_destroy(region); return; } /* check for differences in TSIG keys and patterns, and apply, * first the keys, so that pattern->keyptr can be set right. */ repat_keys(xfrd, opt); repat_patterns(xfrd, opt); repat_options(xfrd, opt); zonestat_inc_ifneeded(xfrd); send_ok(ssl); region_destroy(region); } static void print_cfg_err(void *unused, const char *message) { (void)unused; log_msg(LOG_ERR, "%s", message); } /* mostly identical to do_repattern */ void xfrd_reload_config(xfrd_state_type *xfrd) { const char *chrootdir = xfrd->nsd->chrootdir; const char *file = xfrd->nsd->options->configfile; region_type* region; struct nsd_options* options; if (chrootdir && !file_inside_chroot(file, chrootdir)) { log_msg(LOG_ERR, "%s is not relative to %s: %s", xfrd->nsd->options->configfile, xfrd->nsd->chrootdir, "chroot prevents reread of config"); goto error_chroot; } region = region_create(xalloc, free); options = nsd_options_create(region); if (!parse_options_file( options, file, print_cfg_err, NULL, xfrd->nsd->options)) { goto error_parse; } repat_keys(xfrd, options); repat_patterns(xfrd, options); /* adds/deletes zones too */ repat_options(xfrd, options); zonestat_inc_ifneeded(xfrd); error_parse: region_destroy(region); error_chroot: return; } /** do the serverpid command: printout pid of server process */ static void do_serverpid(RES* ssl, xfrd_state_type* xfrd) { (void)ssl_printf(ssl, "%u\n", (unsigned)xfrd->reload_pid); } /** do the print_tsig command: printout tsig info */ static void do_print_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(*arg == '\0') { struct key_options* key; RBTREE_FOR(key, struct key_options*, xfrd->nsd->options->keys) { if(!ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", key->name, key->secret, key->algorithm)) return; } return; } else { struct key_options* key_opts = key_options_find(xfrd->nsd->options, arg); if(!key_opts) { (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg); return; } else { (void)ssl_printf(ssl, "key: name: \"%s\" secret: \"%s\" algorithm: %s\n", arg, key_opts->secret, key_opts->algorithm); } } } /** do the update_tsig command: change existing tsig to new secret */ static void do_update_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct region* region = xfrd->nsd->options->region; char* arg2 = NULL; uint8_t data[65536]; /* 64K */ struct key_options* key_opt; if(*arg == '\0') { (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); return; } if(!find_arg2(ssl, arg, &arg2)) { (void)ssl_printf(ssl, "error: missing argument (secret)\n"); return; } key_opt = key_options_find(xfrd->nsd->options, arg); if(!key_opt) { (void)ssl_printf(ssl, "error: no such key with name: %s\n", arg); memset(arg2, 0xdd, strlen(arg2)); return; } if(b64_pton(arg2, data, sizeof(data)) == -1) { (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2); memset(data, 0xdd, sizeof(data)); /* wipe secret */ memset(arg2, 0xdd, strlen(arg2)); return; } log_msg(LOG_INFO, "changing secret provided with the key: %s with old secret %s and algo: %s\n", arg, key_opt->secret, key_opt->algorithm); if(key_opt->secret) { /* wipe old secret */ memset(key_opt->secret, 0xdd, strlen(key_opt->secret)); region_recycle(region, key_opt->secret, strlen(key_opt->secret)+1); } key_opt->secret = region_strdup(region, arg2); log_msg(LOG_INFO, "the key: %s has new secret %s and algorithm: %s\n", arg, key_opt->secret, key_opt->algorithm); /* wipe secret from temp parse buffer */ memset(arg2, 0xdd, strlen(arg2)); memset(data, 0xdd, sizeof(data)); key_options_desetup(region, key_opt); key_options_setup(region, key_opt); task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, key_opt); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the add tsig command, add new key with name, secret and algo given */ static void do_add_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { char* arg2 = NULL; char* arg3 = NULL; uint8_t data[65536]; /* 64KB */ uint8_t dname[MAXDOMAINLEN+1]; char algo[256]; region_type* region = xfrd->nsd->options->region; struct key_options* new_key_opt; if(*arg == '\0') { (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); return; } if(!find_arg3(ssl, arg, &arg2, &arg3)) { strlcpy(algo, "hmac-sha256", sizeof(algo)); } else { strlcpy(algo, arg3, sizeof(algo)); } if(!arg2) { (void)ssl_printf(ssl, "error: missing argument (secret)\n"); return; } if(key_options_find(xfrd->nsd->options, arg)) { (void)ssl_printf(ssl, "error: key %s already exists\n", arg); memset(arg2, 0xdd, strlen(arg2)); return; } if(b64_pton(arg2, data, sizeof(data)) == -1) { (void)ssl_printf(ssl, "error: the secret: %s is not in b64 format\n", arg2); memset(data, 0xdd, sizeof(data)); /* wipe secret */ memset(arg2, 0xdd, strlen(arg2)); return; } memset(data, 0xdd, sizeof(data)); /* wipe secret from temp buffer */ if(!dname_parse_wire(dname, arg)) { (void)ssl_printf(ssl, "error: could not parse key name: %s\n", arg); memset(arg2, 0xdd, strlen(arg2)); return; } if(tsig_get_algorithm_by_name(algo) == NULL) { (void)ssl_printf(ssl, "error: unknown algorithm: %s\n", algo); memset(arg2, 0xdd, strlen(arg2)); return; } log_msg(LOG_INFO, "adding key with name: %s and secret: %s with algo: %s\n", arg, arg2, algo); new_key_opt = key_options_create(region); new_key_opt->name = region_strdup(region, arg); new_key_opt->secret = region_strdup(region, arg2); new_key_opt->algorithm = region_strdup(region, algo); add_key(xfrd, new_key_opt); /* wipe secret from temp buffer */ memset(arg2, 0xdd, strlen(arg2)); send_ok(ssl); } /** set acl entries to use the given TSIG key */ static void zopt_set_acl_to_tsig(struct acl_options* acl, struct region* region, const char* key_name, struct key_options* key_opt) { while(acl) { if(acl->blocked) { acl = acl->next; continue; } acl->nokey = 0; if(acl->key_name) region_recycle(region, (void*)acl->key_name, strlen(acl->key_name)+1); acl->key_name = region_strdup(region, key_name); acl->key_options = key_opt; acl = acl->next; } } /** do the assoc_tsig command: associate the zone to use the tsig name */ static void do_assoc_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { region_type* region = xfrd->nsd->options->region; char* arg2 = NULL; struct zone_options* zone; struct key_options* key_opt; if(*arg == '\0') { (void)ssl_printf(ssl, "error: missing argument (zonename)\n"); return; } if(!find_arg2(ssl, arg, &arg2)) { (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); return; } if(!get_zone_arg(ssl, xfrd, arg, &zone)) return; if(!zone) { (void)ssl_printf(ssl, "error: missing argument (zone)\n"); return; } key_opt = key_options_find(xfrd->nsd->options, arg2); if(!key_opt) { (void)ssl_printf(ssl, "error: key: %s does not exist\n", arg2); return; } zopt_set_acl_to_tsig(zone->pattern->allow_notify, region, arg2, key_opt); zopt_set_acl_to_tsig(zone->pattern->notify, region, arg2, key_opt); zopt_set_acl_to_tsig(zone->pattern->request_xfr, region, arg2, key_opt); zopt_set_acl_to_tsig(zone->pattern->provide_xfr, region, arg2, key_opt); zopt_set_acl_to_tsig(zone->pattern->allow_query, region, arg2, key_opt); task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->pattern); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** see if TSIG key is used in the acl */ static int acl_contains_tsig_key(struct acl_options* acl, const char* name) { while(acl) { if(acl->key_name && strcmp(acl->key_name, name) == 0) return 1; acl = acl->next; } return 0; } /** do the del_tsig command, remove an (unused) tsig */ static void do_del_tsig(RES* ssl, xfrd_state_type* xfrd, char* arg) { int used_key = 0; struct zone_options* zone; struct key_options* key_opt; if(*arg == '\0') { (void)ssl_printf(ssl, "error: missing argument (keyname)\n"); return; } key_opt = key_options_find(xfrd->nsd->options, arg); if(!key_opt) { (void)ssl_printf(ssl, "key %s does not exist, nothing to be deleted\n", arg); return; } RBTREE_FOR(zone, struct zone_options*, xfrd->nsd->options->zone_options) { if(acl_contains_tsig_key(zone->pattern->allow_notify, arg) || acl_contains_tsig_key(zone->pattern->notify, arg) || acl_contains_tsig_key(zone->pattern->request_xfr, arg) || acl_contains_tsig_key(zone->pattern->provide_xfr, arg) || acl_contains_tsig_key(zone->pattern->allow_query, arg)) { if(!ssl_printf(ssl, "zone %s uses key %s\n", zone->name, arg)) return; used_key = 1; break; } } if(used_key) { (void)ssl_printf(ssl, "error: key: %s is in use and cannot be deleted\n", arg); return; } else { remove_key(xfrd, arg); log_msg(LOG_INFO, "key: %s is successfully deleted\n", arg); } send_ok(ssl); } static int can_dump_cookie_secrets(RES* ssl, nsd_type* const nsd) { if(!nsd->options->cookie_secret_file) (void)ssl_printf(ssl, "error: empty cookie-secret-file\n"); else if(nsd->cookie_secrets_source == COOKIE_SECRETS_FROM_CONFIG) (void)ssl_printf(ssl, "error: cookie secrets are already " "configured. Remove \"cookie-secret:\" and " "\"cookie-staging-secret:\" entries from configuration " "first (and reconfig) before managing cookies with " "nsd-control\n"); else return 1; return 0; } /* returns `0` on failure */ static int cookie_secret_file_dump_and_reload(RES* ssl, nsd_type* const nsd) { char secret_hex[NSD_COOKIE_SECRET_SIZE * 2 + 1]; FILE* f; size_t i; /* open write only and truncate */ if(!nsd->options->cookie_secret_file) { (void)ssl_printf(ssl, "cookie-secret-file empty\n"); return 0; } else if((f = fopen(nsd->options->cookie_secret_file, "w")) == NULL ) { (void)ssl_printf( ssl , "unable to open cookie secret file %s: %s\n" , nsd->options->cookie_secret_file , strerror(errno)); return 0; } for(i = 0; i < nsd->cookie_count; i++) { struct cookie_secret const* cs = &nsd->cookie_secrets[i]; ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE, secret_hex, sizeof(secret_hex)); (void)len; /* silence unused variable warning with -DNDEBUG */ assert( len == NSD_COOKIE_SECRET_SIZE * 2 ); secret_hex[NSD_COOKIE_SECRET_SIZE * 2] = '\0'; fprintf(f, "%s\n", secret_hex); } explicit_bzero(secret_hex, sizeof(secret_hex)); fclose(f); nsd->cookie_secrets_source = COOKIE_SECRETS_FROM_FILE; region_str_replace(nsd->region, &nsd->cookie_secrets_filename , nsd->options->cookie_secret_file); task_new_cookies(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, nsd->do_answer_cookie, nsd->cookie_count, nsd->cookie_secrets); xfrd_set_reload_now(xfrd); send_ok(ssl); return 1; } static void do_activate_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { nsd_type* nsd = xrfd->nsd; size_t backup_cookie_count; cookie_secrets_type backup_cookie_secrets; (void)arg; if(!can_dump_cookie_secrets(ssl, xfrd->nsd)) return; if(nsd->cookie_count <= 1 ) { (void)ssl_printf(ssl, "error: no staging cookie secret to activate\n"); return; } backup_cookie_count = nsd->cookie_count; memcpy( backup_cookie_secrets, nsd->cookie_secrets , sizeof(cookie_secrets_type)); activate_cookie_secret(nsd); if(!cookie_secret_file_dump_and_reload(ssl, nsd)) { memcpy( nsd->cookie_secrets, backup_cookie_secrets , sizeof(cookie_secrets_type)); nsd->cookie_count = backup_cookie_count; } explicit_bzero(backup_cookie_secrets, sizeof(cookie_secrets_type)); } static void do_drop_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { nsd_type* nsd = xrfd->nsd; size_t backup_cookie_count; cookie_secrets_type backup_cookie_secrets; (void)arg; if(!can_dump_cookie_secrets(ssl, xfrd->nsd)) return; if(nsd->cookie_count <= 1 ) { (void)ssl_printf(ssl, "error: can not drop the currently active cookie secret\n"); return; } backup_cookie_count = nsd->cookie_count; memcpy( backup_cookie_secrets, nsd->cookie_secrets , sizeof(cookie_secrets_type)); drop_cookie_secret(nsd); if(!cookie_secret_file_dump_and_reload(ssl, nsd)) { memcpy( nsd->cookie_secrets, backup_cookie_secrets , sizeof(cookie_secrets_type)); nsd->cookie_count = backup_cookie_count; } explicit_bzero(backup_cookie_secrets, sizeof(cookie_secrets_type)); } static void do_add_cookie_secret(RES* ssl, xfrd_state_type* xrfd, char* arg) { nsd_type* nsd = xrfd->nsd; uint8_t secret[NSD_COOKIE_SECRET_SIZE]; size_t backup_cookie_count; cookie_secrets_type backup_cookie_secrets; if(!can_dump_cookie_secrets(ssl, xfrd->nsd)) return; if(*arg == '\0') { (void)ssl_printf(ssl, "error: missing argument (cookie_secret)\n"); return; } if(strlen(arg) != 32) { explicit_bzero(arg, strlen(arg)); (void)ssl_printf(ssl, "invalid cookie secret: invalid argument length\n"); (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n"); return; } if(hex_pton(arg, secret, NSD_COOKIE_SECRET_SIZE) != NSD_COOKIE_SECRET_SIZE ) { explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE); explicit_bzero(arg, strlen(arg)); (void)ssl_printf(ssl, "invalid cookie secret: parse error\n"); (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n"); return; } explicit_bzero(arg, strlen(arg)); backup_cookie_count = nsd->cookie_count; memcpy( backup_cookie_secrets, nsd->cookie_secrets , sizeof(cookie_secrets_type)); if(nsd->cookie_secrets_source != COOKIE_SECRETS_FROM_FILE && nsd->cookie_secrets_source != COOKIE_SECRETS_FROM_CONFIG) { nsd->cookie_count = 0; } add_cookie_secret(nsd, secret); explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE); if(!cookie_secret_file_dump_and_reload(ssl, nsd)) { explicit_bzero(arg, strlen(arg)); (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n" , nsd->options->cookie_secret_file); memcpy( nsd->cookie_secrets, backup_cookie_secrets , sizeof(cookie_secrets_type)); nsd->cookie_count = backup_cookie_count; } explicit_bzero(backup_cookie_secrets, sizeof(cookie_secrets_type)); } static void do_print_cookie_secrets(RES* ssl, xfrd_state_type* xrfd, char* arg) { nsd_type* nsd = xrfd->nsd; char secret_hex[NSD_COOKIE_SECRET_SIZE * 2 + 1]; int i; (void)arg; switch(nsd->cookie_secrets_source){ case COOKIE_SECRETS_NONE: break; case COOKIE_SECRETS_GENERATED: if(!ssl_printf(ssl, "source : random generated\n")) return; break; case COOKIE_SECRETS_FROM_FILE: if(!ssl_printf( ssl, "source : \"%s\"\n" , nsd->cookie_secrets_filename)) return; break; case COOKIE_SECRETS_FROM_CONFIG: if(!ssl_printf(ssl, "source : configuration\n")) return; break; default: if(!ssl_printf(ssl, "source : unknown\n")) return; break; } for(i = 0; (size_t)i < nsd->cookie_count; i++) { struct cookie_secret const* cs = &nsd->cookie_secrets[i]; ssize_t const len = hex_ntop(cs->cookie_secret, NSD_COOKIE_SECRET_SIZE, secret_hex, sizeof(secret_hex)); (void)len; /* silence unused variable warning with -DNDEBUG */ assert( len == NSD_COOKIE_SECRET_SIZE * 2 ); secret_hex[NSD_COOKIE_SECRET_SIZE * 2] = '\0'; if (i == 0) (void)ssl_printf(ssl, "active : %s\n", secret_hex); else if (nsd->cookie_count == 2) (void)ssl_printf(ssl, "staging: %s\n", secret_hex); else (void)ssl_printf(ssl, "staging[%d]: %s\n", i, secret_hex); } explicit_bzero(secret_hex, sizeof(secret_hex)); } /** check for name with end-of-string, space or tab after it */ static int cmdcmp(char* p, const char* cmd, size_t len) { return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t'); } /** execute a remote control command */ static void execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd) { char* p = skipwhite(cmd); /* compare command */ if(cmdcmp(p, "stop", 4)) { do_stop(ssl, rc->xfrd); } else if(cmdcmp(p, "reload", 6)) { do_reload(ssl, rc->xfrd, skipwhite(p+6)); } else if(cmdcmp(p, "write", 5)) { do_write(ssl, rc->xfrd, skipwhite(p+5)); } else if(cmdcmp(p, "status", 6)) { do_status(ssl, rc->xfrd); } else if(cmdcmp(p, "stats_noreset", 13)) { do_stats(ssl, rc->xfrd, 1); } else if(cmdcmp(p, "stats", 5)) { do_stats(ssl, rc->xfrd, 0); } else if(cmdcmp(p, "log_reopen", 10)) { do_log_reopen(ssl, rc->xfrd); } else if(cmdcmp(p, "addzone", 7)) { do_addzone(ssl, rc->xfrd, skipwhite(p+7)); } else if(cmdcmp(p, "delzone", 7)) { do_delzone(ssl, rc->xfrd, skipwhite(p+7)); } else if(cmdcmp(p, "changezone", 10)) { do_changezone(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "addzones", 8)) { do_addzones(ssl, rc->xfrd); } else if(cmdcmp(p, "delzones", 8)) { do_delzones(ssl, rc->xfrd); } else if(cmdcmp(p, "notify", 6)) { do_notify(ssl, rc->xfrd, skipwhite(p+6)); } else if(cmdcmp(p, "transfer", 8)) { do_transfer(ssl, rc->xfrd, skipwhite(p+8)); } else if(cmdcmp(p, "force_transfer", 14)) { do_force_transfer(ssl, rc->xfrd, skipwhite(p+14)); } else if(cmdcmp(p, "zonestatus", 10)) { do_zonestatus(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "verbosity", 9)) { do_verbosity(ssl, skipwhite(p+9)); } else if(cmdcmp(p, "repattern", 9)) { do_repattern(ssl, rc->xfrd); } else if(cmdcmp(p, "reconfig", 8)) { do_repattern(ssl, rc->xfrd); } else if(cmdcmp(p, "serverpid", 9)) { do_serverpid(ssl, rc->xfrd); } else if(cmdcmp(p, "print_tsig", 10)) { do_print_tsig(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "update_tsig", 11)) { do_update_tsig(ssl, rc->xfrd, skipwhite(p+11)); } else if(cmdcmp(p, "add_tsig", 8)) { do_add_tsig(ssl, rc->xfrd, skipwhite(p+8)); } else if(cmdcmp(p, "assoc_tsig", 10)) { do_assoc_tsig(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "del_tsig", 8)) { do_del_tsig(ssl, rc->xfrd, skipwhite(p+8)); } else if(cmdcmp(p, "add_cookie_secret", 17)) { do_add_cookie_secret(ssl, rc->xfrd, skipwhite(p+17)); } else if(cmdcmp(p, "drop_cookie_secret", 18)) { do_drop_cookie_secret(ssl, rc->xfrd, skipwhite(p+18)); } else if(cmdcmp(p, "print_cookie_secrets", 20)) { do_print_cookie_secrets(ssl, rc->xfrd, skipwhite(p+20)); } else if(cmdcmp(p, "activate_cookie_secret", 22)) { do_activate_cookie_secret(ssl, rc->xfrd, skipwhite(p+22)); } else { (void)ssl_printf(ssl, "error unknown command '%s'\n", p); } } /** handle remote control request */ static void handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) { int r; char pre[10]; char magic[8]; char buf[1024]; if (fcntl(s->c.ev_fd, F_SETFL, 0) == -1) { /* set blocking */ log_msg(LOG_ERR, "cannot fcntl rc: %s", strerror(errno)); } /* try to read magic UBCT[version]_space_ string */ #ifdef HAVE_SSL if(res->ssl) { ERR_clear_error(); if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) return; log_crypto_err("could not SSL_read"); return; } } else { #endif /* HAVE_SSL */ while(1) { ssize_t rr = read(res->fd, magic, sizeof(magic)-1); if(rr <= 0) { if(rr == 0) return; if(errno == EINTR || errno == EAGAIN) continue; log_msg(LOG_ERR, "could not read: %s", strerror(errno)); return; } r = (int)rr; break; } #ifdef HAVE_SSL } #endif /* HAVE_SSL */ magic[7] = 0; if( r != 7 || strncmp(magic, "NSDCT", 5) != 0) { VERBOSITY(2, (LOG_INFO, "control connection has bad header")); /* probably wrong tool connected, ignore it completely */ return; } /* read the command line */ if(!ssl_read_line(res, buf, sizeof(buf))) { return; } snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION); if(strcmp(magic, pre) != 0) { VERBOSITY(2, (LOG_INFO, "control connection had bad " "version %s, cmd: %s", magic, buf)); (void)ssl_printf(res, "error version mismatch\n"); return; } /* always log control commands */ VERBOSITY(0, (LOG_INFO, "control cmd: %s", buf)); /* figure out what to do */ execute_cmd(rc, res, buf); } #ifdef HAVE_SSL /** handle SSL_do_handshake changes to the file descriptor to wait for later */ static void remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, int r, int r2) { if(r2 == SSL_ERROR_WANT_READ) { if(s->shake_state == rc_hs_read) { /* try again later */ return; } s->shake_state = rc_hs_read; if(s->event_added) event_del(&s->c); memset(&s->c, 0, sizeof(s->c)); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, s); if(event_base_set(xfrd->event_base, &s->c) != 0) log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); s->event_added = 1; return; } else if(r2 == SSL_ERROR_WANT_WRITE) { if(s->shake_state == rc_hs_write) { /* try again later */ return; } s->shake_state = rc_hs_write; if(s->event_added) event_del(&s->c); memset(&s->c, 0, sizeof(s->c)); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE, remote_control_callback, s); if(event_base_set(xfrd->event_base, &s->c) != 0) log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); s->event_added = 1; return; } else { if(r == 0) log_msg(LOG_ERR, "remote control connection closed prematurely"); log_crypto_err("remote control failed ssl"); clean_point(rc, s); } } #endif /* HAVE_SSL */ static void remote_control_callback(int fd, short event, void* arg) { RES res; struct rc_state* s = (struct rc_state*)arg; struct daemon_remote* rc = s->rc; if( (event&EV_TIMEOUT) ) { log_msg(LOG_ERR, "remote control timed out"); clean_point(rc, s); return; } #ifdef HAVE_SSL if(s->ssl) { /* (continue to) setup the SSL connection */ int r; ERR_clear_error(); r = SSL_do_handshake(s->ssl); if(r != 1) { int r2 = SSL_get_error(s->ssl, r); remote_handshake_later(rc, s, fd, r, r2); return; } s->shake_state = rc_none; } #endif /* HAVE_SSL */ /* once handshake has completed, check authentication */ if (!rc->use_cert) { VERBOSITY(3, (LOG_INFO, "unauthenticated remote control connection")); #ifdef HAVE_SSL } else if(SSL_get_verify_result(s->ssl) == X509_V_OK) { # ifdef HAVE_SSL_GET1_PEER_CERTIFICATE X509* x = SSL_get1_peer_certificate(s->ssl); # else X509* x = SSL_get_peer_certificate(s->ssl); # endif if(!x) { VERBOSITY(2, (LOG_INFO, "remote control connection " "provided no client certificate")); clean_point(rc, s); return; } VERBOSITY(3, (LOG_INFO, "remote control connection authenticated")); X509_free(x); #endif /* HAVE_SSL */ } else { VERBOSITY(2, (LOG_INFO, "remote control connection failed to " "authenticate with client certificate")); clean_point(rc, s); return; } /* if OK start to actually handle the request */ #ifdef HAVE_SSL res.ssl = s->ssl; #endif /* HAVE_SSL */ res.fd = fd; handle_req(rc, s, &res); VERBOSITY(3, (LOG_INFO, "remote control operation completed")); clean_point(rc, s); } #ifdef BIND8_STATS const char* opcode2str(int o) { switch(o) { case OPCODE_QUERY: return "QUERY"; case OPCODE_IQUERY: return "IQUERY"; case OPCODE_STATUS: return "STATUS"; case OPCODE_NOTIFY: return "NOTIFY"; case OPCODE_UPDATE: return "UPDATE"; default: return "OTHER"; } } /** print long number */ static int print_longnum(RES* ssl, char* desc, uint64_t x) { if(x > (uint64_t)1024*1024*1024) { /* more than a Gb */ size_t front = (size_t)(x / (uint64_t)1000000); size_t back = (size_t)(x % (uint64_t)1000000); return ssl_printf(ssl, "%s%lu%6.6lu\n", desc, (unsigned long)front, (unsigned long)back); } else { return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x); } } /* print one block of statistics. n is name and d is delimiter */ static void print_stat_block(RES* ssl, char* n, char* d, struct nsdst* st) { const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", "BADVERS" }; size_t i; for(i=0; i<= 255; i++) { if(inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; if(!ssl_printf(ssl, "%s%snum.type.%s=%lu\n", n, d, rrtype_to_string(i), (unsigned long)st->qtype[i])) return; } /* opcode */ for(i=0; i<6; i++) { if(inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) continue; if(!ssl_printf(ssl, "%s%snum.opcode.%s=%lu\n", n, d, opcode2str(i), (unsigned long)st->opcode[i])) return; } /* qclass */ for(i=0; i<4; i++) { if(inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; if(!ssl_printf(ssl, "%s%snum.class.%s=%lu\n", n, d, rrclass_to_string(i), (unsigned long)st->qclass[i])) return; } /* rcode */ for(i=0; i<17; i++) { if(inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /* NSD does not use larger */ continue; if(!ssl_printf(ssl, "%s%snum.rcode.%s=%lu\n", n, d, rcstr[i], (unsigned long)st->rcode[i])) return; } /* edns */ if(!ssl_printf(ssl, "%s%snum.edns=%lu\n", n, d, (unsigned long)st->edns)) return; /* ednserr */ if(!ssl_printf(ssl, "%s%snum.ednserr=%lu\n", n, d, (unsigned long)st->ednserr)) return; /* qudp */ if(!ssl_printf(ssl, "%s%snum.udp=%lu\n", n, d, (unsigned long)st->qudp)) return; /* qudp6 */ if(!ssl_printf(ssl, "%s%snum.udp6=%lu\n", n, d, (unsigned long)st->qudp6)) return; /* ctcp */ if(!ssl_printf(ssl, "%s%snum.tcp=%lu\n", n, d, (unsigned long)st->ctcp)) return; /* ctcp6 */ if(!ssl_printf(ssl, "%s%snum.tcp6=%lu\n", n, d, (unsigned long)st->ctcp6)) return; /* ctls */ if(!ssl_printf(ssl, "%s%snum.tls=%lu\n", n, d, (unsigned long)st->ctls)) return; /* ctls6 */ if(!ssl_printf(ssl, "%s%snum.tls6=%lu\n", n, d, (unsigned long)st->ctls6)) return; /* nona */ if(!ssl_printf(ssl, "%s%snum.answer_wo_aa=%lu\n", n, d, (unsigned long)st->nona)) return; /* rxerr */ if(!ssl_printf(ssl, "%s%snum.rxerr=%lu\n", n, d, (unsigned long)st->rxerr)) return; /* txerr */ if(!ssl_printf(ssl, "%s%snum.txerr=%lu\n", n, d, (unsigned long)st->txerr)) return; /* number of requested-axfr, number of times axfr served to clients */ if(!ssl_printf(ssl, "%s%snum.raxfr=%lu\n", n, d, (unsigned long)st->raxfr)) return; /* number of requested-ixfr, number of times ixfr served to clients */ if(!ssl_printf(ssl, "%s%snum.rixfr=%lu\n", n, d, (unsigned long)st->rixfr)) return; /* truncated */ if(!ssl_printf(ssl, "%s%snum.truncated=%lu\n", n, d, (unsigned long)st->truncated)) return; /* dropped */ if(!ssl_printf(ssl, "%s%snum.dropped=%lu\n", n, d, (unsigned long)st->dropped)) return; } #ifdef USE_ZONE_STATS static void resize_zonestat(xfrd_state_type* xfrd, size_t num) { struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*)); if(xfrd->zonestat_clear_num != 0) memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num * sizeof(struct nsdst*)); free(xfrd->zonestat_clear); xfrd->zonestat_clear = a; xfrd->zonestat_clear_num = num; } void zonestat_print(RES *ssl, struct evbuffer *evbuf, xfrd_state_type *xfrd, int clear, struct nsdst **zonestats) { struct zonestatname* n; struct nsdst stat0, stat1; RBTREE_FOR(n, struct zonestatname*, xfrd->nsd->options->zonestatnames){ char* name = (char*)n->node.key; if(n->id >= xfrd->zonestat_safe) continue; /* newly allocated and reload has not yet done and replied with new size */ if(name == NULL || name[0]==0) continue; /* empty name, do not output */ /* the statistics are stored in two blocks, during reload * the newly forked processes get the other block to use, * these blocks are mmapped and are currently in use to * add statistics to */ memcpy(&stat0, &zonestats[0][n->id], sizeof(stat0)); memcpy(&stat1, &zonestats[1][n->id], sizeof(stat1)); stats_add(&stat0, &stat1); /* save a copy of current (cumulative) stats in stat1 */ memcpy(&stat1, &stat0, sizeof(stat1)); /* subtract last total of stats that was 'cleared' */ if(n->id < xfrd->zonestat_clear_num && xfrd->zonestat_clear[n->id]) stats_subtract(&stat0, xfrd->zonestat_clear[n->id]); if(clear) { /* extend storage array if needed */ if(n->id >= xfrd->zonestat_clear_num) { if(n->id+1 < xfrd->nsd->options->zonestatnames->count) resize_zonestat(xfrd, xfrd->nsd->options->zonestatnames->count); else resize_zonestat(xfrd, n->id+1); } if(!xfrd->zonestat_clear[n->id]) xfrd->zonestat_clear[n->id] = xalloc( sizeof(struct nsdst)); /* store last total of stats */ memcpy(xfrd->zonestat_clear[n->id], &stat1, sizeof(struct nsdst)); } /* stat0 contains the details that we want to print */ if (ssl) { if(!ssl_printf(ssl, "%s%snum.queries=%lu\n", name, ".", (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + stat0.ctcp6 + stat0.ctls + stat0.ctls6))) return; print_stat_block(ssl, name, ".", &stat0); } #ifdef USE_METRICS if (evbuf) { metrics_zonestat_print_one(evbuf, name, &stat0); } #else (void)evbuf; #endif /* USE_METRICS */ } } #endif /* USE_ZONE_STATS */ static void print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear, struct nsdst* st, struct nsdst** zonestats) { size_t i; stc_type total = 0; struct timeval elapsed, uptime; /* per CPU and total */ for(i=0; insd->child_count; i++) { if(!ssl_printf(ssl, "server%d.queries=%lu\n", (int)i, (unsigned long)xfrd->nsd->children[i].query_count)) return; total += xfrd->nsd->children[i].query_count; } if(!ssl_printf(ssl, "num.queries=%lu\n", (unsigned long)total)) return; /* time elapsed and uptime (in seconds) */ timeval_subtract(&uptime, now, &xfrd->nsd->rc->boot_time); timeval_subtract(&elapsed, now, &xfrd->nsd->rc->stats_time); if(!ssl_printf(ssl, "time.boot=%lu.%6.6lu\n", (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec)) return; if(!ssl_printf(ssl, "time.elapsed=%lu.%6.6lu\n", (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec)) return; /* mem info, database on disksize */ if(!print_longnum(ssl, "size.db.disk=", st->db_disk)) return; if(!print_longnum(ssl, "size.db.mem=", st->db_mem)) return; if(!print_longnum(ssl, "size.xfrd.mem=", region_get_mem(xfrd->region))) return; if(!print_longnum(ssl, "size.config.disk=", xfrd->nsd->options->zonelist_off)) return; if(!print_longnum(ssl, "size.config.mem=", region_get_mem( xfrd->nsd->options->region))) return; print_stat_block(ssl, "", "", st); /* zone statistics */ if(!ssl_printf(ssl, "zone.primary=%lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) return; if(!ssl_printf(ssl, "zone.secondary=%lu\n", (unsigned long)xfrd->zones->count)) return; if(!ssl_printf(ssl, "zone.master=%lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) return; if(!ssl_printf(ssl, "zone.slave=%lu\n", (unsigned long)xfrd->zones->count)) return; #ifdef USE_ZONE_STATS zonestat_print(ssl, NULL, xfrd, clear, zonestats); /* per-zone statistics */ #else (void)clear; (void)zonestats; #endif } void process_stats_alloc(struct xfrd_state* xfrd, struct nsdst** stats, struct nsdst** zonestats) { *stats = xmallocarray(xfrd->nsd->child_count*2, sizeof(struct nsdst)); #ifdef USE_ZONE_STATS zonestats[0] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); zonestats[1] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); #else (void)zonestats; #endif } void process_stats_grab(struct xfrd_state* xfrd, struct timeval* stattime, struct nsdst* stats, struct nsdst** zonestats) { if(gettimeofday(stattime, NULL) == -1) log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); memcpy(stats, xfrd->nsd->stat_map, xfrd->nsd->child_count*2*sizeof(struct nsdst)); #ifdef USE_ZONE_STATS memcpy(zonestats[0], xfrd->nsd->zonestat[0], xfrd->zonestat_safe*sizeof(struct nsdst)); memcpy(zonestats[1], xfrd->nsd->zonestat[1], xfrd->zonestat_safe*sizeof(struct nsdst)); #else (void)zonestats; #endif } void process_stats_add_old_new(struct xfrd_state* xfrd, struct nsdst* stats) { size_t i; uint64_t dbd = stats[0].db_disk; uint64_t dbm = stats[0].db_mem; /* The old and new server processes have separate stat blocks, * and these are added up together. This results in the statistics * values per server-child. The reload task briefly forks both * old and new server processes. */ for(i=0; insd->child_count; i++) { stats_add(&stats[i], &stats[xfrd->nsd->child_count+i]); } stats[0].db_disk = dbd; stats[0].db_mem = dbm; } void process_stats_manage_clear(struct xfrd_state* xfrd, struct nsdst* stats, int peek) { struct nsdst st; size_t i; if(peek) { /* Subtract the earlier resetted values from the numbers, * but do not reset the values that are retrieved now. */ if(!xfrd->stat_clear) return; /* nothing to subtract */ for(i=0; insd->child_count; i++) { /* subtract cumulative count that has been reset */ stats_subtract(&stats[i], &xfrd->stat_clear[i]); } return; } if(!xfrd->stat_clear) xfrd->stat_clear = region_alloc_zero(xfrd->region, sizeof(struct nsdst)*xfrd->nsd->child_count); for(i=0; insd->child_count; i++) { /* store cumulative count copy */ memcpy(&st, &stats[i], sizeof(st)); /* subtract cumulative count that has been reset */ stats_subtract(&stats[i], &xfrd->stat_clear[i]); /* store cumulative count in the cleared value array */ memcpy(&xfrd->stat_clear[i], &st, sizeof(st)); } } void process_stats_add_total(struct xfrd_state* xfrd, struct nsdst* total, struct nsdst* stats) { size_t i; /* copy over the first one, with also the nonadded values. */ memcpy(total, &stats[0], sizeof(*total)); xfrd->nsd->children[0].query_count = stats[0].qudp + stats[0].qudp6 + stats[0].ctcp + stats[0].ctcp6 + stats[0].ctls + stats[0].ctls6; for(i=1; insd->child_count; i++) { stats_add(total, &stats[i]); xfrd->nsd->children[i].query_count = stats[i].qudp + stats[i].qudp6 + stats[i].ctcp + stats[i].ctcp6 + stats[i].ctls + stats[i].ctls6; } } void process_stats(RES* ssl, struct evbuffer *evbuf, struct xfrd_state* xfrd, int peek) { struct timeval stattime; struct nsdst* stats, *zonestats[2], total; /* it only really makes sense for one to be used at a time and would * otherwise cause issues if peek is zero */ assert((ssl && !evbuf) || (!ssl && evbuf)); process_stats_alloc(xfrd, &stats, zonestats); process_stats_grab(xfrd, &stattime, stats, zonestats); process_stats_add_old_new(xfrd, stats); process_stats_manage_clear(xfrd, stats, peek); process_stats_add_total(xfrd, &total, stats); if (ssl) { print_stats(ssl, xfrd, &stattime, !peek, &total, zonestats); } #ifdef USE_METRICS if (evbuf) { if (xfrd->nsd->options->control_enable) { /* only pass in rc->stats_time if remote-conrol is enabled, * otherwise stats_time is uninitialized */ metrics_print_stats(evbuf, xfrd, &stattime, !peek, &total, zonestats, &xfrd->nsd->rc->stats_time); } else { metrics_print_stats(evbuf, xfrd, &stattime, !peek, &total, zonestats, NULL); } } #else (void)evbuf; #endif /* USE_METRICS */ if(!peek) { xfrd->nsd->rc->stats_time = stattime; } free(stats); #ifdef USE_ZONE_STATS free(zonestats[0]); free(zonestats[1]); #endif VERBOSITY(3, (LOG_INFO, "remote control stats printed")); } #endif /* BIND8_STATS */ int create_local_accept_sock(const char *path, int* noproto) { #ifdef HAVE_SYS_UN_H int s; struct sockaddr_un usock; VERBOSITY(3, (LOG_INFO, "creating unix socket %s", path)); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* this member exists on BSDs, not Linux */ usock.sun_len = (unsigned)sizeof(usock); #endif usock.sun_family = AF_LOCAL; /* length is 92-108, 104 on FreeBSD */ (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path)); if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { log_msg(LOG_ERR, "Cannot create local socket %s (%s)", path, strerror(errno)); return -1; } if (unlink(path) && errno != ENOENT) { /* The socket already exists and cannot be removed */ log_msg(LOG_ERR, "Cannot remove old local socket %s (%s)", path, strerror(errno)); goto err; } if (bind(s, (struct sockaddr *)&usock, (socklen_t)sizeof(struct sockaddr_un)) == -1) { log_msg(LOG_ERR, "Cannot bind local socket %s (%s)", path, strerror(errno)); goto err; } if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "Cannot set non-blocking mode"); goto err; } if (listen(s, TCP_BACKLOG) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); goto err; } (void)noproto; /*unused*/ return s; err: close(s); return -1; #else (void)path; log_msg(LOG_ERR, "Local sockets are not supported"); *noproto = 1; return -1; #endif } nsd-4.12.0/region-allocator.h0000644000175000017500000001077315002373054015417 0ustar mozziemozzie/* * region-allocator.h -- region based memory allocator. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef REGION_ALLOCATOR_H #define REGION_ALLOCATOR_H #include typedef struct region region_type; #define DEFAULT_CHUNK_SIZE 4096 #define DEFAULT_LARGE_OBJECT_SIZE (DEFAULT_CHUNK_SIZE / 8) #define DEFAULT_INITIAL_CLEANUP_SIZE 16 /* * mmap allocator constants * */ #ifdef USE_MMAP_ALLOC /* header starts with size_t containing allocated size info and has at least 16 bytes to align the returned memory */ #define MMAP_ALLOC_HEADER_SIZE (sizeof(size_t) >= 16 ? (sizeof(size_t)) : 16) /* mmap allocator uses chunks of 32 4kB pages */ #define MMAP_ALLOC_CHUNK_SIZE ((32 * 4096) - MMAP_ALLOC_HEADER_SIZE) #define MMAP_ALLOC_LARGE_OBJECT_SIZE (MMAP_ALLOC_CHUNK_SIZE / 8) #define MMAP_ALLOC_INITIAL_CLEANUP_SIZE 16 #endif /* USE_MMAP_ALLOC */ /* * Create a new region. */ region_type *region_create(void *(*allocator)(size_t), void (*deallocator)(void *)); /* * Create a new region, with chunk size and large object size. * Note that large_object_size must be <= chunk_size. * Anything larger than the large object size is individually alloced. * large_object_size = chunk_size/8 is reasonable; * initial_cleanup_size is the number of preallocated ptrs for cleanups. * The cleanups are in a growing array, and it must start larger than zero. * If recycle is true, environmentally friendly memory recycling is be enabled. */ region_type *region_create_custom(void *(*allocator)(size_t), void (*deallocator)(void *), size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size, int recycle); /* * Destroy REGION. All memory associated with REGION is freed as if * region_free_all was called. */ void region_destroy(region_type *region); /* * Add a cleanup to REGION. ACTION will be called with DATA as * parameter when the region is freed or destroyed. * * Returns 0 on failure. */ size_t region_add_cleanup(region_type *region, void (*action)(void *), void *data); /* * Remove cleanup, both action and data must match exactly. */ void region_remove_cleanup(region_type *region, void (*action)(void *), void *data); /* * Allocate SIZE bytes of memory inside REGION. The memory is * deallocated when region_free_all is called for this region. */ void *region_alloc(region_type *region, size_t size); /** Allocate array with integer overflow checks, in region */ void *region_alloc_array(region_type *region, size_t num, size_t size); /* * Allocate SIZE bytes of memory inside REGION and copy INIT into it. * The memory is deallocated when region_free_all is called for this * region. */ void *region_alloc_init(region_type *region, const void *init, size_t size); /** * Allocate array (with integer overflow check on sizes), and init with * the given array copied into it. Allocated in the region */ void *region_alloc_array_init(region_type *region, const void *init, size_t num, size_t size); /* * Allocate SIZE bytes of memory inside REGION that are initialized to * 0. The memory is deallocated when region_free_all is called for * this region. */ void *region_alloc_zero(region_type *region, size_t size); /** * Allocate array (with integer overflow check on sizes), and zero it. * Allocated in the region. */ void *region_alloc_array_zero(region_type *region, size_t num, size_t size); /* * Run the cleanup actions and free all memory associated with REGION. */ void region_free_all(region_type *region); /* * Duplicate STRING and allocate the result in REGION. */ char *region_strdup(region_type *region, const char *string); /* * Replace a string on the to_replace location, if string is different */ void region_str_replace(region_type* region, char **to_replace, const char *string); /* * Recycle an allocated memory block. Pass size used to alloc it. * Does nothing if recycling is not enabled for the region. */ void region_recycle(region_type *region, void *block, size_t size); /* * Print some REGION statistics to OUT. */ void region_dump_stats(region_type *region, FILE *out); /* get size of recyclebin */ size_t region_get_recycle_size(region_type* region); /* get size of region memory in use */ size_t region_get_mem(region_type* region); /* get size of region memory unused */ size_t region_get_mem_unused(region_type* region); /* Debug print REGION statistics to LOG. */ void region_log_stats(region_type *region); #endif /* REGION_ALLOCATOR_H */ nsd-4.12.0/region-allocator.c0000644000175000017500000003413515002373054015410 0ustar mozziemozzie/* * region-allocator.c -- region based memory allocator. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "region-allocator.h" #include "util.h" /** This value is enough so that x*y does not overflow if both < than this */ #define REGION_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) #ifdef ALIGNMENT #undef ALIGNMENT #endif #ifndef PACKED_STRUCTS #define REGION_ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1))) #if SIZEOF_OFF_T > SIZEOF_VOIDP #define ALIGNMENT (sizeof(off_t)) #else #define ALIGNMENT (sizeof(void *)) #endif #else #define REGION_ALIGN_UP(x, s) ((x)total_allocated = 0; result->small_objects = 0; result->large_objects = 0; result->chunk_count = 1; result->unused_space = 0; result->recycle_bin = NULL; result->recycle_size = 0; result->large_list = NULL; result->allocated = 0; result->data = NULL; result->initial_data = NULL; result->allocator = allocator; result->deallocator = deallocator; assert(initial_cleanup_count > 0); result->maximum_cleanup_count = initial_cleanup_count; result->cleanup_count = 0; result->cleanups = (cleanup_type *) allocator( result->maximum_cleanup_count * sizeof(cleanup_type)); if (!result->cleanups) { deallocator(result); return NULL; } result->chunk_size = DEFAULT_CHUNK_SIZE; result->large_object_size = DEFAULT_LARGE_OBJECT_SIZE; return result; } region_type * region_create(void *(*allocator)(size_t size), void (*deallocator)(void *)) { region_type* result = alloc_region_base(allocator, deallocator, DEFAULT_INITIAL_CLEANUP_SIZE); if(!result) return NULL; result->data = (char *) allocator(result->chunk_size); if (!result->data) { deallocator(result->cleanups); deallocator(result); return NULL; } result->initial_data = result->data; return result; } region_type *region_create_custom(void *(*allocator)(size_t), void (*deallocator)(void *), size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size, int recycle) { region_type* result = alloc_region_base(allocator, deallocator, initial_cleanup_size); if(!result) return NULL; assert(large_object_size <= chunk_size); result->chunk_size = chunk_size; result->large_object_size = large_object_size; if(result->chunk_size > 0) { result->data = (char *) allocator(result->chunk_size); if (!result->data) { deallocator(result->cleanups); deallocator(result); return NULL; } result->initial_data = result->data; } if(recycle) { result->recycle_bin = allocator(sizeof(struct recycle_elem*) * result->large_object_size); if(!result->recycle_bin) { region_destroy(result); return NULL; } memset(result->recycle_bin, 0, sizeof(struct recycle_elem*) * result->large_object_size); } return result; } void region_destroy(region_type *region) { void (*deallocator)(void *); if (!region) return; deallocator = region->deallocator; region_free_all(region); deallocator(region->cleanups); deallocator(region->initial_data); if(region->recycle_bin) deallocator(region->recycle_bin); if(region->large_list) { struct large_elem* p = region->large_list, *np; while(p) { np = p->next; deallocator(p); p = np; } } deallocator(region); } size_t region_add_cleanup(region_type *region, void (*action)(void *), void *data) { assert(action); if (region->cleanup_count >= region->maximum_cleanup_count) { cleanup_type *cleanups = (cleanup_type *) region->allocator( 2 * region->maximum_cleanup_count * sizeof(cleanup_type)); if (!cleanups) return 0; memcpy(cleanups, region->cleanups, region->cleanup_count * sizeof(cleanup_type)); region->deallocator(region->cleanups); region->cleanups = cleanups; region->maximum_cleanup_count *= 2; } region->cleanups[region->cleanup_count].action = action; region->cleanups[region->cleanup_count].data = data; ++region->cleanup_count; return region->cleanup_count; } void region_remove_cleanup(region_type *region, void (*action)(void *), void *data) { size_t i; for(i=0; icleanup_count; i++) { if(region->cleanups[i].action == action && region->cleanups[i].data == data) { region->cleanup_count--; region->cleanups[i] = region->cleanups[region->cleanup_count]; return; } } } void * region_alloc(region_type *region, size_t size) { size_t aligned_size; void *result; if (size == 0) { size = 1; } aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if (aligned_size >= region->large_object_size) { result = region->allocator(size + sizeof(struct large_elem)); if (!result) return NULL; ((struct large_elem*)result)->prev = NULL; ((struct large_elem*)result)->next = region->large_list; if(region->large_list) region->large_list->prev = (struct large_elem*)result; region->large_list = (struct large_elem*)result; region->total_allocated += size; ++region->large_objects; return (char *)result + sizeof(struct large_elem); } if (region->recycle_bin && region->recycle_bin[aligned_size]) { result = (void*)region->recycle_bin[aligned_size]; region->recycle_bin[aligned_size] = region->recycle_bin[aligned_size]->next; region->recycle_size -= aligned_size; region->unused_space += aligned_size - size; return result; } if (region->allocated + aligned_size > region->chunk_size) { void *chunk = region->allocator(region->chunk_size); size_t wasted; if (!chunk) return NULL; wasted = (region->chunk_size - region->allocated) & (~(ALIGNMENT-1)); if( #ifndef PACKED_STRUCTS wasted >= ALIGNMENT #else wasted >= SIZEOF_VOIDP #endif ) { /* put wasted part in recycle bin for later use */ region->total_allocated += wasted; ++region->small_objects; region_recycle(region, region->data+region->allocated, wasted); region->allocated += wasted; } ++region->chunk_count; region->unused_space += region->chunk_size - region->allocated; if(!region_add_cleanup(region, region->deallocator, chunk)) { region->deallocator(chunk); region->chunk_count--; region->unused_space -= region->chunk_size - region->allocated; return NULL; } region->allocated = 0; region->data = (char *) chunk; } result = region->data + region->allocated; region->allocated += aligned_size; region->total_allocated += aligned_size; region->unused_space += aligned_size - size; ++region->small_objects; return result; } void * region_alloc_init(region_type *region, const void *init, size_t size) { void *result = region_alloc(region, size); if (!result) return NULL; memcpy(result, init, size); return result; } void * region_alloc_zero(region_type *region, size_t size) { void *result = region_alloc(region, size); if (!result) return NULL; memset(result, 0, size); return result; } void * region_alloc_array_init(region_type *region, const void *init, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array_init failed because of integer overflow"); exit(1); } return region_alloc_init(region, init, num*size); } void * region_alloc_array_zero(region_type *region, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array_zero failed because of integer overflow"); exit(1); } return region_alloc_zero(region, num*size); } void * region_alloc_array(region_type *region, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array failed because of integer overflow"); exit(1); } return region_alloc(region, num*size); } void region_free_all(region_type *region) { size_t i; assert(region); assert(region->cleanups); i = region->cleanup_count; while (i > 0) { --i; assert(region->cleanups[i].action); region->cleanups[i].action(region->cleanups[i].data); } if(region->recycle_bin) { memset(region->recycle_bin, 0, sizeof(struct recycle_elem*) * region->large_object_size); region->recycle_size = 0; } if(region->large_list) { struct large_elem* p = region->large_list, *np; void (*deallocator)(void *) = region->deallocator; while(p) { np = p->next; deallocator(p); p = np; } region->large_list = NULL; } region->data = region->initial_data; region->cleanup_count = 0; region->allocated = 0; region->total_allocated = 0; region->small_objects = 0; region->large_objects = 0; region->chunk_count = 1; region->unused_space = 0; } char * region_strdup(region_type *region, const char *string) { return (char *) region_alloc_init(region, string, strlen(string) + 1); } void region_str_replace(region_type *region, char **to_replace, const char *string) { assert(to_replace); if(!*to_replace) { if(!string) return; *to_replace = region_strdup(region, string); } else if(!string) { region_recycle(region, *to_replace, strlen(*to_replace) + 1); *to_replace = NULL; } else if(strcmp(*to_replace, string)) { region_recycle(region, *to_replace, strlen(*to_replace) + 1); *to_replace = region_strdup(region, string); } } void region_recycle(region_type *region, void *block, size_t size) { size_t aligned_size; if(!block || !region->recycle_bin) return; if (size == 0) { size = 1; } aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if(aligned_size < region->large_object_size) { struct recycle_elem* elem = (struct recycle_elem*)block; /* we rely on the fact that ALIGNMENT is void* so the next will fit */ assert(aligned_size >= sizeof(struct recycle_elem)); #ifdef CHECK_DOUBLE_FREE if(CHECK_DOUBLE_FREE) { /* make sure the same ptr is not freed twice. */ struct recycle_elem *p = region->recycle_bin[aligned_size]; while(p) { assert(p != elem); p = p->next; } } #endif elem->next = region->recycle_bin[aligned_size]; region->recycle_bin[aligned_size] = elem; region->recycle_size += aligned_size; region->unused_space -= aligned_size - size; return; } else { struct large_elem* l; /* a large allocation */ region->total_allocated -= size; --region->large_objects; l = (struct large_elem*)((char*)block-sizeof(struct large_elem)); if(l->prev) l->prev->next = l->next; else region->large_list = l->next; if(l->next) l->next->prev = l->prev; region->deallocator(l); } } void region_dump_stats(region_type *region, FILE *out) { fprintf(out, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin", (unsigned long) (region->small_objects + region->large_objects), (unsigned long) region->small_objects, (unsigned long) region->large_objects, (unsigned long) region->total_allocated, (unsigned long) region->unused_space, (unsigned long) region->chunk_count, (unsigned long) region->cleanup_count, (unsigned long) region->recycle_size); if(region->recycle_bin) { /* print details of the recycle bin */ size_t i; for(i=0; ilarge_object_size; i++) { size_t count = 0; struct recycle_elem* el = region->recycle_bin[i]; while(el) { count++; el = el->next; } if(i%ALIGNMENT == 0 && i!=0) fprintf(out, " %lu", (unsigned long)count); } } } size_t region_get_recycle_size(region_type* region) { return region->recycle_size; } size_t region_get_mem(region_type* region) { return region->total_allocated; } size_t region_get_mem_unused(region_type* region) { return region->unused_space; } /* debug routine */ void region_log_stats(region_type *region) { char buf[10240], *str=buf; int strl = sizeof(buf); int len; snprintf(str, strl, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin", (unsigned long) (region->small_objects + region->large_objects), (unsigned long) region->small_objects, (unsigned long) region->large_objects, (unsigned long) region->total_allocated, (unsigned long) region->unused_space, (unsigned long) region->chunk_count, (unsigned long) region->cleanup_count, (unsigned long) region->recycle_size); len = strlen(str); str+=len; strl-=len; if(region->recycle_bin) { /* print details of the recycle bin */ size_t i; for(i=0; ilarge_object_size; i++) { size_t count = 0; struct recycle_elem* el = region->recycle_bin[i]; while(el) { count++; el = el->next; } if(i%ALIGNMENT == 0 && i!=0) { snprintf(str, strl, " %lu", (unsigned long)count); len = strlen(str); str+=len; strl-=len; } } } log_msg(LOG_INFO, "memory: %s", buf); } nsd-4.12.0/rdata.h0000644000175000017500000000333215002373054013242 0ustar mozziemozzie/* * rdata.h -- RDATA conversion functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef RDATA_H #define RDATA_H #include "dns.h" #include "namedb.h" /* High bit of the APL length field is the negation bit. */ #define APL_NEGATION_MASK 0x80U #define APL_LENGTH_MASK (~APL_NEGATION_MASK) extern lookup_table_type dns_certificate_types[]; extern lookup_table_type dns_algorithms[]; extern const char *svcparamkey_strs[]; int rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type, rdata_atom_type rdata, rr_type *rr); /* * Split the wireformat RDATA into an array of rdata atoms. Domain * names are inserted into the OWNERS table. The number of rdata atoms * is returned and the array itself is allocated in REGION and stored * in RDATAS. * * Returns -1 on failure. */ ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t rdata_size, buffer_type *packet, rdata_atom_type **rdatas); /* * Calculate the maximum size of the rdata assuming domain names are * not compressed. */ size_t rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas); int rdata_atoms_to_unknown_string(buffer_type *out, rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas); /* print rdata to a text string (as for a zone file) returns 0 on a failure (bufpos is reset to original position). returns 1 on success, bufpos is moved. */ int print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor, rr_type *record); #endif /* RDATA_H */ nsd-4.12.0/rdata.c0000644000175000017500000010301615002373054013235 0ustar mozziemozzie/* * rdata.c -- RDATA conversion functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "rdata.h" #include "zonec.h" /* Taken from RFC 4398, section 2.1. */ lookup_table_type dns_certificate_types[] = { /* 0 Reserved */ { 1, "PKIX" }, /* X.509 as per PKIX */ { 2, "SPKI" }, /* SPKI cert */ { 3, "PGP" }, /* OpenPGP packet */ { 4, "IPKIX" }, /* The URL of an X.509 data object */ { 5, "ISPKI" }, /* The URL of an SPKI certificate */ { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */ { 7, "ACPKIX" }, /* Attribute Certificate */ { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */ { 253, "URI" }, /* URI private */ { 254, "OID" }, /* OID private */ /* 255 Reserved */ /* 256-65279 Available for IANA assignment */ /* 65280-65534 Experimental */ /* 65535 Reserved */ { 0, NULL } }; /* Taken from RFC 2535, section 7. */ lookup_table_type dns_algorithms[] = { { 1, "RSAMD5" }, /* RFC 2537 */ { 2, "DH" }, /* RFC 2539 */ { 3, "DSA" }, /* RFC 2536 */ { 4, "ECC" }, { 5, "RSASHA1" }, /* RFC 3110 */ { 6, "DSA-NSEC3-SHA1" }, /* RFC 5155 */ { 7, "RSASHA1-NSEC3-SHA1" }, /* RFC 5155 */ { 8, "RSASHA256" }, /* RFC 5702 */ { 10, "RSASHA512" }, /* RFC 5702 */ { 12, "ECC-GOST" }, /* RFC 5933 */ { 13, "ECDSAP256SHA256" }, /* RFC 6605 */ { 14, "ECDSAP384SHA384" }, /* RFC 6605 */ { 15, "ED25519" }, /* RFC 8080 */ { 16, "ED448" }, /* RFC 8080 */ { 252, "INDIRECT" }, { 253, "PRIVATEDNS" }, { 254, "PRIVATEOID" }, { 0, NULL } }; const char *svcparamkey_strs[] = { "mandatory", "alpn", "no-default-alpn", "port", "ipv4hint", "ech", "ipv6hint", "dohpath", "ohttp", "tls-supported-groups" }; typedef int (*rdata_to_string_type)(buffer_type *output, rdata_atom_type rdata, rr_type *rr); static int rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { buffer_printf(output, "%s", dname_to_string(domain_dname(rdata_atom_domain(rdata)), NULL)); return 1; } static int rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); size_t offset = 0; uint8_t length = data[offset]; size_t i; while (length > 0) { if (offset) /* concat label */ buffer_printf(output, "."); for (i = 1; i <= length; ++i) { uint8_t ch = data[i+offset]; if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') { buffer_printf(output, "\\%c", (char) ch); } else if (!isgraph((unsigned char) ch)) { buffer_printf(output, "\\%03u", (unsigned int) ch); } else if (isprint((unsigned char) ch)) { buffer_printf(output, "%c", (char) ch); } else { buffer_printf(output, "\\%03u", (unsigned int) ch); } } /* next label */ offset = offset+length+1; length = data[offset]; } /* root label */ buffer_printf(output, "."); return 1; } static int rdata_text_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint8_t length = data[0]; size_t i; buffer_printf(output, "\""); for (i = 1; i <= length; ++i) { char ch = (char) data[i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } buffer_printf(output, "\""); return 1; } static int rdata_texts_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t pos = 0; const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; while (pos < length && pos + data[pos] < length) { buffer_printf(output, "\""); for (i = 1; i <= data[pos]; ++i) { char ch = (char) data[pos + i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[pos+i]); } } pos += data[pos]+1; buffer_printf(output, pos < length?"\" ":"\""); } return 1; } static int rdata_long_text_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; buffer_printf(output, "\""); for (i = 0; i < length; ++i) { char ch = (char) data[i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } buffer_printf(output, "\""); return 1; } static int rdata_unquoted_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint8_t length = data[0]; size_t i; for (i = 1; i <= length; ++i) { char ch = (char) data[i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\' || ch == '(' || ch == ')' || ch == '\'' || isspace((unsigned char)ch)) { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } return 1; } static int rdata_unquoteds_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t pos = 0; const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; while (pos < length && pos + data[pos] < length) { for (i = 1; i <= data[pos]; ++i) { char ch = (char) data[pos + i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\' || isspace((unsigned char)ch)) { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[pos+i]); } } pos += data[pos]+1; buffer_printf(output, pos < length?" ":""); } return 1; } static int rdata_tag_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint8_t length = data[0]; size_t i; for (i = 1; i <= length; ++i) { char ch = (char) data[i]; if (isdigit((unsigned char)ch) || islower((unsigned char)ch)) buffer_printf(output, "%c", ch); else return 0; } return 1; } static int rdata_byte_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t data = *rdata_atom_data(rdata); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_short_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t data = read_uint16(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_long_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint32_t data = read_uint32(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_longlong_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint64_t data = read_uint64(rdata_atom_data(rdata)); buffer_printf(output, "%llu", (unsigned long long) data); return 1; } static int rdata_a_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; char str[200]; if (inet_ntop(AF_INET, rdata_atom_data(rdata), str, sizeof(str))) { buffer_printf(output, "%s", str); result = 1; } return result; } static int rdata_aaaa_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; char str[200]; if (inet_ntop(AF_INET6, rdata_atom_data(rdata), str, sizeof(str))) { buffer_printf(output, "%s", str); result = 1; } return result; } static int rdata_ilnp64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint16_t a1 = read_uint16(data); uint16_t a2 = read_uint16(data+2); uint16_t a3 = read_uint16(data+4); uint16_t a4 = read_uint16(data+6); buffer_printf(output, "%.4x:%.4x:%.4x:%.4x", a1, a2, a3, a4); return 1; } static int rdata_eui48_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint8_t a1 = data[0]; uint8_t a2 = data[1]; uint8_t a3 = data[2]; uint8_t a4 = data[3]; uint8_t a5 = data[4]; uint8_t a6 = data[5]; buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", a1, a2, a3, a4, a5, a6); return 1; } static int rdata_eui64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint8_t a1 = data[0]; uint8_t a2 = data[1]; uint8_t a3 = data[2]; uint8_t a4 = data[3]; uint8_t a5 = data[4]; uint8_t a6 = data[5]; uint8_t a7 = data[6]; uint8_t a8 = data[7]; buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", a1, a2, a3, a4, a5, a6, a7, a8); return 1; } static int rdata_rrtype_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t type = read_uint16(rdata_atom_data(rdata)); buffer_printf(output, "%s", rrtype_to_string(type)); return 1; } static int rdata_algorithm_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t id = *rdata_atom_data(rdata); buffer_printf(output, "%u", (unsigned) id); return 1; } static int rdata_certificate_type_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t id = read_uint16(rdata_atom_data(rdata)); lookup_table_type *type = lookup_by_id(dns_certificate_types, id); if (type) { buffer_printf(output, "%s", type->name); } else { buffer_printf(output, "%u", (unsigned) id); } return 1; } static int rdata_period_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint32_t period = read_uint32(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) period); return 1; } static int rdata_time_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; time_t time = (time_t) read_uint32(rdata_atom_data(rdata)); struct tm *tm = gmtime(&time); char buf[15]; if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm)) { buffer_printf(output, "%s", buf); result = 1; } return result; } static int rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { buffer_write(output, "-", 1); return 1; } size -= 1; /* remove length byte from count */ buffer_reserve(output, size * 2 + 1); length = b32_ntop(rdata_atom_data(rdata)+1, size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { /* single zero represents empty buffer */ buffer_write(output, (rr->type == TYPE_DOA ? "-" : "0"), 1); return 1; } buffer_reserve(output, size * 2 + 1); length = b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static void hex_to_string(buffer_type *output, const uint8_t *data, size_t size) { static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; size_t i; buffer_reserve(output, size * 2); for (i = 0; i < size; ++i) { uint8_t octet = *data++; buffer_write_u8(output, hexdigits[octet >> 4]); buffer_write_u8(output, hexdigits[octet & 0x0f]); } } static int rdata_hex_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { if(rdata_atom_size(rdata) == 0) { /* single zero represents empty buffer, such as CDS deletes */ buffer_printf(output, "0"); } else { hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata)); } return 1; } static int rdata_hexlen_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { if(rdata_atom_size(rdata) <= 1) { /* NSEC3 salt hex can be empty */ buffer_printf(output, "-"); return 1; } hex_to_string(output, rdata_atom_data(rdata)+1, rdata_atom_size(rdata)-1); return 1; } static int rdata_nsap_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { buffer_printf(output, "0x"); hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata)); return 1; } static int rdata_apl_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 4)) { uint16_t address_family = buffer_read_u16(&packet); uint8_t prefix = buffer_read_u8(&packet); uint8_t length = buffer_read_u8(&packet); int negated = length & APL_NEGATION_MASK; int af = -1; length &= APL_LENGTH_MASK; switch (address_family) { case 1: af = AF_INET; break; case 2: af = AF_INET6; break; } if (af != -1 && buffer_available(&packet, length)) { char text_address[1000]; uint8_t address[128]; memset(address, 0, sizeof(address)); buffer_read(&packet, address, length); if (inet_ntop(af, address, text_address, sizeof(text_address))) { buffer_printf(output, "%s%d:%s/%d", negated ? "!" : "", (int) address_family, text_address, (int) prefix); result = 1; } } } return result; } /* * Print protocol and service numbers rather than names for Well-Know Services * (WKS) RRs. WKS RRs are deprecated, though not technically, and should not * be used. The parser supports tcp/udp for protocols and a small subset of * services because getprotobyname and/or getservbyname are marked MT-Unsafe * and locale. getprotobyname_r and getservbyname_r exist on some platforms, * but are still marked locale (meaning the locale object is used without * synchonization, which is a problem for a library). Failure to load a zone * on a primary server because of an unknown protocol or service name is * acceptable as the operator can opt to use the numeric value. Failure to * load a zone on a secondary server is problematic because "unsupported" * protocols and services might be written. Print the numeric value for * maximum compatibility. * * (see simdzone/generic/wks.h for details). */ static int rdata_services_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 1)) { uint8_t protocol_number = buffer_read_u8(&packet); ssize_t bitmap_size = buffer_remaining(&packet); uint8_t *bitmap = buffer_current(&packet); buffer_printf(output, "%" PRIu8, protocol_number); for (int i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, " %d", i); } } buffer_skip(&packet, bitmap_size); result = 1; } return result; } static int rdata_ipsecgateway_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr) { switch(rdata_atom_data(rr->rdatas[1])[0]) { case IPSECKEY_NOGATEWAY: buffer_printf(output, "."); break; case IPSECKEY_IP4: return rdata_a_to_string(output, rdata, rr); case IPSECKEY_IP6: return rdata_aaaa_to_string(output, rdata, rr); case IPSECKEY_DNAME: return rdata_dns_name_to_string(output, rdata, rr); default: return 0; } return 1; } static int rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t i; uint8_t *bitmap = rdata_atom_data(rdata); size_t bitmap_size = rdata_atom_size(rdata); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s ", rrtype_to_string(i)); } } buffer_skip(output, -1); return 1; } static int rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t saved_position = buffer_position(output); buffer_type packet; int insert_space = 0; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); while (buffer_available(&packet, 2)) { uint8_t window = buffer_read_u8(&packet); uint8_t bitmap_size = buffer_read_u8(&packet); uint8_t *bitmap = buffer_current(&packet); int i; if (!buffer_available(&packet, bitmap_size)) { buffer_set_position(output, saved_position); return 0; } for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s%s", insert_space ? " " : "", rrtype_to_string( window * 256 + i)); insert_space = 1; } } buffer_skip(&packet, bitmap_size); } return 1; } static int rdata_loc_to_string(buffer_type *ATTR_UNUSED(output), rdata_atom_type ATTR_UNUSED(rdata), rr_type* ATTR_UNUSED(rr)) { /* * Returning 0 forces the record to be printed in unknown * format. */ return 0; } static void buffer_print_svcparamkey(buffer_type *output, uint16_t svcparamkey) { if (svcparamkey < SVCPARAMKEY_COUNT) buffer_printf(output, "%s", svcparamkey_strs[svcparamkey]); else buffer_printf(output, "key%d", (int)svcparamkey); } static int rdata_svcparam_port_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { if (val_len != 2) return 0; /* wireformat error, a short is 2 bytes */ buffer_printf(output, "=%d", (int)ntohs(data[0])); return 1; } static int rdata_svcparam_ipv4hint_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { char ip_str[INET_ADDRSTRLEN + 1]; assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ if ((val_len % IP4ADDRLEN) == 0) { if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ buffer_printf(output, "=%s", ip_str); data += IP4ADDRLEN / sizeof(uint16_t); while ((val_len -= IP4ADDRLEN) > 0) { if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ buffer_printf(output, ",%s", ip_str); data += IP4ADDRLEN / sizeof(uint16_t); } return 1; } else return 0; } static int rdata_svcparam_ipv6hint_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { char ip_str[INET6_ADDRSTRLEN + 1]; assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ if ((val_len % IP6ADDRLEN) == 0) { if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ buffer_printf(output, "=%s", ip_str); data += IP6ADDRLEN / sizeof(uint16_t); while ((val_len -= IP6ADDRLEN) > 0) { if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ buffer_printf(output, ",%s", ip_str); data += IP6ADDRLEN / sizeof(uint16_t); } return 1; } else return 0; } static int rdata_svcparam_mandatory_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ if (val_len % sizeof(uint16_t)) return 0; /* wireformat error, val_len must be multiple of shorts */ buffer_write_u8(output, '='); buffer_print_svcparamkey(output, ntohs(*data)); data += 1; while ((val_len -= sizeof(uint16_t))) { buffer_write_u8(output, ','); buffer_print_svcparamkey(output, ntohs(*data)); data += 1; } return 1; } static int rdata_svcparam_ech_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { int length; assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ buffer_write_u8(output, '='); buffer_reserve(output, val_len * 2 + 1); length = b64_ntop((uint8_t*) data, val_len, (char *) buffer_current(output), val_len * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static int rdata_svcparam_alpn_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { uint8_t *dp = (void *)data; assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ buffer_write_u8(output, '='); buffer_write_u8(output, '"'); while (val_len) { uint8_t i, str_len = *dp++; if (str_len > --val_len) return 0; for (i = 0; i < str_len; i++) { if (dp[i] == '"' || dp[i] == '\\') buffer_printf(output, "\\\\\\%c", dp[i]); else if (dp[i] == ',') buffer_printf(output, "\\\\%c", dp[i]); else if (!isprint(dp[i])) buffer_printf(output, "\\%03u", (unsigned) dp[i]); else buffer_write_u8(output, dp[i]); } dp += str_len; if ((val_len -= str_len)) buffer_write_u8(output, ','); } buffer_write_u8(output, '"'); return 1; } static int rdata_svcparam_tls_supported_groups_to_string(buffer_type *output, uint16_t val_len, uint16_t *data) { assert(val_len > 0); /* Guaranteed by rdata_svcparam_to_string */ if ((val_len % sizeof(uint16_t)) == 1) return 0; /* A series of uint16_t is an even number of bytes */ buffer_printf(output, "=%d", (int)ntohs(*data++)); while ((val_len -= sizeof(uint16_t)) > 0) buffer_printf(output, ",%d", (int)ntohs(*data++)); return 1; } static int rdata_svcparam_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t size = rdata_atom_size(rdata); uint16_t* data = (uint16_t *)rdata_atom_data(rdata); uint16_t svcparamkey, val_len; uint8_t* dp; size_t i; if (size < 4) return 0; svcparamkey = ntohs(data[0]); buffer_print_svcparamkey(output, svcparamkey); val_len = ntohs(data[1]); if (size != val_len + 4) return 0; /* wireformat error */ if (!val_len) { /* Some SvcParams MUST have values */ switch (svcparamkey) { case SVCB_KEY_ALPN: case SVCB_KEY_PORT: case SVCB_KEY_IPV4HINT: case SVCB_KEY_IPV6HINT: case SVCB_KEY_MANDATORY: case SVCB_KEY_DOHPATH: case SVCB_KEY_TLS_SUPPORTED_GROUPS: return 0; default: return 1; } } switch (svcparamkey) { case SVCB_KEY_PORT: return rdata_svcparam_port_to_string(output, val_len, data+2); case SVCB_KEY_IPV4HINT: return rdata_svcparam_ipv4hint_to_string(output, val_len, data+2); case SVCB_KEY_IPV6HINT: return rdata_svcparam_ipv6hint_to_string(output, val_len, data+2); case SVCB_KEY_MANDATORY: return rdata_svcparam_mandatory_to_string(output, val_len, data+2); case SVCB_KEY_NO_DEFAULT_ALPN: return 0; /* wireformat error, should not have a value */ case SVCB_KEY_ALPN: return rdata_svcparam_alpn_to_string(output, val_len, data+2); case SVCB_KEY_ECH: return rdata_svcparam_ech_to_string(output, val_len, data+2); case SVCB_KEY_OHTTP: return 0; /* wireformat error, should not have a value */ case SVCB_KEY_TLS_SUPPORTED_GROUPS: return rdata_svcparam_tls_supported_groups_to_string(output, val_len, data+2); case SVCB_KEY_DOHPATH: /* fallthrough */ default: buffer_write(output, "=\"", 2); dp = (void*) (data + 2); for (i = 0; i < val_len; i++) { if (dp[i] == '"' || dp[i] == '\\') buffer_printf(output, "\\%c", dp[i]); else if (!isprint(dp[i])) buffer_printf(output, "\\%03u", (unsigned) dp[i]); else buffer_write_u8(output, dp[i]); } buffer_write_u8(output, '"'); break; } return 1; } static int rdata_hip_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t size = rdata_atom_size(rdata); uint8_t hit_length; uint16_t pk_length; int length = 0; if(size < 4) return 0; hit_length = rdata_atom_data(rdata)[0]; pk_length = read_uint16(rdata_atom_data(rdata) + 2); length = 4 + hit_length + pk_length; if(hit_length == 0 || pk_length == 0 || size < length) return 0; buffer_printf(output, "%u ", (unsigned)rdata_atom_data(rdata)[1]); hex_to_string(output, rdata_atom_data(rdata) + 4, hit_length); buffer_printf(output, " "); buffer_reserve(output, pk_length * 2 + 1); length = b64_ntop(rdata_atom_data(rdata) + 4 + hit_length, pk_length, (char *) buffer_current(output), pk_length * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static int rdata_atma_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t size = rdata_atom_size(rdata), i; if(size < 2 || rdata_atom_data(rdata)[0] > 1) return 0; if(!rdata_atom_data(rdata)[0]) { hex_to_string(output, rdata_atom_data(rdata) + 1, size - 1); return 1; } for(i = 1; i < size; i++) { if(!isdigit(rdata_atom_data(rdata)[i])) return 0; } buffer_write_u8(output, '+'); buffer_write(output, rdata_atom_data(rdata) + 1, size - 1); return 1; } static int rdata_amtrelay_d_type_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t data = *rdata_atom_data(rdata); buffer_printf(output , "%c %lu", (data & 0x80 ? '1' : '0'), ((unsigned long)data & 0x7f)); return 1; } static int rdata_amtrelay_relay_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr) { switch(rdata_atom_data(rr->rdatas[1])[0] & 0x7f) { case AMTRELAY_NOGATEWAY: break; case AMTRELAY_IP4: return rdata_a_to_string(output, rdata, rr); case AMTRELAY_IP6: return rdata_aaaa_to_string(output, rdata, rr); case AMTRELAY_DNAME: return rdata_dns_name_to_string(output, rdata, rr); default: return 0; } return 1; } static int rdata_unknown_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t size = rdata_atom_size(rdata); buffer_printf(output, "\\# %lu ", (unsigned long) size); hex_to_string(output, rdata_atom_data(rdata), size); return 1; } static rdata_to_string_type rdata_to_string_table[RDATA_ZF_UNKNOWN + 1] = { rdata_dname_to_string, rdata_dns_name_to_string, rdata_text_to_string, rdata_texts_to_string, rdata_byte_to_string, rdata_short_to_string, rdata_long_to_string, rdata_longlong_to_string, rdata_a_to_string, rdata_aaaa_to_string, rdata_rrtype_to_string, rdata_algorithm_to_string, rdata_certificate_type_to_string, rdata_period_to_string, rdata_time_to_string, rdata_base64_to_string, rdata_base32_to_string, rdata_hex_to_string, rdata_hexlen_to_string, rdata_nsap_to_string, rdata_apl_to_string, rdata_ipsecgateway_to_string, rdata_services_to_string, rdata_nxt_to_string, rdata_nsec_to_string, rdata_loc_to_string, rdata_ilnp64_to_string, rdata_eui48_to_string, rdata_eui64_to_string, rdata_long_text_to_string, rdata_unquoted_to_string, rdata_unquoteds_to_string, rdata_tag_to_string, rdata_svcparam_to_string, rdata_hip_to_string, rdata_atma_to_string, rdata_amtrelay_d_type_to_string, rdata_amtrelay_relay_to_string, rdata_unknown_to_string }; int rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type, rdata_atom_type rdata, rr_type* record) { return rdata_to_string_table[type](output, rdata, record); } ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t data_size, buffer_type *packet, rdata_atom_type **rdatas) { size_t end = buffer_position(packet) + data_size; size_t i; rdata_atom_type temp_rdatas[MAXRDATALEN]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); region_type *temp_region; assert(descriptor->maximum <= MAXRDATALEN); if (!buffer_available(packet, data_size)) { return -1; } temp_region = region_create(xalloc, free); for (i = 0; i < descriptor->maximum; ++i) { int is_domain = 0; int is_normalized = 0; int is_wirestore = 0; size_t length = 0; int required = i < descriptor->minimum; switch (rdata_atom_wireformat_type(rrtype, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: is_domain = 1; is_normalized = 1; break; case RDATA_WF_LITERAL_DNAME: is_domain = 1; is_wirestore = 1; break; case RDATA_WF_BYTE: length = sizeof(uint8_t); break; case RDATA_WF_SHORT: length = sizeof(uint16_t); break; case RDATA_WF_LONG: length = sizeof(uint32_t); break; case RDATA_WF_LONGLONG: length = sizeof(uint64_t); break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: length = end - buffer_position(packet); break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: /* Length is stored in the first byte. */ length = 1; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[length - 1]; } break; case RDATA_WF_A: length = sizeof(in_addr_t); break; case RDATA_WF_AAAA: length = IP6ADDRLEN; break; case RDATA_WF_ILNP64: length = IP6ADDRLEN/2; break; case RDATA_WF_EUI48: length = EUI48ADDRLEN; break; case RDATA_WF_EUI64: length = EUI64ADDRLEN; break; case RDATA_WF_BINARY: /* Remaining RDATA is binary. */ length = end - buffer_position(packet); break; case RDATA_WF_APL: length = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if (buffer_position(packet) + length <= end) { /* Mask out negation bit. */ length += (buffer_current(packet)[length - 1] & APL_LENGTH_MASK); } break; case RDATA_WF_IPSECGATEWAY: assert(i>1); /* we are past the gateway type */ switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ { default: case IPSECKEY_NOGATEWAY: length = 0; break; case IPSECKEY_IP4: length = IP4ADDRLEN; break; case IPSECKEY_IP6: length = IP6ADDRLEN; break; case IPSECKEY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; case RDATA_WF_SVCPARAM: length = 4; if (buffer_position(packet) + 4 <= end) { length += read_uint16(buffer_current(packet) + 2); } break; case RDATA_WF_HIP: /* Length is stored in the first byte (HIT length) * plus the third and fourth byte (PK length) */ length = 4; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[0]; length += read_uint16(buffer_current(packet) + 2); } break; case RDATA_WF_AMTRELAY_RELAY: assert(i>1); switch(rdata_atom_data(temp_rdatas[1])[0] & 0x7f) /* relay type */ { default: case AMTRELAY_NOGATEWAY: length = 0; break; case AMTRELAY_IP4: length = IP4ADDRLEN; break; case AMTRELAY_IP6: length = IP6ADDRLEN; break; case AMTRELAY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; } if (is_domain) { const dname_type *dname; if (!required && buffer_position(packet) == end) { break; } dname = dname_make_from_packet( temp_region, packet, 1, is_normalized); if (!dname || buffer_position(packet) > end) { /* Error in domain name. */ region_destroy(temp_region); return -1; } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + ((size_t)dname->name_size)); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); } else { temp_rdatas[i].domain = domain_table_insert(owners, dname); temp_rdatas[i].domain->usage ++; } } else { if (buffer_position(packet) + length > end) { if (required) { /* Truncated RDATA. */ region_destroy(temp_region); return -1; } else { break; } } if (!required && buffer_position(packet) == end) { break; } temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + length); temp_rdatas[i].data[0] = length; buffer_read(packet, temp_rdatas[i].data + 1, length); } } if (buffer_position(packet) < end) { /* Trailing garbage. */ region_destroy(temp_region); return -1; } *rdatas = (rdata_atom_type *) region_alloc_array_init( region, temp_rdatas, i, sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; } size_t rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas) { size_t result = 0; size_t i; for (i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(descriptor->type, i)) { result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size; } else { result += rdata_atom_size(rdatas[i]); } } return result; } int rdata_atoms_to_unknown_string(buffer_type *output, rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas) { size_t i; size_t size = rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas); buffer_printf(output, " \\# %lu ", (unsigned long) size); for (i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(descriptor->type, i)) { const dname_type *dname = domain_dname(rdata_atom_domain(rdatas[i])); hex_to_string( output, dname_name(dname), dname->name_size); } else { hex_to_string(output, rdata_atom_data(rdatas[i]), rdata_atom_size(rdatas[i])); } } return 1; } int print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor, rr_type *record) { size_t i; size_t saved_position = buffer_position(output); for (i = 0; i < record->rdata_count; ++i) { if (i == 0) { buffer_printf(output, "\t"); } else if (descriptor->type == TYPE_SOA && i == 2) { buffer_printf(output, " (\n\t\t"); } else { buffer_printf(output, " "); } if (!rdata_atom_to_string( output, (rdata_zoneformat_type) descriptor->zoneformat[i], record->rdatas[i], record)) { buffer_set_position(output, saved_position); return 0; } } if (descriptor->type == TYPE_SOA) { buffer_printf(output, " )"); } return 1; } nsd-4.12.0/rbtree.h0000644000175000017500000000456715002373054013445 0ustar mozziemozzie/* * rbtree.h -- generic red-black tree * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef RBTREE_H #define RBTREE_H #include "region-allocator.h" /* * This structure must be the first member of the data structure in * the rbtree. This allows easy casting between an rbnode_type and the * user data (poor man's inheritance). */ typedef struct rbnode rbnode_type; struct rbnode { rbnode_type *parent; rbnode_type *left; rbnode_type *right; const void *key; uint8_t color; } ATTR_PACKED; #define RBTREE_NULL &rbtree_null_node extern rbnode_type rbtree_null_node; typedef struct rbtree rbtree_type; struct rbtree { region_type *region; /* The root of the red-black tree */ rbnode_type *root; /* The number of the nodes in the tree */ size_t count; /* Current node for walks... */ rbnode_type *_node; /* Key compare function. <0,0,>0 like strcmp. Return 0 on two NULL ptrs. */ int (*cmp) (const void *, const void *); } ATTR_PACKED; /* rbtree.c */ rbtree_type *rbtree_create(region_type *region, int (*cmpf)(const void *, const void *)); rbnode_type *rbtree_insert(rbtree_type *rbtree, rbnode_type *data); /* returns node that is now unlinked from the tree. User to delete it. * returns 0 if node not present */ rbnode_type *rbtree_delete(rbtree_type *rbtree, const void *key); rbnode_type *rbtree_search(rbtree_type *rbtree, const void *key); /* returns true if exact match in result. Else result points to <= element, or NULL if key is smaller than the smallest key. */ int rbtree_find_less_equal(rbtree_type *rbtree, const void *key, rbnode_type **result); rbnode_type *rbtree_first(rbtree_type *rbtree); rbnode_type *rbtree_last(rbtree_type *rbtree); rbnode_type *rbtree_next(rbnode_type *rbtree); rbnode_type *rbtree_previous(rbnode_type *rbtree); #define RBTREE_WALK(rbtree, k, d) \ for((rbtree)->_node = rbtree_first(rbtree);\ (rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \ ((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node)) /* call with node=variable of struct* with rbnode_type as first element. with type is the type of a pointer to that struct. */ #define RBTREE_FOR(node, type, rbtree) \ for(node=(type)rbtree_first(rbtree); \ (rbnode_type*)node != RBTREE_NULL; \ node = (type)rbtree_next((rbnode_type*)node)) #endif /* RBTREE_H */ nsd-4.12.0/rbtree.c0000644000175000017500000003271615002373054013435 0ustar mozziemozzie/* * rbtree.c -- generic red black tree * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "rbtree.h" #define BLACK 0 #define RED 1 rbnode_type rbtree_null_node = { RBTREE_NULL, /* Parent. */ RBTREE_NULL, /* Left. */ RBTREE_NULL, /* Right. */ NULL, /* Key. */ BLACK /* Color. */ }; static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node); static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node); static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node); static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent); /* * Creates a new red black tree, initializes and returns a pointer to it. * * Return NULL on failure. * */ rbtree_type * rbtree_create (region_type *region, int (*cmpf)(const void *, const void *)) { rbtree_type *rbtree; /* Allocate memory for it */ rbtree = (rbtree_type *) region_alloc(region, sizeof(rbtree_type)); if (!rbtree) { return NULL; } /* Initialize it */ rbtree->root = RBTREE_NULL; rbtree->count = 0; rbtree->region = region; rbtree->cmp = cmpf; return rbtree; } /* * Rotates the node to the left. * */ static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *right = node->right; node->right = right->left; if (right->left != RBTREE_NULL) right->left->parent = node; right->parent = node->parent; if (node->parent != RBTREE_NULL) { if (node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } } else { rbtree->root = right; } right->left = node; node->parent = right; } /* * Rotates the node to the right. * */ static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *left = node->left; node->left = left->right; if (left->right != RBTREE_NULL) left->right->parent = node; left->parent = node->parent; if (node->parent != RBTREE_NULL) { if (node == node->parent->right) { node->parent->right = left; } else { node->parent->left = left; } } else { rbtree->root = left; } left->right = node; node->parent = left; } static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *uncle; /* While not at the root and need fixing... */ while (node != rbtree->root && node->parent->color == RED) { /* If our parent is left child of our grandparent... */ if (node->parent == node->parent->parent->left) { uncle = node->parent->parent->right; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->right) { node = node->parent; rbtree_rotate_left(rbtree, node); } /* Now we're the left child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; rbtree_rotate_right(rbtree, node->parent->parent); } } else { uncle = node->parent->parent->left; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->left) { node = node->parent; rbtree_rotate_right(rbtree, node); } /* Now we're the right child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; rbtree_rotate_left(rbtree, node->parent->parent); } } } rbtree->root->color = BLACK; } /* * Inserts a node into a red black tree. * * Returns NULL on failure or the pointer to the newly added node * otherwise. */ rbnode_type * rbtree_insert (rbtree_type *rbtree, rbnode_type *data) { /* XXX Not necessary, but keeps compiler quiet... */ int r = 0; /* We start at the root of the tree */ rbnode_type *node = rbtree->root; rbnode_type *parent = RBTREE_NULL; /* Lets find the new parent... */ while (node != RBTREE_NULL) { /* Compare two keys, do we have a duplicate? */ if ((r = rbtree->cmp(data->key, node->key)) == 0) { return NULL; } parent = node; if (r < 0) { node = node->left; } else { node = node->right; } } /* Initialize the new node */ data->parent = parent; data->left = data->right = RBTREE_NULL; data->color = RED; rbtree->count++; /* Insert it into the tree... */ if (parent != RBTREE_NULL) { if (r < 0) { parent->left = data; } else { parent->right = data; } } else { rbtree->root = data; } /* Fix up the red-black properties... */ rbtree_insert_fixup(rbtree, data); return data; } /* * Searches the red black tree, returns the data if key is found or NULL otherwise. * */ rbnode_type * rbtree_search (rbtree_type *rbtree, const void *key) { rbnode_type *node; if (rbtree_find_less_equal(rbtree, key, &node)) { return node; } else { return NULL; } } /* helpers for delete */ static void swap_int8(uint8_t* x, uint8_t* y) { uint8_t t = *x; *x = *y; *y = t; } static void swap_np(rbnode_type** x, rbnode_type** y) { rbnode_type* t = *x; *x = *y; *y = t; } static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent, rbnode_type* old, rbnode_type* new) { if(parent == RBTREE_NULL) { assert(rbtree->root == old); if(rbtree->root == old) rbtree->root = new; return; } assert(parent->left == old || parent->right == old || parent->left == new || parent->right == new); if(parent->left == old) parent->left = new; if(parent->right == old) parent->right = new; } static void change_child_ptr(rbnode_type* child, rbnode_type* old, rbnode_type* new) { if(child == RBTREE_NULL) return; assert(child->parent == old || child->parent == new); if(child->parent == old) child->parent = new; } rbnode_type* rbtree_delete(rbtree_type *rbtree, const void *key) { rbnode_type *to_delete; rbnode_type *child; if((to_delete = rbtree_search(rbtree, key)) == 0) return 0; rbtree->count--; /* make sure we have at most one non-leaf child */ if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL) { /* swap with smallest from right subtree (or largest from left) */ rbnode_type *smright = to_delete->right; while(smright->left != RBTREE_NULL) smright = smright->left; /* swap the smright and to_delete elements in the tree, * but the rbnode_type is first part of user data struct * so cannot just swap the keys and data pointers. Instead * readjust the pointers left,right,parent */ /* swap colors - colors are tied to the position in the tree */ swap_int8(&to_delete->color, &smright->color); /* swap child pointers in parents of smright/to_delete */ change_parent_ptr(rbtree, to_delete->parent, to_delete, smright); if(to_delete->right != smright) change_parent_ptr(rbtree, smright->parent, smright, to_delete); /* swap parent pointers in children of smright/to_delete */ change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(to_delete->left, to_delete, smright); if(to_delete->right != smright) change_child_ptr(to_delete->right, to_delete, smright); if(to_delete->right == smright) { /* set up so after swap they work */ to_delete->right = to_delete; smright->parent = smright; } /* swap pointers in to_delete/smright nodes */ swap_np(&to_delete->parent, &smright->parent); swap_np(&to_delete->left, &smright->left); swap_np(&to_delete->right, &smright->right); /* now delete to_delete (which is at the location where the smright previously was) */ } assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL); if(to_delete->left != RBTREE_NULL) child = to_delete->left; else child = to_delete->right; /* unlink to_delete from the tree, replace to_delete with child */ change_parent_ptr(rbtree, to_delete->parent, to_delete, child); change_child_ptr(child, to_delete, to_delete->parent); if(to_delete->color == RED) { /* if node is red then the child (black) can be swapped in */ } else if(child->color == RED) { /* change child to BLACK, removing a RED node is no problem */ if(child!=RBTREE_NULL) child->color = BLACK; } else rbtree_delete_fixup(rbtree, child, to_delete->parent); /* unlink completely */ to_delete->parent = RBTREE_NULL; to_delete->left = RBTREE_NULL; to_delete->right = RBTREE_NULL; to_delete->color = BLACK; return to_delete; } static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent) { rbnode_type* sibling; int go_up = 1; /* determine sibling to the node that is one-black short */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; while(go_up) { if(child_parent == RBTREE_NULL) { /* removed parent==black from root, every path, so ok */ return; } if(sibling->color == RED) { /* rotate to get a black sibling */ child_parent->color = RED; sibling->color = BLACK; if(child_parent->right == child) rbtree_rotate_right(rbtree, child_parent); else rbtree_rotate_left(rbtree, child_parent); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } if(child_parent->color == BLACK && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* fixup local with recolor of sibling */ if(sibling != RBTREE_NULL) sibling->color = RED; child = child_parent; child_parent = child_parent->parent; /* prepare to go up, new sibling */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else go_up = 0; } if(child_parent->color == RED && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* move red to sibling to rebalance */ if(sibling != RBTREE_NULL) sibling->color = RED; child_parent->color = BLACK; return; } assert(sibling != RBTREE_NULL); /* get a new sibling, by rotating at sibling. See which child of sibling is red */ if(child_parent->right == child && sibling->color == BLACK && sibling->right->color == RED && sibling->left->color == BLACK) { sibling->color = RED; sibling->right->color = BLACK; rbtree_rotate_left(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else if(child_parent->left == child && sibling->color == BLACK && sibling->left->color == RED && sibling->right->color == BLACK) { sibling->color = RED; sibling->left->color = BLACK; rbtree_rotate_right(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } /* now we have a black sibling with a red child. rotate and exchange colors. */ sibling->color = child_parent->color; child_parent->color = BLACK; if(child_parent->right == child) { assert(sibling->left->color == RED); sibling->left->color = BLACK; rbtree_rotate_right(rbtree, child_parent); } else { assert(sibling->right->color == RED); sibling->right->color = BLACK; rbtree_rotate_left(rbtree, child_parent); } } int rbtree_find_less_equal(rbtree_type *rbtree, const void *key, rbnode_type **result) { int r; rbnode_type *node; assert(result); /* We start at root... */ node = rbtree->root; *result = NULL; /* While there are children... */ while (node != RBTREE_NULL) { r = rbtree->cmp(key, node->key); if (r == 0) { /* Exact match */ *result = node; return 1; } if (r < 0) { node = node->left; } else { /* Temporary match */ *result = node; node = node->right; } } return 0; } /* * Finds the first element in the red black tree * */ rbnode_type * rbtree_first (rbtree_type *rbtree) { rbnode_type *node; for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left); return node; } rbnode_type * rbtree_last (rbtree_type *rbtree) { rbnode_type *node; for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right); return node; } /* * Returns the next node... * */ rbnode_type * rbtree_next (rbnode_type *node) { rbnode_type *parent; if (node->right != RBTREE_NULL) { /* One right, then keep on going left... */ for (node = node->right; node->left != RBTREE_NULL; node = node->left); } else { parent = node->parent; while (parent != RBTREE_NULL && node == parent->right) { node = parent; parent = parent->parent; } node = parent; } return node; } rbnode_type * rbtree_previous(rbnode_type *node) { rbnode_type *parent; if (node->left != RBTREE_NULL) { /* One left, then keep on going right... */ for (node = node->left; node->right != RBTREE_NULL; node = node->right); } else { parent = node->parent; while (parent != RBTREE_NULL && node == parent->left) { node = parent; parent = parent->parent; } node = parent; } return node; } nsd-4.12.0/radtree.h0000644000175000017500000001604015002373054013575 0ustar mozziemozzie/* * radtree -- generic radix tree for binary strings. * * Copyright (c) 2010, NLnet Labs. See LICENSE for license. */ #ifndef RADTREE_H #define RADTREE_H struct radnode; struct region; /** length of the binary string */ typedef uint16_t radstrlen_type; /** * The radix tree * * The elements are stored based on binary strings(0-255) of a given length. * They are sorted, a prefix is sorted before its suffixes. * If you want to know the key string, you should store it yourself, the * tree stores it in the parts necessary for lookup. * For binary strings for domain names see the radname routines. */ struct radtree { /** root node in tree */ struct radnode* root; /** count of number of elements */ size_t count; /** region for allocation */ struct region* region; }; /** * A radix tree lookup node. * The array is malloced separately from the radnode. */ struct radnode { /** data element associated with the binary string up to this node */ void* elem; /** parent node (NULL for the root) */ struct radnode* parent; /** index in the parent lookup array */ uint8_t pidx; /** offset of the lookup array, add to [i] for lookups */ uint8_t offset; /** length of the lookup array */ uint16_t len; /** capacity of the lookup array (can be larger than length) */ uint16_t capacity; /** the lookup array by [byte-offset] */ struct radsel* array; } ATTR_PACKED; /** * radix select edge in array */ struct radsel { /** additional string after the selection-byte for this edge. */ uint8_t* str; /** length of the additional string for this edge */ radstrlen_type len; /** node that deals with byte+str */ struct radnode* node; } ATTR_PACKED; /** * Create new radix tree * @param region: where to allocate the tree. * @return new tree or NULL on alloc failure. */ struct radtree* radix_tree_create(struct region* region); /** * Init new radix tree. * @param rt: radix tree to be initialized. */ void radix_tree_init(struct radtree* rt); /** * Delete intermediate nodes from radix tree * @param rt: radix tree to be initialized. */ void radix_tree_clear(struct radtree* rt); /** * Delete radix tree. * @param rt: radix tree to be deleted. */ void radix_tree_delete(struct radtree* rt); /** * Insert element into radix tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @param elem: pointer to element data. * @return NULL on failure - out of memory. * NULL on failure - duplicate entry. * On success the new radix node for this element. */ struct radnode* radix_insert(struct radtree* rt, uint8_t* k, radstrlen_type len, void* elem); /** * Delete element from radix tree. * @param rt: the radix tree. * @param n: radix node for that element. * if NULL, nothing is deleted. */ void radix_delete(struct radtree* rt, struct radnode* n); /** * Find radix element in tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @return the radix node or NULL if not found. */ struct radnode* radix_search(struct radtree* rt, uint8_t* k, radstrlen_type len); /** * Find radix element in tree, and if not found, find the closest smaller or * equal element in the tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @param result: returns the radix node or closest match (NULL if key is * smaller than the smallest key in the tree). * @return true if exact match, false if no match. */ int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result); /** * Return the first (smallest) element in the tree. * @param rt: the radix tree. * @return: first node or NULL if none. */ struct radnode* radix_first(struct radtree* rt); /** * Return the last (largest) element in the tree. * @param rt: the radix tree. * @return: last node or NULL if none. */ struct radnode* radix_last(struct radtree* rt); /** * Return the next element. * @param n: the element to go from. * @return: next node or NULL if none. */ struct radnode* radix_next(struct radnode* n); /** * Return the previous element. * @param n: the element to go from. * @return: prev node or NULL if none. */ struct radnode* radix_prev(struct radnode* n); /* * Perform a walk through all elements of the tree. * node: variable of type struct radnode*. * tree: pointer to the tree. * for(node=radix_first(tree); node; node=radix_next(node)) */ /** * Create a binary string to represent a domain name * @param k: string buffer to store into * @param len: output length, initially, the max, output the result. * @param dname: the domain name to convert, in wireformat. * @param dlen: length of space for dname. */ void radname_d2r(uint8_t* k, radstrlen_type* len, const uint8_t* dname, size_t dlen); /** * Convert a binary string back to a domain name. * @param k: the binary string. * @param len: length of k. * @param dname: buffer to store domain name into. * @param dlen: length of dname (including root label). */ void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen); /** * Search the radix tree using a domain name. * The name is internally converted to a radname. * @param rt: tree * @param d: domain name, no compression pointers allowed. * @param max: max length to go from d. * @return NULL on parse error or if not found. */ struct radnode* radname_search(struct radtree* rt, const uint8_t* d, size_t max); /** * Find radix element in tree by domain name, and if not found, * find the closest smaller or equal element in the tree. * The name is internally converted to a radname (same sorting order). * @param rt: the radix tree. * @param d: domain name, no compression pointers allowed. * @param max: max length to go from d. * @param result: returns the radix node or closest match (NULL if key is * smaller than the smallest key in the tree). * could result in NULL on a parse error as well (with return false). * @return true if exact match, false if no match. */ int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max, struct radnode** result); /** * Insert radix element by domain name. * @param rt: the radix tree * @param d: domain name, no compression pointers. * @param max: max length from d. * @param elem: the element pointer to insert. * @return NULL on failure - out of memory. * NULL on failure - duplicate entry. * NULL on failure - parse error. * On success the radix node for this element. */ struct radnode* radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem); /** * Delete element by domain name from radix tree. * @param rt: the radix tree. * @param d: the domain name. If it is not in the tree nothing happens. * @param max: max length. */ void radname_delete(struct radtree* rt, const uint8_t* d, size_t max); /** number of bytes in common in strings */ radstrlen_type bstr_common_ext(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen); /** true if one is prefix of the other */ int bstr_is_prefix_ext(uint8_t* p, radstrlen_type plen, uint8_t* x, radstrlen_type xlen); #endif /* RADTREE_H */ nsd-4.12.0/radtree.c0000644000175000017500000011301515002373054013570 0ustar mozziemozzie/* * radtree -- generic radix tree for binary strings. * * Copyright (c) 2010, NLnet Labs. See LICENSE for license. */ #include "config.h" #include #include #include #include #include #include "radtree.h" #include "util.h" #include "region-allocator.h" #include #include struct radtree* radix_tree_create(struct region* region) { struct radtree* rt = (struct radtree*)region_alloc(region, sizeof(*rt)); if(!rt) return NULL; rt->region = region; radix_tree_init(rt); return rt; } void radix_tree_init(struct radtree* rt) { rt->root = NULL; rt->count = 0; } /** delete radnodes in postorder recursion */ static void radnode_del_postorder(struct region* region, struct radnode* n) { unsigned i; if(!n) return; for(i=0; ilen; i++) { radnode_del_postorder(region, n->array[i].node); region_recycle(region, n->array[i].str, n->array[i].len); } region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(region, n, sizeof(*n)); } void radix_tree_clear(struct radtree* rt) { radnode_del_postorder(rt->region, rt->root); rt->root = NULL; rt->count = 0; } void radix_tree_delete(struct radtree* rt) { if(!rt) return; radix_tree_clear(rt); region_recycle(rt->region, rt, sizeof(*rt)); } /** return last elem-containing node in this subtree (excl self) */ static struct radnode* radnode_last_in_subtree(struct radnode* n) { int idx; /* try last entry in array first */ for(idx=((int)n->len)-1; idx >= 0; idx--) { if(n->array[idx].node) { /* does it have entries in its subtrees? */ if(n->array[idx].node->len > 0) { struct radnode* s = radnode_last_in_subtree( n->array[idx].node); if(s) return s; } /* no, does it have an entry itself? */ if(n->array[idx].node->elem) return n->array[idx].node; } } return NULL; } /** last in subtree, incl self */ static struct radnode* radnode_last_in_subtree_incl_self(struct radnode* n) { struct radnode* s = radnode_last_in_subtree(n); if(s) return s; if(n->elem) return n; return NULL; } /** return first elem-containing node in this subtree (excl self) */ static struct radnode* radnode_first_in_subtree(struct radnode* n) { unsigned idx; struct radnode* s; /* try every subnode */ for(idx=0; idxlen; idx++) { if(n->array[idx].node) { /* does it have elem itself? */ if(n->array[idx].node->elem) return n->array[idx].node; /* try its subtrees */ if((s=radnode_first_in_subtree(n->array[idx].node))!=0) return s; } } return NULL; } /** Find an entry in arrays from idx-1 to 0 */ static struct radnode* radnode_find_prev_from_idx(struct radnode* n, unsigned from) { unsigned idx = from; while(idx > 0) { idx --; if(n->array[idx].node) { struct radnode* s = radnode_last_in_subtree_incl_self( n->array[idx].node); if(s) return s; } } return NULL; } /** * Find a prefix of the key, in whole-nodes. * Finds the longest prefix that corresponds to a whole radnode entry. * There may be a slightly longer prefix in one of the array elements. * @param result: the longest prefix, the entry itself if *respos==len, * otherwise an array entry, residx. * @param respos: pos in string where next unmatched byte is, if == len an * exact match has been found. If == 0 then a "" match was found. * @return false if no prefix found, not even the root "" prefix. */ static int radix_find_prefix_node(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result, radstrlen_type* respos) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; *respos = 0; *result = n; if(!n) return 0; while(n) { if(pos == len) { return 1; } byte = k[pos]; if(byte < n->offset) { return 1; } byte -= n->offset; if(byte >= n->len) { return 1; } pos++; if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) { return 1; } if(memcmp(&k[pos], n->array[byte].str, n->array[byte].len) != 0) { return 1; } pos += n->array[byte].len; } n = n->array[byte].node; if(!n) return 1; *respos = pos; *result = n; } /* cannot reach because of returns when !n above */ /* ENOTREACH */ return 1; } /** grow array to at least the given size, offset unchanged */ static int radnode_array_grow(struct region* region, struct radnode* n, unsigned want) { unsigned ns = ((unsigned)n->capacity)*2; struct radsel* a; assert(want <= 256); /* cannot be more, range of uint8 */ if(want > ns) ns = want; if(ns > 256) ns = 256; /* we do not use realloc, because we want to keep the old array * in case alloc fails, so that the tree is still usable */ a = (struct radsel*)region_alloc_array(region, ns, sizeof(struct radsel)); if(!a) return 0; assert(n->len <= n->capacity); assert(n->capacity < ns); memcpy(&a[0], &n->array[0], n->len*sizeof(struct radsel)); region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); n->array = a; n->capacity = ns; return 1; } /** make space in radnode array for another byte */ static int radnode_array_space(struct region* region, struct radnode* n, uint8_t byte) { /* is there an array? */ if(!n->array || n->capacity == 0) { n->array = (struct radsel*)region_alloc(region, sizeof(struct radsel)); if(!n->array) return 0; memset(&n->array[0], 0, sizeof(struct radsel)); n->len = 1; n->capacity = 1; n->offset = byte; /* is the array unused? */ } else if(n->len == 0 && n->capacity != 0) { n->len = 1; n->offset = byte; memset(&n->array[0], 0, sizeof(struct radsel)); /* is it below the offset? */ } else if(byte < n->offset) { /* is capacity enough? */ unsigned idx; unsigned need = n->offset-byte; if(n->len+need > n->capacity) { /* grow array */ if(!radnode_array_grow(region, n, n->len+need)) return 0; } /* reshuffle items to end */ memmove(&n->array[need], &n->array[0], n->len*sizeof(struct radsel)); /* fixup pidx */ for(idx = 0; idx < n->len; idx++) { if(n->array[idx+need].node) n->array[idx+need].node->pidx = idx+need; } /* zero the first */ memset(&n->array[0], 0, need*sizeof(struct radsel)); n->len += need; n->offset = byte; /* is it above the max? */ } else if(byte-n->offset >= n->len) { /* is capacity enough? */ unsigned need = (byte-n->offset) - n->len + 1; /* grow array */ if(n->len + need > n->capacity) { if(!radnode_array_grow(region, n, n->len+need)) return 0; } /* zero added entries */ memset(&n->array[n->len], 0, need*sizeof(struct radsel)); /* grow length */ n->len += need; } return 1; } /** create a prefix in the array strs */ static int radsel_str_create(struct region* region, struct radsel* r, uint8_t* k, radstrlen_type pos, radstrlen_type len) { r->str = (uint8_t*)region_alloc(region, sizeof(uint8_t)*(len-pos)); if(!r->str) return 0; /* out of memory */ memmove(r->str, k+pos, len-pos); r->len = len-pos; return 1; } /** see if one byte string p is a prefix of another x (equality is true) */ static int bstr_is_prefix(uint8_t* p, radstrlen_type plen, uint8_t* x, radstrlen_type xlen) { /* if plen is zero, it is an (empty) prefix */ if(plen == 0) return 1; /* if so, p must be shorter */ if(plen > xlen) return 0; return (memcmp(p, x, plen) == 0); } /** number of bytes in common for the two strings */ static radstrlen_type bstr_common(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen) { unsigned i, max = ((xlenstr, r->len)) { uint8_t* split_str=NULL, *dupstr=NULL; radstrlen_type split_len=0; /* 'add' is a prefix of r.node */ /* also for empty addstr */ /* set it up so that the 'add' node has r.node as child */ /* so, r.node gets moved below the 'add' node, but we do * this so that the r.node stays the same pointer for its * key name */ assert(addlen != r->len); assert(addlen < r->len); if(r->len-addlen > 1) { /* shift one because a char is in the lookup array */ if(!radsel_prefix_remainder(region, addlen+1, r->str, r->len, &split_str, &split_len)) return 0; } if(addlen != 0) { dupstr = (uint8_t*)region_alloc(region, addlen*sizeof(uint8_t)); if(!dupstr) { region_recycle(region, split_str, split_len); return 0; } memcpy(dupstr, addstr, addlen); } if(!radnode_array_space(region, add, r->str[addlen])) { region_recycle(region, split_str, split_len); region_recycle(region, dupstr, addlen); return 0; } /* alloc succeeded, now link it in */ add->parent = r->node->parent; add->pidx = r->node->pidx; add->array[0].node = r->node; add->array[0].str = split_str; add->array[0].len = split_len; r->node->parent = add; r->node->pidx = 0; r->node = add; region_recycle(region, r->str, r->len); r->str = dupstr; r->len = addlen; } else if(bstr_is_prefix(r->str, r->len, addstr, addlen)) { uint8_t* split_str = NULL; radstrlen_type split_len = 0; /* r.node is a prefix of 'add' */ /* set it up so that the 'r.node' has 'add' as child */ /* and basically, r.node is already completely fine, * we only need to create a node as its child */ assert(addlen != r->len); assert(r->len < addlen); if(addlen-r->len > 1) { /* shift one because a character goes into array */ if(!radsel_prefix_remainder(region, r->len+1, addstr, addlen, &split_str, &split_len)) return 0; } if(!radnode_array_space(region, r->node, addstr[r->len])) { region_recycle(region, split_str, split_len); return 0; } /* alloc succeeded, now link it in */ add->parent = r->node; add->pidx = addstr[r->len] - r->node->offset; r->node->array[add->pidx].node = add; r->node->array[add->pidx].str = split_str; r->node->array[add->pidx].len = split_len; } else { /* okay we need to create a new node that chooses between * the nodes 'add' and r.node * We do this so that r.node stays the same pointer for its * key name. */ struct radnode* com; uint8_t* common_str=NULL, *s1_str=NULL, *s2_str=NULL; radstrlen_type common_len, s1_len=0, s2_len=0; common_len = bstr_common(r->str, r->len, addstr, addlen); assert(common_len < r->len); assert(common_len < addlen); /* create the new node for choice */ com = (struct radnode*)region_alloc_zero(region, sizeof(*com)); if(!com) return 0; /* out of memory */ /* create the two substrings for subchoices */ if(r->len-common_len > 1) { /* shift by one char because it goes in lookup array */ if(!radsel_prefix_remainder(region, common_len+1, r->str, r->len, &s1_str, &s1_len)) { region_recycle(region, com, sizeof(*com)); return 0; } } if(addlen-common_len > 1) { if(!radsel_prefix_remainder(region, common_len+1, addstr, addlen, &s2_str, &s2_len)) { region_recycle(region, com, sizeof(*com)); region_recycle(region, s1_str, s1_len); return 0; } } /* create the shared prefix to go in r */ if(common_len > 0) { common_str = (uint8_t*)region_alloc(region, common_len*sizeof(uint8_t)); if(!common_str) { region_recycle(region, com, sizeof(*com)); region_recycle(region, s1_str, s1_len); region_recycle(region, s2_str, s2_len); return 0; } memcpy(common_str, addstr, common_len); } /* make space in the common node array */ if(!radnode_array_space(region, com, r->str[common_len]) || !radnode_array_space(region, com, addstr[common_len])) { region_recycle(region, com->array, com->capacity*sizeof(struct radsel)); region_recycle(region, com, sizeof(*com)); region_recycle(region, common_str, common_len); region_recycle(region, s1_str, s1_len); region_recycle(region, s2_str, s2_len); return 0; } /* allocs succeeded, proceed to link it all up */ com->parent = r->node->parent; com->pidx = r->node->pidx; r->node->parent = com; r->node->pidx = r->str[common_len]-com->offset; add->parent = com; add->pidx = addstr[common_len]-com->offset; com->array[r->node->pidx].node = r->node; com->array[r->node->pidx].str = s1_str; com->array[r->node->pidx].len = s1_len; com->array[add->pidx].node = add; com->array[add->pidx].str = s2_str; com->array[add->pidx].len = s2_len; region_recycle(region, r->str, r->len); r->str = common_str; r->len = common_len; r->node = com; } return 1; } struct radnode* radix_insert(struct radtree* rt, uint8_t* k, radstrlen_type len, void* elem) { struct radnode* n; radstrlen_type pos = 0; /* create new element to add */ struct radnode* add = (struct radnode*)region_alloc_zero(rt->region, sizeof(*add)); if(!add) return NULL; /* out of memory */ add->elem = elem; /* find out where to add it */ if(!radix_find_prefix_node(rt, k, len, &n, &pos)) { /* new root */ assert(rt->root == NULL); if(len == 0) { rt->root = add; } else { /* add a root to point to new node */ n = (struct radnode*)region_alloc_zero(rt->region, sizeof(*n)); if(!n) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } if(!radnode_array_space(rt->region, n, k[0])) { region_recycle(rt->region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(rt->region, n, sizeof(*n)); region_recycle(rt->region, add, sizeof(*add)); return NULL; } add->parent = n; add->pidx = 0; n->array[0].node = add; if(len > 1) { if(!radsel_prefix_remainder(rt->region, 1, k, len, &n->array[0].str, &n->array[0].len)) { region_recycle(rt->region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(rt->region, n, sizeof(*n)); region_recycle(rt->region, add, sizeof(*add)); return NULL; } } rt->root = n; } } else if(pos == len) { /* found an exact match */ if(n->elem) { /* already exists, failure */ region_recycle(rt->region, add, sizeof(*add)); return NULL; } n->elem = elem; region_recycle(rt->region, add, sizeof(*add)); add = n; } else { /* n is a node which can accomodate */ uint8_t byte; assert(pos < len); byte = k[pos]; /* see if it falls outside of array */ if(byte < n->offset || byte-n->offset >= n->len) { /* make space in the array for it; adjusts offset */ if(!radnode_array_space(rt->region, n, byte)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } assert(byte>=n->offset && byte-n->offsetlen); byte -= n->offset; /* see if more prefix needs to be split off */ if(pos+1 < len) { if(!radsel_str_create(rt->region, &n->array[byte], k, pos+1, len)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } /* insert the new node in the new bucket */ add->parent = n; add->pidx = byte; n->array[byte].node = add; /* so a bucket exists and byte falls in it */ } else if(n->array[byte-n->offset].node == NULL) { /* use existing bucket */ byte -= n->offset; if(pos+1 < len) { /* split off more prefix */ if(!radsel_str_create(rt->region, &n->array[byte], k, pos+1, len)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } /* insert the new node in the new bucket */ add->parent = n; add->pidx = byte; n->array[byte].node = add; } else { /* use bucket but it has a shared prefix, * split that out and create a new intermediate * node to split out between the two. * One of the two might exactmatch the new * intermediate node */ if(!radsel_split(rt->region, &n->array[byte-n->offset], k, pos+1, len, add)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } } rt->count ++; return add; } /** Delete a radnode */ static void radnode_delete(struct region* region, struct radnode* n) { unsigned i; if(!n) return; for(i=0; ilen; i++) { /* safe to free NULL str */ region_recycle(region, n->array[i].str, n->array[i].len); } region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(region, n, sizeof(*n)); } /** Cleanup node with one child, it is removed and joined into parent[x] str */ static int radnode_cleanup_onechild(struct region* region, struct radnode* n, struct radnode* par) { uint8_t* join; radstrlen_type joinlen; uint8_t pidx = n->pidx; struct radnode* child = n->array[0].node; /* node had one child, merge them into the parent. */ /* keep the child node, so its pointers stay valid. */ /* at parent, append child->str to array str */ assert(pidx < par->len); joinlen = par->array[pidx].len + n->array[0].len + 1; join = (uint8_t*)region_alloc(region, joinlen*sizeof(uint8_t)); if(!join) { /* cleanup failed due to out of memory */ /* the tree is inefficient, with node n still existing */ return 0; } /* we know that .str and join are malloced, thus aligned */ if(par->array[pidx].str) memcpy(join, par->array[pidx].str, par->array[pidx].len); /* the array lookup is gone, put its character in the lookup string*/ join[par->array[pidx].len] = child->pidx + n->offset; /* but join+len may not be aligned */ if(n->array[0].str) memmove(join+par->array[pidx].len+1, n->array[0].str, n->array[0].len); region_recycle(region, par->array[pidx].str, par->array[pidx].len); par->array[pidx].str = join; par->array[pidx].len = joinlen; /* and set the node to our child. */ par->array[pidx].node = child; child->parent = par; child->pidx = pidx; /* we are unlinked, delete our node */ radnode_delete(region, n); return 1; } /** remove array of nodes */ static void radnode_array_clean_all(struct region* region, struct radnode* n) { n->offset = 0; n->len = 0; /* shrink capacity */ region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); n->array = NULL; n->capacity = 0; } /** see if capacity can be reduced for the given node array */ static void radnode_array_reduce_if_needed(struct region* region, struct radnode* n) { if(n->len <= n->capacity/2 && n->len != n->capacity) { struct radsel* a = (struct radsel*)region_alloc_array(region, sizeof(*a), n->len); if(!a) return; memcpy(a, n->array, sizeof(*a)*n->len); region_recycle(region, n->array, n->capacity*sizeof(*a)); n->array = a; n->capacity = n->len; } } /** remove NULL nodes from front of array */ static void radnode_array_clean_front(struct region* region, struct radnode* n) { /* move them up and adjust offset */ unsigned idx, shuf = 0; /* remove until a nonNULL entry */ while(shuf < n->len && n->array[shuf].node == NULL) shuf++; if(shuf == 0) return; if(shuf == n->len) { /* the array is empty, the tree is inefficient */ radnode_array_clean_all(region, n); return; } assert(shuf < n->len); assert((int)shuf <= 255-(int)n->offset); memmove(&n->array[0], &n->array[shuf], (n->len - shuf)*sizeof(struct radsel)); n->offset += shuf; n->len -= shuf; for(idx=0; idxlen; idx++) if(n->array[idx].node) n->array[idx].node->pidx = idx; /* see if capacity can be reduced */ radnode_array_reduce_if_needed(region, n); } /** remove NULL nodes from end of array */ static void radnode_array_clean_end(struct region* region, struct radnode* n) { /* shorten it */ unsigned shuf = 0; /* remove until a nonNULL entry */ while(shuf < n->len && n->array[n->len-1-shuf].node == NULL) shuf++; if(shuf == 0) return; if(shuf == n->len) { /* the array is empty, the tree is inefficient */ radnode_array_clean_all(region, n); return; } assert(shuf < n->len); n->len -= shuf; /* array elements can stay where they are */ /* see if capacity can be reduced */ radnode_array_reduce_if_needed(region, n); } /** clean up radnode leaf, where we know it has a parent */ static void radnode_cleanup_leaf(struct region* region, struct radnode* n, struct radnode* par) { uint8_t pidx; /* node was a leaf */ /* delete leaf node, but store parent+idx */ pidx = n->pidx; radnode_delete(region, n); /* set parent+idx entry to NULL str and node.*/ assert(pidx < par->len); region_recycle(region, par->array[pidx].str, par->array[pidx].len); par->array[pidx].str = NULL; par->array[pidx].len = 0; par->array[pidx].node = NULL; /* see if par offset or len must be adjusted */ if(par->len == 1) { /* removed final element from array */ radnode_array_clean_all(region, par); } else if(pidx == 0) { /* removed first element from array */ radnode_array_clean_front(region, par); } else if(pidx == par->len-1) { /* removed last element from array */ radnode_array_clean_end(region, par); } } /** * Cleanup a radix node that was made smaller, see if it can * be merged with others. * @param rt: tree to remove root if needed. * @param n: node to cleanup * @return false on alloc failure. */ static int radnode_cleanup(struct radtree* rt, struct radnode* n) { while(n) { if(n->elem) { /* cannot delete node with a data element */ return 1; } else if(n->len == 1 && n->parent) { return radnode_cleanup_onechild(rt->region, n, n->parent); } else if(n->len == 0) { struct radnode* par = n->parent; if(!par) { /* root deleted */ radnode_delete(rt->region, n); rt->root = NULL; return 1; } /* remove and delete the leaf node */ radnode_cleanup_leaf(rt->region, n, par); /* see if parent can now be cleaned up */ n = par; } else { /* node cannot be cleaned up */ return 1; } } /* ENOTREACH */ return 1; } void radix_delete(struct radtree* rt, struct radnode* n) { if(!n) return; n->elem = NULL; rt->count --; if(!radnode_cleanup(rt, n)) { /* out of memory in cleanup. the elem ptr is NULL, but * the radix tree could be inefficient. */ } } struct radnode* radix_search(struct radtree* rt, uint8_t* k, radstrlen_type len) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; while(n) { if(pos == len) return n->elem?n:NULL; byte = k[pos]; if(byte < n->offset) return NULL; byte -= n->offset; if(byte >= n->len) return NULL; pos++; if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) return NULL; /* no match */ if(memcmp(&k[pos], n->array[byte].str, n->array[byte].len) != 0) return NULL; /* no match */ pos += n->array[byte].len; } n = n->array[byte].node; } return NULL; } /** return self or a previous element */ static int ret_self_or_prev(struct radnode* n, struct radnode** result) { if(n->elem) *result = n; else *result = radix_prev(n); return 0; } int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; int r; if(!n) { /* empty tree */ *result = NULL; return 0; } while(pos < len) { byte = k[pos]; if(byte < n->offset) { /* so the previous is the element itself */ /* or something before this element */ return ret_self_or_prev(n, result); } byte -= n->offset; if(byte >= n->len) { /* so, the previous is the last of array, or itself */ /* or something before this element */ if((*result=radnode_last_in_subtree_incl_self(n))==0) *result = radix_prev(n); return 0; } pos++; if(!n->array[byte].node) { /* no match */ /* Find an entry in arrays from byte-1 to 0 */ *result = radnode_find_prev_from_idx(n, byte); if(*result) return 0; /* this entry or something before it */ return ret_self_or_prev(n, result); } if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) { /* the additional string is longer than key*/ if( (memcmp(&k[pos], n->array[byte].str, len-pos)) <= 0) { /* and the key is before this node */ *result = radix_prev(n->array[byte].node); } else { /* the key is after the additional * string, thus everything in that * subtree is smaller. */ *result=radnode_last_in_subtree_incl_self(n->array[byte].node); /* if somehow that is NULL, * then we have an inefficient tree: * byte+1 is larger than us, so find * something in byte-1 and before */ if(!*result) *result = radix_prev(n->array[byte].node); } return 0; /* no match */ } if( (r=memcmp(&k[pos], n->array[byte].str, n->array[byte].len)) < 0) { *result = radix_prev(n->array[byte].node); return 0; /* no match */ } else if(r > 0) { /* the key is larger than the additional * string, thus everything in that subtree * is smaller */ *result=radnode_last_in_subtree_incl_self(n->array[byte].node); /* if we have an inefficient tree */ if(!*result) *result = radix_prev(n->array[byte].node); return 0; /* no match */ } pos += n->array[byte].len; } n = n->array[byte].node; } if(n->elem) { /* exact match */ *result = n; return 1; } /* there is a node which is an exact match, but it has no element */ *result = radix_prev(n); return 0; } struct radnode* radix_first(struct radtree* rt) { struct radnode* n; if(!rt || !rt->root) return NULL; n = rt->root; if(n->elem) return n; return radix_next(n); } struct radnode* radix_last(struct radtree* rt) { if(!rt || !rt->root) return NULL; return radnode_last_in_subtree_incl_self(rt->root); } struct radnode* radix_next(struct radnode* n) { if(!n) return NULL; if(n->len) { /* go down */ struct radnode* s = radnode_first_in_subtree(n); if(s) return s; } /* go up - the parent->elem is not useful, because it is before us */ while(n->parent) { unsigned idx = n->pidx; n = n->parent; idx++; for(; idx < n->len; idx++) { /* go down the next branch */ if(n->array[idx].node) { struct radnode* s; /* node itself */ if(n->array[idx].node->elem) return n->array[idx].node; /* or subtree */ s = radnode_first_in_subtree( n->array[idx].node); if(s) return s; } } } return NULL; } struct radnode* radix_prev(struct radnode* n) { if(!n) return NULL; /* must go up, since all array nodes are after this node */ while(n->parent) { uint8_t idx = n->pidx; struct radnode* s; n = n->parent; assert(n->len > 0); /* since we are a child */ /* see if there are elements in previous branches there */ s = radnode_find_prev_from_idx(n, idx); if(s) return s; /* the current node is before the array */ if(n->elem) return n; } return NULL; } /** convert one character from domain-name to radname */ static uint8_t char_d2r(uint8_t c) { if(c < 'A') return c+1; /* make space for 00 */ else if(c <= 'Z') return c-'A'+'a'; /* lowercase */ else return c; } /** convert one character from radname to domain-name (still lowercased) */ static uint8_t char_r2d(uint8_t c) { assert(c != 0); /* end of label */ if(c <= 'A') return c-1; else return c; } /** copy and convert a range of characters */ static void cpy_d2r(uint8_t* to, const uint8_t* from, int len) { int i; for(i=0; i= dlen); assert(dlen > 0); /* even root label has dlen=1 */ /* root */ if(dlen == 1) { assert(dname[0] == 0); *len = 0; return; } /* walk through domain name and remember label positions */ do { /* compression pointers not allowed */ if((dname[dpos] & 0xc0)) { *len = 0; return; /* format error */ } labstart[lab++] = &dname[dpos]; if(dpos + dname[dpos] + 1 >= dlen) { *len = 0; return; /* format error */ } /* skip the label contents */ dpos += dname[dpos]; dpos ++; } while(dname[dpos] != 0); /* exit condition makes root label not in labelstart stack */ /* because the root was handled before, we know there is some text */ assert(lab > 0); lab-=1; kpos = *labstart[lab]; cpy_d2r(k, labstart[lab]+1, kpos); /* if there are more labels, copy them over */ while(lab) { /* put 'end-of-label' 00 to end previous label */ k[kpos++]=0; /* append the label */ lab--; cpy_d2r(k+kpos, labstart[lab]+1, *labstart[lab]); kpos += *labstart[lab]; } /* done */ assert(kpos == dlen-2); /* no rootlabel, one less label-marker */ *len = kpos; } /* radname code: radix-bstring to domain */ void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen) { /* find labels and push on stack */ uint8_t* labstart[130]; uint8_t lablen[130]; unsigned int lab = 0, dpos, kpos = 0; /* sufficient space */ assert(k && dname); assert((size_t)*dlen >= (size_t)len+2); assert(len <= 256); /* root label */ if(len == 0) { assert(*dlen > 0); dname[0]=0; *dlen=1; return; } /* find labels */ while(kpos < len) { lablen[lab]=0; labstart[lab]=&k[kpos]; /* skip to next label */ while(kpos < len && k[kpos] != 0) { lablen[lab]++; kpos++; } lab++; /* skip 00 byte for label-end */ if(kpos < len) { assert(k[kpos] == 0); kpos++; } } /* copy the labels over to the domain name */ dpos = 0; while(lab) { lab--; /* label length */ dname[dpos++] = lablen[lab]; /* label content */ cpy_r2d(dname+dpos, labstart[lab], lablen[lab]); dpos += lablen[lab]; } /* append root label */ dname[dpos++] = 0; /* assert the domain name is wellformed */ assert((int)dpos == (int)len+2); assert(dname[dpos-1] == 0); /* ends with root label */ *dlen = dpos; } /** insert by domain name */ struct radnode* radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem) { /* convert and insert */ uint8_t radname[300]; radstrlen_type len = (radstrlen_type)sizeof(radname); if(max > sizeof(radname)) return NULL; /* too long */ radname_d2r(radname, &len, d, max); return radix_insert(rt, radname, len, elem); } /** delete by domain name */ void radname_delete(struct radtree* rt, const uint8_t* d, size_t max) { /* search and remove */ struct radnode* n = radname_search(rt, d, max); if(n) radix_delete(rt, n); } /* search for exact match of domain name, converted to radname in tree */ struct radnode* radname_search(struct radtree* rt, const uint8_t* d, size_t max) { /* stack of labels in the domain name */ const uint8_t* labstart[130]; unsigned int lab, dpos, lpos; struct radnode* n = rt->root; uint8_t byte; radstrlen_type i; uint8_t b; /* search for root? it is '' */ if(max < 1) return NULL; if(d[0] == 0) { if(!n) return NULL; return n->elem?n:NULL; } /* find labels stack in domain name */ lab = 0; dpos = 0; /* must have one label, since root is specialcased */ do { if((d[dpos] & 0xc0)) return NULL; /* compression ptrs not allowed error */ labstart[lab++] = &d[dpos]; if(dpos + d[dpos] + 1 >= max) return NULL; /* format error: outside of bounds */ /* skip the label contents */ dpos += d[dpos]; dpos ++; } while(d[dpos] != 0); /* exit condition makes that root label is not in the labstarts */ /* now: dpos+1 is length of domain name. lab is number of labels-1 */ /* start processing at the last label */ lab-=1; lpos = 0; while(n) { /* fetch next byte this label */ if(lpos < *labstart[lab]) /* lpos+1 to skip labelstart, lpos++ to move forward */ byte = char_d2r(labstart[lab][++lpos]); else { if(lab == 0) /* last label - we're done */ return n->elem?n:NULL; /* next label, search for byte 00 */ lpos = 0; lab--; byte = 0; } /* find that byte in the array */ if(byte < n->offset) return NULL; byte -= n->offset; if(byte >= n->len) return NULL; if(n->array[byte].len != 0) { /* must match additional string */ /* see how many bytes we need and start matching them*/ for(i=0; iarray[byte].len; i++) { /* next byte to match */ if(lpos < *labstart[lab]) b = char_d2r(labstart[lab][++lpos]); else { /* if last label, no match since * we are in the additional string */ if(lab == 0) return NULL; /* next label, search for byte 00 */ lpos = 0; lab--; b = 0; } if(n->array[byte].str[i] != b) return NULL; /* not matched */ } } n = n->array[byte].node; } return NULL; } /* find domain name or smaller or equal domain name in radix tree */ int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max, struct radnode** result) { /* stack of labels in the domain name */ const uint8_t* labstart[130]; unsigned int lab, dpos, lpos; struct radnode* n = rt->root; uint8_t byte; radstrlen_type i; uint8_t b; /* empty tree */ if(!n) { *result = NULL; return 0; } /* search for root? it is '' */ if(max < 1) { *result = NULL; return 0; /* parse error, out of bounds */ } if(d[0] == 0) { if(n->elem) { *result = n; return 1; } /* no smaller element than the root */ *result = NULL; return 0; } /* find labels stack in domain name */ lab = 0; dpos = 0; /* must have one label, since root is specialcased */ do { if((d[dpos] & 0xc0)) { *result = NULL; return 0; /* compression ptrs not allowed error */ } labstart[lab++] = &d[dpos]; if(dpos + d[dpos] + 1 >= max) { *result = NULL; /* format error: outside of bounds */ return 0; } /* skip the label contents */ dpos += d[dpos]; dpos ++; } while(d[dpos] != 0); /* exit condition makes that root label is not in the labstarts */ /* now: dpos+1 is length of domain name. lab is number of labels-1 */ /* start processing at the last label */ lab-=1; lpos = 0; while(1) { /* fetch next byte this label */ if(lpos < *labstart[lab]) /* lpos+1 to skip labelstart, lpos++ to move forward */ byte = char_d2r(labstart[lab][++lpos]); else { if(lab == 0) { /* last label - we're done */ /* exact match */ if(n->elem) { *result = n; return 1; } /* there is a node which is an exact match, * but there no element in it */ *result = radix_prev(n); return 0; } /* next label, search for byte 0 the label separator */ lpos = 0; lab--; byte = 0; } /* find that byte in the array */ if(byte < n->offset) /* so the previous is the element itself */ /* or something before this element */ return ret_self_or_prev(n, result); byte -= n->offset; if(byte >= n->len) { /* so, the previous is the last of array, or itself */ /* or something before this element */ *result = radnode_last_in_subtree_incl_self(n); if(!*result) *result = radix_prev(n); return 0; } if(!n->array[byte].node) { /* no match */ /* Find an entry in arrays from byte-1 to 0 */ *result = radnode_find_prev_from_idx(n, byte); if(*result) return 0; /* this entry or something before it */ return ret_self_or_prev(n, result); } if(n->array[byte].len != 0) { /* must match additional string */ /* see how many bytes we need and start matching them*/ for(i=0; iarray[byte].len; i++) { /* next byte to match */ if(lpos < *labstart[lab]) b = char_d2r(labstart[lab][++lpos]); else { /* if last label, no match since * we are in the additional string */ if(lab == 0) { /* dname ended, thus before * this array element */ *result =radix_prev( n->array[byte].node); return 0; } /* next label, search for byte 00 */ lpos = 0; lab--; b = 0; } if(b < n->array[byte].str[i]) { *result =radix_prev( n->array[byte].node); return 0; } else if(b > n->array[byte].str[i]) { /* the key is after the additional, * so everything in its subtree is * smaller */ *result = radnode_last_in_subtree_incl_self(n->array[byte].node); /* if that is NULL, we have an * inefficient tree, find in byte-1*/ if(!*result) *result = radix_prev(n->array[byte].node); return 0; } } } n = n->array[byte].node; } /* ENOTREACH */ return 0; } nsd-4.12.0/query.h0000644000175000017500000001414515002373054013320 0ustar mozziemozzie/* * query.h -- manipulation with the queries * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef QUERY_H #define QUERY_H #include #include #include "namedb.h" #include "nsd.h" #include "packet.h" #include "tsig.h" struct ixfr_data; enum query_state { QUERY_PROCESSED, QUERY_DISCARDED, QUERY_IN_AXFR, QUERY_IN_IXFR }; typedef enum query_state query_state_type; /* Query as we pass it around */ typedef struct query query_type; struct query { /* * Memory region freed whenever the query is reset. */ region_type *region; /* * The address the query was received from. */ #ifdef INET6 struct sockaddr_storage remote_addr; #else struct sockaddr_in remote_addr; #endif socklen_t remote_addrlen; /* if set, the request came through a proxy */ int is_proxied; /* the client address * the same as remote_addr if not proxied */ #ifdef INET6 struct sockaddr_storage client_addr; #else struct sockaddr_in client_addr; #endif socklen_t client_addrlen; /* * Maximum supported query size. */ size_t maxlen; /* * Space reserved for optional records like EDNS. */ size_t reserved_space; /* EDNS information provided by the client. */ edns_record_type edns; /* TSIG record information and running hash for query-response */ tsig_record_type tsig; /* tsig actions can be overridden, for axfr transfer. */ int tsig_prepare_it, tsig_update_it, tsig_sign_it; int tcp; uint16_t tcplen; buffer_type *packet; #ifdef HAVE_SSL /* * TLS objects. */ SSL* tls; SSL* tls_auth; char* cert_cn; #endif /* Normalized query domain name. */ const dname_type *qname; /* Query type and class in host byte order. */ uint16_t qtype; uint16_t qclass; /* The zone used to answer the query. */ zone_type *zone; /* The delegation domain, if any. */ domain_type *delegation_domain; /* The delegation NS rrset, if any. */ rrset_type *delegation_rrset; /* Original opcode. */ uint8_t opcode; /* * The number of CNAMES followed. After a CNAME is followed * we no longer clear AA for a delegation and do not REFUSE * or SERVFAIL if the destination zone of the CNAME does not exist, * or is configured but not present. * Also includes number of DNAMES followed. */ int cname_count; /* Used for dname compression. */ uint16_t compressed_dname_count; domain_type **compressed_dnames; /* * Indexed by domain->number, index 0 is reserved for the * query name when generated from a wildcard record. */ uint16_t *compressed_dname_offsets; size_t compressed_dname_offsets_size; /* number of temporary domains used for the query */ size_t number_temporary_domains; /* * Used for AXFR processing. */ int axfr_is_done; zone_type *axfr_zone; domain_type *axfr_current_domain; rrset_type *axfr_current_rrset; uint16_t axfr_current_rr; /* Used for IXFR processing, * indicates if the zone transfer is done, connection can close. */ int ixfr_is_done; /* the ixfr data that is processed */ struct ixfr_data* ixfr_data; /* the ixfr data that is the last segment */ struct ixfr_data* ixfr_end_data; /* ixfr count of newsoa bytes added, 0 none, len means done */ size_t ixfr_count_newsoa; /* ixfr count of oldsoa bytes added, 0 none, len means done */ size_t ixfr_count_oldsoa; /* ixfr count of del bytes added, 0 none, len means done */ size_t ixfr_count_del; /* ixfr count of add bytes added, 0 none, len means done */ size_t ixfr_count_add; /* position for the end of SOA record, for UDP truncation */ size_t ixfr_pos_of_newsoa; #ifdef RATELIMIT /* if we encountered a wildcard, its domain */ domain_type *wildcard_domain; #endif }; /* Check if the last write resulted in an overflow. */ static inline int query_overflow(struct query *q); /* * Store the offset of the specified domain in the dname compression * table. */ void query_put_dname_offset(struct query *query, domain_type *domain, uint16_t offset); /* * Lookup the offset of the specified domain in the dname compression * table. Offset 0 is used to indicate the domain is not yet in the * compression table. */ static inline uint16_t query_get_dname_offset(struct query *query, domain_type *domain) { return query->compressed_dname_offsets[domain->number]; } /* * Remove all compressed dnames that have an offset that points beyond * the end of the current answer. This must be done after some RRs * are truncated and before adding new RRs. Otherwise dnames may be * compressed using truncated data! */ void query_clear_dname_offsets(struct query *query, size_t max_offset); /* * Clear the compression tables. */ void query_clear_compression_tables(struct query *query); /* * Enter the specified domain into the compression table starting at * the specified offset. */ void query_add_compression_domain(struct query *query, domain_type *domain, uint16_t offset); /* * Create a new query structure. */ query_type *query_create(region_type *region, uint16_t *compressed_dname_offsets, size_t compressed_dname_size, domain_type **compressed_dnames); /* * Reset a query structure so it is ready for receiving and processing * a new query. */ void query_reset(query_type *query, size_t maxlen, int is_tcp); /* * Process a query and write the response in the query I/O buffer. */ query_state_type query_process(query_type *q, nsd_type *nsd, uint32_t *now_p); /* * Prepare the query structure for writing the response. The packet * data up-to the current packet limit is preserved. This usually * includes the packet header and question section. Space is reserved * for the optional EDNS record, if required. */ void query_prepare_response(query_type *q); /* * Add EDNS0 information to the response if required. */ void query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p); /* * Write an error response into the query structure with the indicated * RCODE. */ query_state_type query_error(query_type *q, nsd_rc_type rcode); static inline int query_overflow(query_type *q) { return buffer_position(q->packet) > (q->maxlen - q->reserved_space); } #endif /* QUERY_H */ nsd-4.12.0/query.c0000644000175000017500000015450315002373054013316 0ustar mozziemozzie/* * query.c -- nsd(8) the resolver. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "answer.h" #include "axfr.h" #include "dns.h" #include "dname.h" #include "nsd.h" #include "namedb.h" #include "query.h" #include "util.h" #include "options.h" #include "nsec3.h" #include "tsig.h" /* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation. * This function determines if the final response packet needs the NS RRset * included. Currently, it will only return negative if QTYPE == DNSKEY|DS. * This way, resolvers won't fallback to TCP unnecessarily when priming * trust anchors. */ static int answer_needs_ns(struct query *query); static int add_rrset(struct query *query, answer_type *answer, rr_section_type section, domain_type *owner, rrset_type *rrset); static void answer_authoritative(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname); static void answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname); void query_put_dname_offset(struct query *q, domain_type *domain, uint16_t offset) { assert(q); assert(domain); assert(domain->number > 0); if (offset > MAX_COMPRESSION_OFFSET) return; if (q->compressed_dname_count >= MAX_COMPRESSED_DNAMES) return; q->compressed_dname_offsets[domain->number] = offset; q->compressed_dnames[q->compressed_dname_count] = domain; ++q->compressed_dname_count; } void query_clear_dname_offsets(struct query *q, size_t max_offset) { while (q->compressed_dname_count > 0 && (q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] >= max_offset)) { q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] = 0; --q->compressed_dname_count; } } void query_clear_compression_tables(struct query *q) { uint16_t i; for (i = 0; i < q->compressed_dname_count; ++i) { assert(q->compressed_dnames); q->compressed_dname_offsets[q->compressed_dnames[i]->number] = 0; } q->compressed_dname_count = 0; } void query_add_compression_domain(struct query *q, domain_type *domain, uint16_t offset) { while (domain->parent) { DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "query dname: %s, number: %lu, offset: %u\n", domain_to_string(domain), (unsigned long) domain->number, offset)); query_put_dname_offset(q, domain, offset); offset += label_length(dname_name(domain_dname(domain))) + 1; domain = domain->parent; } } /* * Generate an error response with the specified RCODE. */ query_state_type query_error (struct query *q, nsd_rc_type rcode) { if (rcode == NSD_RC_DISCARD) { return QUERY_DISCARDED; } 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... */ QDCOUNT_SET(q->packet, 0); ANCOUNT_SET(q->packet, 0); NSCOUNT_SET(q->packet, 0); ARCOUNT_SET(q->packet, 0); buffer_set_position(q->packet, QHEADERSZ); return QUERY_PROCESSED; } static int query_ratelimit_err(nsd_type* nsd) { time_t now = time(NULL); if(nsd->err_limit_time == now) { /* see if limit is exceeded for this second */ if(nsd->err_limit_count++ > ERROR_RATELIMIT) return 1; } else { /* new second, new limits */ nsd->err_limit_time = now; nsd->err_limit_count = 1; } return 0; } static query_state_type query_formerr (struct query *query, nsd_type* nsd) { int opcode = OPCODE(query->packet); if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; FLAGS_SET(query->packet, FLAGS(query->packet) & 0x0100U); /* Preserve the RD flag. Clear the rest. */ OPCODE_SET(query->packet, opcode); return query_error(query, NSD_RC_FORMAT); } static void query_cleanup(void *data) { query_type *query = (query_type *) data; region_destroy(query->region); } query_type * query_create(region_type *region, uint16_t *compressed_dname_offsets, size_t compressed_dname_size, domain_type **compressed_dnames) { query_type *query = (query_type *) region_alloc_zero(region, sizeof(query_type)); /* create region with large block size, because the initial chunk saves many mallocs in the server */ query->region = region_create_custom(xalloc, free, 16384, 16384/8, 32, 0); query->compressed_dname_offsets = compressed_dname_offsets; query->compressed_dnames = compressed_dnames; query->packet = buffer_create(region, QIOBUFSZ); region_add_cleanup(region, query_cleanup, query); query->compressed_dname_offsets_size = compressed_dname_size; tsig_create_record(&query->tsig, region); query->tsig_prepare_it = 1; query->tsig_update_it = 1; query->tsig_sign_it = 1; return query; } void query_reset(query_type *q, size_t maxlen, int is_tcp) { /* * As long as less than 4Kb (region block size) has been used, * this call to free_all is free, the block is saved for re-use, * so no malloc() or free() calls are done. * at present use of the region is for: * o query qname dname_type (255 max). * o wildcard expansion domain_type (7*ptr+u32+2bytes)+(5*ptr nsec3) * o wildcard expansion for additional section domain_type. * o nsec3 hashed name(s) (3 dnames for a nonexist_proof, * one proof per wildcard and for nx domain). */ region_free_all(q->region); q->remote_addrlen = (socklen_t)sizeof(q->remote_addr); q->client_addrlen = (socklen_t)sizeof(q->client_addr); q->is_proxied = 0; q->maxlen = maxlen; q->reserved_space = 0; buffer_clear(q->packet); edns_init_record(&q->edns); tsig_init_record(&q->tsig, NULL, NULL); q->tsig_prepare_it = 1; q->tsig_update_it = 1; q->tsig_sign_it = 1; q->tcp = is_tcp; q->qname = NULL; q->qtype = 0; q->qclass = 0; q->zone = NULL; q->opcode = 0; q->cname_count = 0; q->delegation_domain = NULL; q->delegation_rrset = NULL; q->compressed_dname_count = 0; q->number_temporary_domains = 0; q->axfr_is_done = 0; q->axfr_zone = NULL; q->axfr_current_domain = NULL; q->axfr_current_rrset = NULL; q->axfr_current_rr = 0; q->ixfr_is_done = 0; q->ixfr_data = NULL; q->ixfr_count_newsoa = 0; q->ixfr_count_oldsoa = 0; q->ixfr_count_del = 0; q->ixfr_count_add = 0; #ifdef RATELIMIT q->wildcard_domain = NULL; #endif } /* get a temporary domain number (or 0=failure) */ static domain_type* query_get_tempdomain(struct query *q) { static domain_type d[EXTRA_DOMAIN_NUMBERS]; if(q->number_temporary_domains >= EXTRA_DOMAIN_NUMBERS) return 0; q->number_temporary_domains ++; memset(&d[q->number_temporary_domains-1], 0, sizeof(domain_type)); d[q->number_temporary_domains-1].number = q->compressed_dname_offsets_size + q->number_temporary_domains - 1; return &d[q->number_temporary_domains-1]; } static void query_addtxt(struct query *q, const uint8_t *dname, uint16_t klass, uint32_t ttl, const char *txt) { size_t txt_length = strlen(txt); uint8_t len = (uint8_t) txt_length; assert(txt_length <= UCHAR_MAX); /* Add the dname */ if (dname >= buffer_begin(q->packet) && dname <= buffer_current(q->packet)) { buffer_write_u16(q->packet, 0xc000 | (dname - buffer_begin(q->packet))); } else { buffer_write(q->packet, dname + 1, *dname); } buffer_write_u16(q->packet, TYPE_TXT); buffer_write_u16(q->packet, klass); buffer_write_u32(q->packet, ttl); buffer_write_u16(q->packet, len + 1); buffer_write_u8(q->packet, len); buffer_write(q->packet, txt, len); } /* * Parse the question section of a query. The normalized query name * is stored in QUERY->name, the class in QUERY->klass, and the type * in QUERY->type. */ static int process_query_section(query_type *query) { uint8_t qnamebuf[MAXDOMAINLEN]; buffer_set_position(query->packet, QHEADERSZ); /* Lets parse the query name and convert it to lower case. */ if(!packet_read_query_section(query->packet, qnamebuf, &query->qtype, &query->qclass)) return 0; query->qname = dname_make(query->region, qnamebuf, 1); return 1; } /* * Process an optional EDNS OPT record. Sets QUERY->EDNS to 0 if * there was no EDNS record, to -1 if there was an invalid or * unsupported EDNS record, and to 1 otherwise. Updates QUERY->MAXLEN * if the EDNS record specifies a maximum supported response length. * * Return NSD_RC_FORMAT on failure, NSD_RC_OK on success. */ static nsd_rc_type process_edns(nsd_type* nsd, struct query *q) { if (q->edns.status == EDNS_ERROR) { /* The only error is VERSION not implemented */ return NSD_RC_FORMAT; } if (q->edns.status == EDNS_OK) { /* Only care about UDP size larger than normal... */ if (!q->tcp && q->edns.maxlen > UDP_MAX_MESSAGE_LEN) { size_t edns_size; #if defined(INET6) if (q->client_addr.ss_family == AF_INET6) { edns_size = nsd->ipv6_edns_size; } else #endif edns_size = nsd->ipv4_edns_size; if (q->edns.maxlen < edns_size) { q->maxlen = q->edns.maxlen; } else { q->maxlen = edns_size; } #if defined(INET6) && !defined(IPV6_USE_MIN_MTU) && !defined(IPV6_MTU) /* * Use IPv6 minimum MTU to avoid sending * packets that are too large for some links. * IPv6 will not automatically fragment in * this case (unlike IPv4). */ if (q->client_addr.ss_family == AF_INET6 && q->maxlen > IPV6_MIN_MTU) { q->maxlen = IPV6_MIN_MTU; } #endif } /* Strip the OPT resource record off... */ buffer_set_position(q->packet, q->edns.position); buffer_set_limit(q->packet, q->edns.position); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1); } return NSD_RC_OK; } /* * Processes TSIG. * Sets error when tsig does not verify on the query. */ static nsd_rc_type process_tsig(struct query* q) { if(q->tsig.status == TSIG_ERROR) return NSD_RC_FORMAT; if(q->tsig.status == TSIG_OK) { if(!tsig_from_query(&q->tsig)) { char a[128]; addr2str(&q->client_addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig (%s) for key %s from %s", tsig_error(q->tsig.error_code), dname_to_string(q->tsig.key_name, NULL), a); return NSD_RC_NOTAUTH; } buffer_set_limit(q->packet, q->tsig.position); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1); tsig_prepare(&q->tsig); tsig_update(&q->tsig, q->packet, buffer_limit(q->packet)); if(!tsig_verify(&q->tsig)) { char a[128]; addr2str(&q->client_addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig signature for key %s from %s", dname_to_string(q->tsig.key->name, NULL), a); return NSD_RC_NOTAUTH; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "query good tsig signature for %s", dname_to_string(q->tsig.key->name, NULL))); } return NSD_RC_OK; } /* * Check notify acl and forward to xfrd (or return an error). */ static query_state_type answer_notify(struct nsd* nsd, struct query *query) { int acl_num, acl_num_xfr; struct acl_options *why; nsd_rc_type rc; struct zone_options* zone_opt; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s processing acl", dname_to_string(query->qname, NULL))); zone_opt = zone_options_find(nsd->options, query->qname); if(!zone_opt) return query_error(query, NSD_RC_NXDOMAIN); if(!nsd->this_child) /* we are in debug mode or something */ return query_error(query, NSD_RC_SERVFAIL); if(!tsig_find_rr(&query->tsig, query->packet)) { DEBUG(DEBUG_XFRD,2, (LOG_ERR, "bad tsig RR format")); return query_error(query, NSD_RC_FORMAT); } rc = process_tsig(query); if(rc != NSD_RC_OK) return query_error(query, rc); /* check if it passes acl */ if(query->is_proxied && acl_check_incoming_block_proxy( zone_opt->pattern->allow_notify, query, &why) == -1) { /* the proxy address is blocked */ if (verbosity >= 2) { char address[128], proxy[128]; addr2str(&query->client_addr, address, sizeof(address)); addr2str(&query->remote_addr, proxy, sizeof(proxy)); VERBOSITY(2, (LOG_INFO, "notify for %s from %s via proxy %s refused because of proxy, %s%s%s", dname_to_string(query->qname, NULL), address, proxy, (why?why->ip_address_spec:""), (why&&why->ip_address_spec[0]?" ":""), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches"))); } return query_error(query, NSD_RC_REFUSE); } if((acl_num = acl_check_incoming(zone_opt->pattern->allow_notify, query, &why)) != -1) { int s = nsd->serve2xfrd_fd_send[nsd->this_child->child_num]; uint16_t sz; uint32_t acl_send = htonl(acl_num); uint32_t acl_xfr; size_t pos; /* Find priority candidate for request XFR. -1 if no match */ acl_num_xfr = acl_check_incoming( zone_opt->pattern->request_xfr, query, NULL); acl_xfr = htonl(acl_num_xfr); assert(why); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s passed acl %s %s", dname_to_string(query->qname, NULL), why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); if(buffer_limit(query->packet) > MAX_PACKET_SIZE) return query_error(query, NSD_RC_SERVFAIL); /* forward to xfrd for processing Note. Blocking IPC I/O, but acl is OK. */ sz = buffer_limit(query->packet) + sizeof(acl_send) + sizeof(acl_xfr); sz = htons(sz); if(!write_socket(s, &sz, sizeof(sz)) || !write_socket(s, buffer_begin(query->packet), buffer_limit(query->packet)) || !write_socket(s, &acl_send, sizeof(acl_send)) || !write_socket(s, &acl_xfr, sizeof(acl_xfr))) { log_msg(LOG_ERR, "error in IPC notify server2main, %s", strerror(errno)); return query_error(query, NSD_RC_SERVFAIL); } if(verbosity >= 1) { uint32_t serial = 0; char address[128]; addr2str(&query->client_addr, address, sizeof(address)); if(packet_find_notify_serial(query->packet, &serial)) VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u", dname_to_string(query->qname, NULL), address, (unsigned)serial)); else VERBOSITY(1, (LOG_INFO, "notify for %s from %s", dname_to_string(query->qname, NULL), address)); } /* create notify reply - keep same query contents */ QR_SET(query->packet); /* This is an answer. */ AA_SET(query->packet); /* we are authoritative. */ ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); RCODE_SET(query->packet, RCODE_OK); /* Error code. */ /* position is right after the query */ pos = buffer_position(query->packet); buffer_clear(query->packet); buffer_set_position(query->packet, pos); /* tsig is added in add_additional later (if needed) */ return QUERY_PROCESSED; } if (verbosity >= 2) { char address[128]; addr2str(&query->client_addr, address, sizeof(address)); VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s%s%s", dname_to_string(query->qname, NULL), address, (why?why->ip_address_spec:""), (why&&why->ip_address_spec[0]?" ":""), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches"))); } return query_error(query, NSD_RC_REFUSE); } /* * Answer a query in the CHAOS class. */ static query_state_type answer_chaos(struct nsd *nsd, query_type *q) { AA_CLR(q->packet); switch (q->qtype) { case TYPE_ANY: case TYPE_TXT: if ((q->qname->name_size == 11 && memcmp(dname_name(q->qname), "\002id\006server", 11) == 0) || (q->qname->name_size == 15 && memcmp(dname_name(q->qname), "\010hostname\004bind", 15) == 0)) { if(!nsd->options->hide_identity) { /* Add ID */ query_addtxt(q, buffer_begin(q->packet) + QHEADERSZ, CLASS_CH, 0, nsd->identity); ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1); } else { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; } } else if ((q->qname->name_size == 16 && memcmp(dname_name(q->qname), "\007version\006server", 16) == 0) || (q->qname->name_size == 14 && memcmp(dname_name(q->qname), "\007version\004bind", 14) == 0)) { if(!nsd->options->hide_version) { /* Add version */ query_addtxt(q, buffer_begin(q->packet) + QHEADERSZ, CLASS_CH, 0, nsd->version); ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1); } else { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; } } else { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.22. Extended DNS Error Code 21 - Not Supported */ q->edns.ede = EDE_NOT_SUPPORTED; } break; default: RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.22. Extended DNS Error Code 21 - Not Supported */ q->edns.ede = EDE_NOT_SUPPORTED; break; } return QUERY_PROCESSED; } /* * Find the covering NSEC for a non-existent domain name. Normally * the NSEC will be located at CLOSEST_MATCH, except when it is an * empty non-terminal. In this case the NSEC may be located at the * previous domain name (in canonical ordering). */ static domain_type * find_covering_nsec(domain_type *closest_match, zone_type *zone, rrset_type **nsec_rrset) { assert(closest_match); assert(nsec_rrset); /* loop away temporary created domains. For real ones it is &RBTREE_NULL */ #ifdef USE_RADIX_TREE while (closest_match->rnode == NULL) #else while (closest_match->node.parent == NULL) #endif closest_match = closest_match->parent; while (closest_match) { *nsec_rrset = domain_find_rrset(closest_match, zone, TYPE_NSEC); if (*nsec_rrset) { return closest_match; } if (closest_match == zone->apex) { /* Don't look outside the current zone. */ return NULL; } closest_match = domain_previous(closest_match); } return NULL; } struct additional_rr_types { uint16_t rr_type; rr_section_type rr_section; }; struct additional_rr_types default_additional_rr_types[] = { { TYPE_A, ADDITIONAL_A_SECTION }, { TYPE_AAAA, ADDITIONAL_AAAA_SECTION }, { 0, (rr_section_type) 0 } }; struct additional_rr_types swap_aaaa_additional_rr_types[] = { { TYPE_AAAA, ADDITIONAL_A_SECTION }, { TYPE_A, ADDITIONAL_AAAA_SECTION }, { 0, (rr_section_type) 0 } }; struct additional_rr_types rt_additional_rr_types[] = { { TYPE_A, ADDITIONAL_A_SECTION }, { TYPE_AAAA, ADDITIONAL_AAAA_SECTION }, { TYPE_X25, ADDITIONAL_OTHER_SECTION }, { TYPE_ISDN, ADDITIONAL_OTHER_SECTION }, { 0, (rr_section_type) 0 } }; static void add_additional_rrsets(struct query *query, answer_type *answer, rrset_type *master_rrset, size_t rdata_index, int allow_glue, struct additional_rr_types types[]) { size_t i; assert(query); assert(answer); assert(master_rrset); assert(rdata_atom_is_domain(rrset_rrtype(master_rrset), rdata_index)); for (i = 0; i < master_rrset->rr_count; ++i) { int j; domain_type *additional = rdata_atom_domain(master_rrset->rrs[i].rdatas[rdata_index]); domain_type *match = additional; assert(additional); if (!allow_glue && domain_is_glue(match, query->zone)) continue; /* * Check to see if we need to generate the dependent * based on a wildcard domain. */ while (!match->is_existing) { match = match->parent; } if (additional != match && domain_wildcard_child(match)) { domain_type *wildcard_child = domain_wildcard_child(match); domain_type *temp = (domain_type *) region_alloc( query->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE temp->rnode = NULL; temp->dname = additional->dname; #else memcpy(&temp->node, &additional->node, sizeof(rbnode_type)); temp->node.parent = NULL; #endif temp->number = additional->number; temp->parent = match; temp->wildcard_child_closest_match = temp; temp->rrsets = wildcard_child->rrsets; temp->is_existing = wildcard_child->is_existing; additional = temp; } for (j = 0; types[j].rr_type != 0; ++j) { rrset_type *rrset = domain_find_rrset( additional, query->zone, types[j].rr_type); if (rrset) { answer_add_rrset(answer, types[j].rr_section, additional, rrset); } } } } static int answer_needs_ns(struct query* query) { assert(query); /* Currently, only troublesome for DNSKEY and DS, * cuz their RRSETs are quite large. */ return (query->qtype != TYPE_DNSKEY && query->qtype != TYPE_DS && query->qtype != TYPE_ANY); } static int add_rrset(struct query *query, answer_type *answer, rr_section_type section, domain_type *owner, rrset_type *rrset) { int result; assert(query); assert(answer); assert(owner); assert(rrset); assert(rrset_rrclass(rrset) == CLASS_IN); result = answer_add_rrset(answer, section, owner, rrset); if(minimal_responses && section != AUTHORITY_SECTION && query->qtype != TYPE_NS) return result; switch (rrset_rrtype(rrset)) { case TYPE_NS: #if defined(INET6) /* if query over IPv6, swap A and AAAA; put AAAA first */ add_additional_rrsets(query, answer, rrset, 0, 1, (query->client_addr.ss_family == AF_INET6)? swap_aaaa_additional_rr_types: default_additional_rr_types); #else add_additional_rrsets(query, answer, rrset, 0, 1, default_additional_rr_types); #endif break; case TYPE_MB: add_additional_rrsets(query, answer, rrset, 0, 0, default_additional_rr_types); break; case TYPE_MX: case TYPE_KX: add_additional_rrsets(query, answer, rrset, 1, 0, default_additional_rr_types); break; case TYPE_RT: add_additional_rrsets(query, answer, rrset, 1, 0, rt_additional_rr_types); break; case TYPE_SRV: add_additional_rrsets(query, answer, rrset, 3, 0, default_additional_rr_types); break; default: break; } return result; } /* returns 0 on error, or the domain number for to_name. from_name is changes to to_name by the DNAME rr. DNAME rr is from src to dest. closest encloser encloses the to_name. */ static size_t query_synthesize_cname(struct query* q, struct answer* answer, const dname_type* from_name, const dname_type* to_name, domain_type* src, domain_type* to_closest_encloser, domain_type** to_closest_match, uint32_t ttl) { /* add temporary domains for from_name and to_name and all their (not allocated yet) parents */ /* any domains below src are not_existing (because of DNAME at src) */ int i; size_t j; domain_type* cname_domain; domain_type* cname_dest; rrset_type* rrset; domain_type* lastparent = src; assert(q && answer && from_name && to_name && src && to_closest_encloser); assert(to_closest_match); /* check for loop by duplicate CNAME rrset synthesized */ for(j=0; jrrset_count; ++j) { if(answer->section[j] == ANSWER_SECTION && answer->rrsets[j]->rr_count == 1 && answer->rrsets[j]->rrs[0].type == TYPE_CNAME && dname_compare(domain_dname(answer->rrsets[j]->rrs[0].owner), from_name) == 0 && answer->rrsets[j]->rrs[0].rdata_count == 1 && dname_compare(domain_dname(answer->rrsets[j]->rrs[0].rdatas->domain), to_name) == 0) { DEBUG(DEBUG_QUERY,2, (LOG_INFO, "loop for synthesized CNAME rrset for query %s", dname_to_string(q->qname, NULL))); return 0; } } /* allocate source part */ for(i=0; i < from_name->label_count - domain_dname(src)->label_count; i++) { domain_type* newdom = query_get_tempdomain(q); if(!newdom) return 0; newdom->is_existing = 1; newdom->parent = lastparent; #ifdef USE_RADIX_TREE newdom->dname #else newdom->node.key #endif = dname_partial_copy(q->region, from_name, domain_dname(src)->label_count + i + 1); if(dname_compare(domain_dname(newdom), q->qname) == 0) { /* 0 good for query name, otherwise new number */ newdom->number = 0; } DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain src %d. %s nr %d", i, domain_to_string(newdom), (int)newdom->number)); lastparent = newdom; } cname_domain = lastparent; /* allocate dest part */ lastparent = to_closest_encloser; for(i=0; i < to_name->label_count - domain_dname(to_closest_encloser)->label_count; i++) { domain_type* newdom = query_get_tempdomain(q); if(!newdom) return 0; newdom->is_existing = 0; newdom->parent = lastparent; #ifdef USE_RADIX_TREE newdom->dname #else newdom->node.key #endif = dname_partial_copy(q->region, to_name, domain_dname(to_closest_encloser)->label_count + i + 1); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain dest %d. %s nr %d", i, domain_to_string(newdom), (int)newdom->number)); lastparent = newdom; } cname_dest = lastparent; *to_closest_match = cname_dest; /* allocate the CNAME RR */ rrset = (rrset_type*) region_alloc(q->region, sizeof(rrset_type)); memset(rrset, 0, sizeof(rrset_type)); rrset->zone = q->zone; rrset->rr_count = 1; rrset->rrs = (rr_type*) region_alloc(q->region, sizeof(rr_type)); memset(rrset->rrs, 0, sizeof(rr_type)); rrset->rrs->owner = cname_domain; rrset->rrs->ttl = ttl; rrset->rrs->type = TYPE_CNAME; rrset->rrs->klass = CLASS_IN; rrset->rrs->rdata_count = 1; rrset->rrs->rdatas = (rdata_atom_type*)region_alloc(q->region, sizeof(rdata_atom_type)); rrset->rrs->rdatas->domain = cname_dest; if(!add_rrset(q, answer, ANSWER_SECTION, cname_domain, rrset)) { DEBUG(DEBUG_QUERY,2, (LOG_INFO, "could not add synthesized CNAME rrset to packet for query %s", dname_to_string(q->qname, NULL))); /* failure to add CNAME; likely is a loop, the same twice */ return 0; } return cname_dest->number; } /* * Answer delegation information. * * DNSSEC: Include the DS RRset if present. Otherwise include an NSEC * record proving the DS RRset does not exist. */ static void answer_delegation(query_type *query, answer_type *answer) { assert(answer); assert(query->delegation_domain); assert(query->delegation_rrset); if (query->cname_count == 0) { AA_CLR(query->packet); } else { AA_SET(query->packet); } add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, query->delegation_rrset); if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { rrset_type *rrset; if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_DS))) { add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, rrset); #ifdef NSEC3 } else if (query->zone->nsec3_param) { nsec3_answer_delegation(query, answer); #endif } else if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_NSEC))) { add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, rrset); } } } /* * Answer SOA information. */ static void answer_soa(struct query *query, answer_type *answer) { if (query->qclass != CLASS_ANY) { add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex, query->zone->soa_nx_rrset); } } /* * Answer that the domain name exists but there is no RRset with the * requested type. * * DNSSEC: Include the correct NSEC record proving that the type does * not exist. In the wildcard no data (3.1.3.4) case the wildcard IS * NOT expanded, so the ORIGINAL parameter must point to the original * wildcard entry, not to the generated entry. */ static void answer_nodata(struct query *query, answer_type *answer, domain_type *original) { answer_soa(query, answer); #ifdef NSEC3 if (query->edns.dnssec_ok && query->zone->nsec3_param) { nsec3_answer_nodata(query, answer, original); } else #endif if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { domain_type *nsec_domain; rrset_type *nsec_rrset; nsec_domain = find_covering_nsec(original, query->zone, &nsec_rrset); if (nsec_domain) { add_rrset(query, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } } static void answer_nxdomain(query_type *query, answer_type *answer) { RCODE_SET(query->packet, RCODE_NXDOMAIN); answer_soa(query, answer); } /* * Answer domain information (or SOA if we do not have an RRset for * the type specified by the query). */ static void answer_domain(struct nsd* nsd, struct query *q, answer_type *answer, domain_type *domain, domain_type *original) { rrset_type *rrset; if (q->qtype == TYPE_ANY) { rrset_type *preferred_rrset = NULL; rrset_type *normal_rrset = NULL; rrset_type *non_preferred_rrset = NULL; /* * Minimize response size for ANY, with one RRset * according to RFC 8482(4.1). * Prefers popular and not large rtypes (A,AAAA,...) * lowering large ones (DNSKEY,RRSIG,...). */ for (rrset = domain_find_any_rrset(domain, q->zone); rrset; rrset = rrset->next) { if (rrset->zone == q->zone #ifdef NSEC3 && rrset_rrtype(rrset) != TYPE_NSEC3 #endif /* * Don't include the RRSIG RRset when * DNSSEC is used, because it is added * automatically on an per-RRset basis. */ && !(q->edns.dnssec_ok && zone_is_secure(q->zone) && rrset_rrtype(rrset) == TYPE_RRSIG)) { switch(rrset_rrtype(rrset)) { case TYPE_A: case TYPE_AAAA: case TYPE_SOA: case TYPE_MX: case TYPE_PTR: preferred_rrset = rrset; break; case TYPE_DNSKEY: case TYPE_RRSIG: case TYPE_NSEC: non_preferred_rrset = rrset; break; default: normal_rrset = rrset; } if (preferred_rrset) break; } } if (preferred_rrset) { add_rrset(q, answer, ANSWER_SECTION, domain, preferred_rrset); } else if (normal_rrset) { add_rrset(q, answer, ANSWER_SECTION, domain, normal_rrset); } else if (non_preferred_rrset) { add_rrset(q, answer, ANSWER_SECTION, domain, non_preferred_rrset); } else { answer_nodata(q, answer, original); return; } #ifdef NSEC3 } else if (q->qtype == TYPE_NSEC3) { answer_nodata(q, answer, original); return; #endif } else if ((rrset = domain_find_rrset(domain, q->zone, q->qtype))) { add_rrset(q, answer, ANSWER_SECTION, domain, rrset); } else if ((rrset = domain_find_rrset(domain, q->zone, TYPE_CNAME))) { int added; /* * If the CNAME is not added it is already in the * answer, so we have a CNAME loop. Don't follow the * CNAME target in this case. */ added = add_rrset(q, answer, ANSWER_SECTION, domain, rrset); assert(rrset->rr_count > 0); if (added) { /* only process first CNAME record */ domain_type *closest_match = rdata_atom_domain(rrset->rrs[0].rdatas[0]); domain_type *closest_encloser = closest_match; zone_type* origzone = q->zone; ++q->cname_count; answer_lookup_zone(nsd, q, answer, closest_match->number, closest_match == closest_encloser, closest_match, closest_encloser, domain_dname(closest_match)); q->zone = origzone; } return; } else { answer_nodata(q, answer, original); return; } if (q->qclass != CLASS_ANY && q->zone->ns_rrset && answer_needs_ns(q) && !minimal_responses) { add_rrset(q, answer, OPTIONAL_AUTHORITY_SECTION, q->zone->apex, q->zone->ns_rrset); } } /* * Answer with authoritative data. If a wildcard is matched the owner * name will be expanded to the domain name specified by * DOMAIN_NUMBER. DOMAIN_NUMBER 0 (zero) is reserved for the original * query name. * * DNSSEC: Include the necessary NSEC records in case the request * domain name does not exist and/or a wildcard match does not exist. */ static void answer_authoritative(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname) { domain_type *match; domain_type *original = closest_match; domain_type *dname_ce; domain_type *wildcard_child; rrset_type *rrset; #ifdef NSEC3 if(exact && domain_has_only_NSEC3(closest_match, q->zone)) { exact = 0; /* pretend it does not exist */ if(closest_encloser->parent) closest_encloser = closest_encloser->parent; } #endif /* NSEC3 */ if((dname_ce = find_dname_above(closest_encloser, q->zone)) != NULL) { /* occlude the found data, the DNAME is closest_encloser */ closest_encloser = dname_ce; exact = 0; } if (exact) { match = closest_match; } else if ((rrset=domain_find_rrset(closest_encloser, q->zone, TYPE_DNAME))) { /* process DNAME */ const dname_type* name = qname; domain_type* src = closest_encloser; domain_type *dest = rdata_atom_domain(rrset->rrs[0].rdatas[0]); const dname_type* newname; size_t newnum = 0; zone_type* origzone = q->zone; assert(rrset->rr_count > 0); if(domain_number != 0) /* we followed CNAMEs or DNAMEs */ name = domain_dname(closest_match); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "expanding DNAME for q=%s", dname_to_string(name, NULL))); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->src is %s", domain_to_string(closest_encloser))); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->dest is %s", domain_to_string(dest))); if(!add_rrset(q, answer, ANSWER_SECTION, closest_encloser, rrset)) { /* stop if DNAME loops, when added second time */ if(dname_is_subdomain(domain_dname(dest), domain_dname(src))) { return; } } newname = dname_replace(q->region, name, domain_dname(src), domain_dname(dest)); ++q->cname_count; if(!newname) { /* newname too long */ RCODE_SET(q->packet, RCODE_YXDOMAIN); /* RFC 8914 - Extended DNS Errors * 4.21. Extended DNS Error Code 0 - Other */ ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede, EDE_OTHER, "DNAME expansion became too large"); return; } DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->result is %s", dname_to_string(newname, NULL))); /* follow the DNAME */ (void)namedb_lookup(nsd->db, newname, &closest_match, &closest_encloser); /* synthesize CNAME record */ newnum = query_synthesize_cname(q, answer, name, newname, src, closest_encloser, &closest_match, rrset->rrs[0].ttl); if(!newnum) { /* could not synthesize the CNAME. */ /* return previous CNAMEs to make resolver recurse for us */ return; } if(q->qtype == TYPE_CNAME) { /* The synthesized CNAME is the answer to * that query, same as BIND does for query * of type CNAME */ return; } answer_lookup_zone(nsd, q, answer, newnum, closest_match == closest_encloser, closest_match, closest_encloser, newname); q->zone = origzone; return; } else if ((wildcard_child=domain_wildcard_child(closest_encloser))!=NULL && wildcard_child->is_existing) { /* Generate the domain from the wildcard. */ #ifdef RATELIMIT q->wildcard_domain = wildcard_child; #endif match = (domain_type *) region_alloc(q->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE match->rnode = NULL; match->dname = wildcard_child->dname; #else memcpy(&match->node, &wildcard_child->node, sizeof(rbnode_type)); match->node.parent = NULL; #endif match->parent = closest_encloser; match->wildcard_child_closest_match = match; match->number = domain_number; match->rrsets = wildcard_child->rrsets; match->is_existing = wildcard_child->is_existing; #ifdef NSEC3 match->nsec3 = wildcard_child->nsec3; /* copy over these entries: match->nsec3_is_exact = wildcard_child->nsec3_is_exact; match->nsec3_cover = wildcard_child->nsec3_cover; match->nsec3_wcard_child_cover = wildcard_child->nsec3_wcard_child_cover; match->nsec3_ds_parent_is_exact = wildcard_child->nsec3_ds_parent_is_exact; match->nsec3_ds_parent_cover = wildcard_child->nsec3_ds_parent_cover; */ if (q->edns.dnssec_ok && q->zone->nsec3_param) { /* Only add nsec3 wildcard data when do bit is set */ nsec3_answer_wildcard(q, answer, wildcard_child, qname); } #endif /* * Remember the original domain in case a Wildcard No * Data (3.1.3.4) response needs to be generated. In * this particular case the wildcard IS NOT * expanded. */ original = wildcard_child; } else { match = NULL; } /* Authoritative zone. */ #ifdef NSEC3 if (q->edns.dnssec_ok && q->zone->nsec3_param) { nsec3_answer_authoritative(&match, q, answer, closest_encloser, qname); } else #endif if (q->edns.dnssec_ok && zone_is_secure(q->zone)) { if (match != closest_encloser) { domain_type *nsec_domain; rrset_type *nsec_rrset; /* * No match found or generated from wildcard, * include NSEC record. */ nsec_domain = find_covering_nsec(closest_match, q->zone, &nsec_rrset); if (nsec_domain) { add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } if (!match) { domain_type *nsec_domain; rrset_type *nsec_rrset; /* * No match and no wildcard. Include NSEC * proving there is no wildcard. */ if(closest_encloser && (nsec_domain = find_covering_nsec(closest_encloser-> wildcard_child_closest_match, q->zone, &nsec_rrset)) != NULL) { add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } } #ifdef NSEC3 if (RCODE(q->packet)!=RCODE_OK) { return; /* nsec3 collision failure */ } #endif if (match) { answer_domain(nsd, q, answer, match, original); } else { answer_nxdomain(q, answer); } } /* * qname may be different after CNAMEs have been followed from query->qname. */ static void answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname) { zone_type* origzone = q->zone; q->zone = domain_find_zone(nsd->db, closest_encloser); if (!q->zone) { /* no zone for this */ if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC 8914 - Extended DNS Errors * 4.21. Extended DNS Error Code 20 - Not Authoritative */ q->edns.ede = EDE_NOT_AUTHORITATIVE; } return; } assert(closest_encloser); /* otherwise, no q->zone would be found */ if(q->zone->opts && q->zone->opts->pattern && q->zone->opts->pattern->allow_query) { struct acl_options *why = NULL; /* check if it passes acl */ if(q->is_proxied && acl_check_incoming_block_proxy( q->zone->opts->pattern->allow_query, q, &why) == -1) { /* the proxy address is blocked */ if (verbosity >= 2) { char address[128], proxy[128]; addr2str(&q->client_addr, address, sizeof(address)); addr2str(&q->remote_addr, proxy, sizeof(proxy)); VERBOSITY(2, (LOG_INFO, "query %s from %s via proxy %s refused because of proxy, %s%s%s", dname_to_string(q->qname, NULL), address, proxy, (why?why->ip_address_spec:""), (why&&why->ip_address_spec[0]?" ":""), (why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches"))); } /* no zone for this */ if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; } return; } if(acl_check_incoming( q->zone->opts->pattern->allow_query, q, &why) != -1) { assert(why); DEBUG(DEBUG_QUERY,1, (LOG_INFO, "query %s passed acl %s %s", dname_to_string(q->qname, NULL), why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); } else if(q->qtype == TYPE_SOA && 0 == dname_compare(q->qname, (const dname_type*)q->zone->opts->node.key) && -1 != acl_check_incoming( q->zone->opts->pattern->provide_xfr, q,&why)) { assert(why); DEBUG(DEBUG_QUERY,1, (LOG_INFO, "SOA apex query %s " "passed request-xfr acl %s %s", dname_to_string(q->qname, NULL), why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); } else { if (q->cname_count == 0 && verbosity >= 2) { char address[128]; addr2str(&q->client_addr, address, sizeof(address)); VERBOSITY(2, (LOG_INFO, "query %s from %s refused, %s%s%s", dname_to_string(q->qname, NULL), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" : why->key_name ) : "no acl matches", (why&&why->ip_address_spec[0]?" ":""), why?why->ip_address_spec:"")); } /* no zone for this */ if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; } return; } } if(!q->zone->apex || !q->zone->soa_rrset) { /* zone is configured but not loaded */ if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_SERVFAIL); /* RFC 8914 - Extended DNS Errors * 4.15. Extended DNS Error Code 14 - Not Ready */ q->edns.ede = EDE_NOT_READY; ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede, EDE_NOT_READY, "Zone is configured but not loaded"); } return; } /* * If confine-to-zone is set to yes do not return additional * information for a zone with a different apex from the query zone. */ if (nsd->options->confine_to_zone && (origzone != NULL && dname_compare(domain_dname(origzone->apex), domain_dname(q->zone->apex)) != 0)) { return; } /* now move up the closest encloser until it exists, previous * (possibly empty) closest encloser was useful to finding the zone * (for empty zones too), but now we want actual data nodes */ if (closest_encloser && !closest_encloser->is_existing) { exact = 0; while (closest_encloser != NULL && !closest_encloser->is_existing) closest_encloser = closest_encloser->parent; } /* * See RFC 4035 (DNSSEC protocol) section 3.1.4.1 Responding * to Queries for DS RRs. */ if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) { /* * Type DS query at a zone cut, use the responsible * parent zone to generate the answer if we are * authoritative for the parent zone. */ zone_type *zone = domain_find_parent_zone(nsd->db, q->zone); if (zone) { q->zone = zone; if(!q->zone->apex || !q->zone->soa_rrset) { /* zone is configured but not loaded */ if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_SERVFAIL); /* RFC 8914 - Extended DNS Errors * 4.15. Extended DNS Error Code 14 - Not Ready */ ASSIGN_EDE_CODE_AND_STRING_LITERAL( q->edns.ede, EDE_NOT_READY, "Zone is configured but not loaded"); } return; } } } /* see if the zone has expired (for secondary zones) */ if(q->zone && q->zone->opts && q->zone->opts->pattern && q->zone->opts->pattern->request_xfr != 0 && !q->zone->is_ok) { if(q->cname_count == 0) { RCODE_SET(q->packet, RCODE_SERVFAIL); /* RFC 8914 - Extended DNS Errors * 4.25. Extended DNS Error Code 24 - Invalid Data */ ASSIGN_EDE_CODE_AND_STRING_LITERAL(q->edns.ede, EDE_INVALID_DATA, "Zone has expired"); } return; } if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) { /* * Type DS query at the zone apex (and the server is * not authoritative for the parent zone). */ if (q->qclass == CLASS_ANY) { AA_CLR(q->packet); } else { AA_SET(q->packet); } answer_nodata(q, answer, closest_encloser); } else { q->delegation_domain = domain_find_ns_rrsets( closest_encloser, q->zone, &q->delegation_rrset); if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) { q->delegation_domain = NULL; /* use higher DNAME */ } if (!q->delegation_domain || !q->delegation_rrset || (exact && q->qtype == TYPE_DS && closest_encloser == q->delegation_domain)) { if (q->qclass == CLASS_ANY) { AA_CLR(q->packet); } else { AA_SET(q->packet); } answer_authoritative(nsd, q, answer, domain_number, exact, closest_match, closest_encloser, qname); } else { answer_delegation(q, answer); } } } static void answer_query(struct nsd *nsd, struct query *q) { domain_type *closest_match; domain_type *closest_encloser; int exact; uint16_t offset; answer_type answer; answer_init(&answer); exact = namedb_lookup(nsd->db, q->qname, &closest_match, &closest_encloser); answer_lookup_zone(nsd, q, &answer, 0, exact, closest_match, closest_encloser, q->qname); ZTATUP2(nsd, q->zone, opcode, q->opcode); ZTATUP2(nsd, q->zone, qtype, q->qtype); ZTATUP2(nsd, q->zone, qclass, q->qclass); offset = dname_label_offsets(q->qname)[domain_dname(closest_encloser)->label_count - 1] + QHEADERSZ; query_add_compression_domain(q, closest_encloser, offset); encode_answer(q, &answer); query_clear_compression_tables(q); } void query_prepare_response(query_type *q) { uint16_t flags; /* * Preserve the data up-to the current packet's limit. */ buffer_set_position(q->packet, buffer_limit(q->packet)); buffer_set_limit(q->packet, buffer_capacity(q->packet)); /* * Reserve space for the EDNS records if required. */ q->reserved_space = edns_reserved_space(&q->edns); q->reserved_space += tsig_reserved_space(&q->tsig); /* Update the flags. */ flags = FLAGS(q->packet); flags &= 0x0100U; /* Preserve the RD flag. */ /* CD flag must be cleared for auth answers */ flags |= 0x8000U; /* Set the QR flag. */ FLAGS_SET(q->packet, flags); } /* * Processes the query. * */ query_state_type query_process(query_type *q, nsd_type *nsd, uint32_t *now_p) { /* The query... */ nsd_rc_type rc; query_state_type query_state; uint16_t arcount; /* Sanity checks */ if (buffer_limit(q->packet) < QHEADERSZ) { /* packet too small to contain DNS header. Now packet investigation macros will work without problems. */ return QUERY_DISCARDED; } if (QR(q->packet)) { /* Not a query? Drop it on the floor. */ return QUERY_DISCARDED; } /* check opcode early on, because new opcodes may have different * specification of the meaning of the rest of the packet */ q->opcode = OPCODE(q->packet); if(q->opcode != OPCODE_QUERY && q->opcode != OPCODE_NOTIFY) { if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; if(nsd->options->drop_updates && q->opcode == OPCODE_UPDATE) return QUERY_DISCARDED; return query_error(q, NSD_RC_IMPL); } if (RCODE(q->packet) != RCODE_OK || !process_query_section(q)) { return query_formerr(q, nsd); } /* Update statistics. */ STATUP2(nsd, opcode, q->opcode); STATUP2(nsd, qtype, q->qtype); STATUP2(nsd, qclass, q->qclass); if (q->opcode != OPCODE_QUERY) { if (q->opcode == OPCODE_NOTIFY) { return answer_notify(nsd, q); } else { if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; return query_error(q, NSD_RC_IMPL); } } /* Dont bother to answer more than one question at once... */ if (QDCOUNT(q->packet) != 1) { if(QDCOUNT(q->packet) == 0 && ANCOUNT(q->packet) == 0 && NSCOUNT(q->packet) == 0 && ARCOUNT(q->packet) == 1 && buffer_limit(q->packet) >= QHEADERSZ+OPT_LEN+ OPT_RDATA) { /* add edns section to answer */ buffer_set_position(q->packet, QHEADERSZ); if (edns_parse_record(&q->edns, q->packet, q, nsd)) { if(process_edns(nsd, q) == NSD_RC_OK) { int opcode = OPCODE(q->packet); (void)query_error(q, NSD_RC_FORMAT); query_add_optional(q, nsd, now_p); FLAGS_SET(q->packet, FLAGS(q->packet) & 0x0100U); /* Preserve the RD flag. Clear the rest. */ OPCODE_SET(q->packet, opcode); QR_SET(q->packet); return QUERY_PROCESSED; } } } FLAGS_SET(q->packet, 0); return query_formerr(q, nsd); } /* Ignore settings of flags */ /* Dont allow any records in the answer or authority section... except for IXFR queries. */ if (ANCOUNT(q->packet) != 0 || (q->qtype!=TYPE_IXFR && NSCOUNT(q->packet) != 0)) { return query_formerr(q, nsd); } if(q->qtype==TYPE_IXFR && NSCOUNT(q->packet) > 0) { unsigned int i; /* skip ixfr soa information data here */ unsigned int nscount = (unsigned)NSCOUNT(q->packet); /* define a bound on the number of extraneous records allowed, * we expect 1, a SOA serial record, and no more. * perhaps RRSIGs (but not needed), otherwise we do not * understand what this means. We do not want too many * because the high iteration counts slow down. */ if(nscount > 64) return query_formerr(q, nsd); for(i=0; i< nscount; i++) if(!packet_skip_rr(q->packet, 0)) return query_formerr(q, nsd); } arcount = ARCOUNT(q->packet); /* A TSIG RR is not allowed before the EDNS OPT RR. * In RFC6891 (about EDNS) it says: * "The placement flexibility for the OPT RR does not * override the need for the TSIG or SIG(0) RRs to be * the last in the additional section whenever they are * present." * And in RFC8945 (about TSIG) it says: * "If multiple TSIG records are detected or a TSIG record is * present in any other position, the DNS message is dropped * and a response with RCODE 1 (FORMERR) MUST be returned." */ /* See if there is an OPT RR. */ if (arcount > 0) { if (edns_parse_record(&q->edns, q->packet, q, nsd)) --arcount; } /* See if there is a TSIG RR. */ if (arcount > 0 && q->tsig.status == TSIG_NOT_PRESENT) { /* see if tsig is after the edns record */ if (!tsig_parse_rr(&q->tsig, q->packet)) return query_formerr(q, nsd); if(q->tsig.status != TSIG_NOT_PRESENT) --arcount; } /* If more RRs left in Add. Section, FORMERR. */ if (arcount > 0) { return query_formerr(q, nsd); } /* Do we have any trailing garbage? */ #ifdef STRICT_MESSAGE_PARSE if (buffer_remaining(q->packet) > 0) { /* If we're strict.... */ return query_formerr(q, nsd); } #endif /* Remove trailing garbage. */ buffer_set_limit(q->packet, buffer_position(q->packet)); rc = process_tsig(q); if (rc != NSD_RC_OK) { return query_error(q, rc); } rc = process_edns(nsd, q); if (rc != NSD_RC_OK) { /* We should not return FORMERR, but BADVERS (=16). * BADVERS is created with Ext. RCODE, followed by RCODE. * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16). * Thus RCODE = NOERROR = NSD_RC_OK. */ RCODE_SET(q->packet, NSD_RC_OK); buffer_clear(q->packet); buffer_set_position(q->packet, QHEADERSZ + 4 + q->qname->name_size); QR_SET(q->packet); AD_CLR(q->packet); QDCOUNT_SET(q->packet, 1); ANCOUNT_SET(q->packet, 0); NSCOUNT_SET(q->packet, 0); ARCOUNT_SET(q->packet, 0); return QUERY_PROCESSED; } if (q->edns.cookie_status == COOKIE_UNVERIFIED) cookie_verify(q, nsd, now_p); query_prepare_response(q); if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) { if (q->qclass == CLASS_CH) { return answer_chaos(nsd, q); } else { /* RFC8914 - Extended DNS Errors * 4.22. Extended DNS Error Code 21 - Not Supported */ q->edns.ede = EDE_NOT_SUPPORTED; return query_error(q, RCODE_REFUSE); } } query_state = answer_axfr_ixfr(nsd, q); if (query_state == QUERY_PROCESSED || query_state == QUERY_IN_AXFR || query_state == QUERY_IN_IXFR) { return query_state; } if(q->qtype == TYPE_ANY && nsd->options->refuse_any && !q->tcp) { TC_SET(q->packet); return query_error(q, NSD_RC_OK); } answer_query(nsd, q); return QUERY_PROCESSED; } void query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) { struct edns_data *edns = &nsd->edns_ipv4; #if defined(INET6) if (q->client_addr.ss_family == AF_INET6) { edns = &nsd->edns_ipv6; } #endif if (RCODE(q->packet) == RCODE_FORMAT) { return; } switch (q->edns.status) { case EDNS_NOT_PRESENT: break; case EDNS_OK: if (q->edns.dnssec_ok) edns->ok[7] = 0x80; else edns->ok[7] = 0x00; buffer_write(q->packet, edns->ok, OPT_LEN); /* Add Extended DNS Error (RFC8914) * to verify that we stay in bounds */ if (q->edns.ede >= 0) q->edns.opt_reserved_space += 6 + ( q->edns.ede_text_len ? q->edns.ede_text_len : 0); if(q->edns.zoneversion && q->zone && q->zone->soa_rrset && q->zone->soa_rrset->rrs && q->zone->soa_rrset->rrs->rdata_count >= 3) q->edns.opt_reserved_space += sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t); if(q->edns.opt_reserved_space == 0 || !buffer_available( q->packet, 2+q->edns.opt_reserved_space)) { /* fill with NULLs */ buffer_write(q->packet, edns->rdata_none, OPT_RDATA); } else { /* rdata length */ buffer_write_u16(q->packet, q->edns.opt_reserved_space); /* edns options */ if(q->edns.nsid) { /* nsid opt header */ buffer_write(q->packet, edns->nsid, OPT_HDR); /* nsid payload */ buffer_write(q->packet, nsd->nsid, nsd->nsid_len); } if(q->edns.zoneversion && q->zone && q->zone->soa_rrset && q->zone->soa_rrset->rrs && q->zone->soa_rrset->rrs->rdata_count >= 3) { buffer_write_u16(q->packet, ZONEVERSION_CODE); buffer_write_u16( q->packet , sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t)); buffer_write_u8(q->packet, domain_dname(q->zone->apex)->label_count - 1); buffer_write_u8( q->packet , ZONEVERSION_SOA_SERIAL); buffer_write_u32(q->packet, read_uint32(rdata_atom_data( q->zone->soa_rrset->rrs->rdatas[2]))); } if(q->edns.cookie_status != COOKIE_NOT_PRESENT) { /* cookie opt header */ buffer_write(q->packet, edns->cookie, OPT_HDR); /* cookie payload */ cookie_create(q, nsd, now_p); buffer_write(q->packet, q->edns.cookie, 24); } /* Append Extended DNS Error (RFC8914) option if needed */ if (q->edns.ede >= 0) { /* < 0 means no EDE */ /* OPTION-CODE */ buffer_write_u16(q->packet, EDE_CODE); /* OPTION-LENGTH */ buffer_write_u16(q->packet, 2 + ( q->edns.ede_text_len ? q->edns.ede_text_len : 0)); /* INFO-CODE */ buffer_write_u16(q->packet, q->edns.ede); /* EXTRA-TEXT */ if (q->edns.ede_text_len) buffer_write(q->packet, q->edns.ede_text, q->edns.ede_text_len); } } ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); STATUP(nsd, edns); ZTATUP(nsd, q->zone, edns); break; case EDNS_ERROR: if (q->edns.dnssec_ok) edns->error[7] = 0x80; else edns->error[7] = 0x00; buffer_write(q->packet, edns->error, OPT_LEN); buffer_write(q->packet, edns->rdata_none, OPT_RDATA); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); STATUP(nsd, ednserr); ZTATUP(nsd, q->zone, ednserr); break; } if (q->tsig.status != TSIG_NOT_PRESENT) { if (q->tsig.status == TSIG_ERROR || q->tsig.error_code != TSIG_ERROR_NOERROR) { tsig_error_reply(&q->tsig); tsig_append_rr(&q->tsig, q->packet); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); } else if(q->tsig.status == TSIG_OK && q->tsig.error_code == TSIG_ERROR_NOERROR) { if(q->tsig_prepare_it) tsig_prepare(&q->tsig); if(q->tsig_update_it) tsig_update(&q->tsig, q->packet, buffer_position(q->packet)); if(q->tsig_sign_it) { tsig_sign(&q->tsig); tsig_append_rr(&q->tsig, q->packet); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); } } } } nsd-4.12.0/popen3.h0000644000175000017500000000134115002373054013351 0ustar mozziemozzie/* * popen3.h -- execute a command and connect stdin, stdout and stderr * * Copyright (c) 2019, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef POPEN3_H #define POPEN3_H #include #include /* * Execute a command and connect stdin, stdout and stderr of the process to * respectively finptr, foutptr and ferrptr if non-NULL. The process * identifier of the new process is returned on success and the pointers to * the FILE handles will have been set. On failure, -1 is returned and none * of the pointers will have been set. */ pid_t popen3(char *const *command, int *fdinptr, int *fdoutptr, int *fderrptr); #endif /* POPEN3_H */ nsd-4.12.0/popen3.c0000644000175000017500000000477215002373054013357 0ustar mozziemozzie#include "config.h" #include #include #include #include #include #include #include #include #include "popen3.h" static void close_pipe(int fds[2]) { if(fds[0] != -1) { close(fds[0]); fds[0] = -1; } if(fds[1] != -1) { close(fds[1]); fds[1] = -1; } } pid_t popen3(char *const *command, int *fdinptr, int *fdoutptr, int *fderrptr) { int err = 0; int fdin[] = { -1, -1 }; int fdout[] = { -1, -1 }; int fderr[] = { -1, -1 }; int fdsig[] = { -1, -1 }; pid_t pid; ssize_t discard; if(command == NULL || *command == NULL) { errno = EINVAL; return -1; } if(fdinptr != NULL && pipe(fdin) == -1) { goto error; } if(fdoutptr != NULL && pipe(fdout) == -1) { goto error; } if(fderrptr != NULL && pipe(fderr) == -1) { goto error; } if(pipe(fdsig) == -1 || fcntl(fdsig[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl(fdsig[1], F_SETFD, FD_CLOEXEC) == -1) { goto error; } pid = fork(); switch(pid) { case -1: /* error */ goto error; case 0: /* child */ if(fderrptr != NULL) { if(dup2(fderr[1], 2) == -1) { goto error_dup2; } close_pipe(fderr); } else { close(2); } if(fdoutptr != NULL) { if(dup2(fdout[1], 1) == -1) { goto error_dup2; } close_pipe(fdout); } else { close(1); } if(fdinptr != NULL) { if(dup2(fdin[0], 0) == -1) { goto error_dup2; } close_pipe(fdin); } else { close(0); } execvp(*command, command); error_dup2: err = errno; close(fdsig[0]); discard = write(fdsig[1], &err, sizeof(err)); (void)discard; close(fdsig[1]); exit(-1); default: /* parent */ { /* wait for signal pipe to close */ int ret; fd_set rfds; close(fdsig[1]); fdsig[1] = -1; do { FD_ZERO(&rfds); FD_SET(fdsig[0], &rfds); ret = select(fdsig[0] + 1, &rfds, NULL, NULL, NULL); } while(ret == -1 && errno == EINTR); if(ret == -1) { goto error; } if((ret = read(fdsig[0], &err, sizeof(err))) != 0) { if(ret != -1) { assert(ret == sizeof(err)); errno = err; } goto error; } close(fdsig[0]); fdsig[0] = -1; } break; } if(fdinptr != NULL) { close(fdin[0]); *fdinptr = fdin[1]; } if(fdoutptr != NULL) { close(fdout[1]); *fdoutptr = fdout[0]; } if(fderrptr != NULL) { close(fderr[1]); *fderrptr = fderr[0]; } return pid; error: err = errno; close_pipe(fdin); close_pipe(fdout); close_pipe(fderr); close_pipe(fdsig); errno = err; return -1; } nsd-4.12.0/packet.h0000644000175000017500000001526715002373054013430 0ustar mozziemozzie/* * packet.h -- low-level DNS packet encoding and decoding functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef PACKET_H #define PACKET_H #include #include "dns.h" #include "namedb.h" struct query; /* * Set of macro's to deal with the dns message header as specified * in RFC1035 in portable way. * */ /* * * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ID | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | QDCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ANCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | NSCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ARCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * */ /* The length of the header */ #define QHEADERSZ 12 /* First octet of flags */ #define RD_MASK 0x01U #define RD_SHIFT 0 #define RD(packet) (*buffer_at((packet), 2) & RD_MASK) #define RD_SET(packet) (*buffer_at((packet), 2) |= RD_MASK) #define RD_CLR(packet) (*buffer_at((packet), 2) &= ~RD_MASK) #define TC_MASK 0x02U #define TC_SHIFT 1 #define TC(packet) (*buffer_at((packet), 2) & TC_MASK) #define TC_SET(packet) (*buffer_at((packet), 2) |= TC_MASK) #define TC_CLR(packet) (*buffer_at((packet), 2) &= ~TC_MASK) #define AA_MASK 0x04U #define AA_SHIFT 2 #define AA(packet) (*buffer_at((packet), 2) & AA_MASK) #define AA_SET(packet) (*buffer_at((packet), 2) |= AA_MASK) #define AA_CLR(packet) (*buffer_at((packet), 2) &= ~AA_MASK) #define OPCODE_MASK 0x78U #define OPCODE_SHIFT 3 #define OPCODE(packet) ((*buffer_at((packet), 2) & OPCODE_MASK) >> OPCODE_SHIFT) #define OPCODE_SET(packet, opcode) \ (*buffer_at((packet), 2) = (*buffer_at((packet), 2) & ~OPCODE_MASK) | ((opcode) << OPCODE_SHIFT)) #define QR_MASK 0x80U #define QR_SHIFT 7 #define QR(packet) (*buffer_at((packet), 2) & QR_MASK) #define QR_SET(packet) (*buffer_at((packet), 2) |= QR_MASK) #define QR_CLR(packet) (*buffer_at((packet), 2) &= ~QR_MASK) /* Second octet of flags */ #define RCODE_MASK 0x0fU #define RCODE_SHIFT 0 #define RCODE(packet) (*buffer_at((packet), 3) & RCODE_MASK) #define RCODE_SET(packet, rcode) \ (*buffer_at((packet), 3) = (*buffer_at((packet), 3) & ~RCODE_MASK) | (rcode)) #define CD_MASK 0x10U #define CD_SHIFT 4 #define CD(packet) (*buffer_at((packet), 3) & CD_MASK) #define CD_SET(packet) (*buffer_at((packet), 3) |= CD_MASK) #define CD_CLR(packet) (*buffer_at((packet), 3) &= ~CD_MASK) #define AD_MASK 0x20U #define AD_SHIFT 5 #define AD(packet) (*buffer_at((packet), 3) & AD_MASK) #define AD_SET(packet) (*buffer_at((packet), 3) |= AD_MASK) #define AD_CLR(packet) (*buffer_at((packet), 3) &= ~AD_MASK) #define Z_MASK 0x40U #define Z_SHIFT 6 #define Z(packet) (*buffer_at((packet), 3) & Z_MASK) #define Z_SET(packet) (*buffer_at((packet), 3) |= Z_MASK) #define Z_CLR(packet) (*buffer_at((packet), 3) &= ~Z_MASK) #define RA_MASK 0x80U #define RA_SHIFT 7 #define RA(packet) (*buffer_at((packet), 3) & RA_MASK) #define RA_SET(packet) (*buffer_at((packet), 3) |= RA_MASK) #define RA_CLR(packet) (*buffer_at((packet), 3) &= ~RA_MASK) /* Query ID */ #define ID(packet) (buffer_read_u16_at((packet), 0)) #define ID_SET(packet, id) (buffer_write_u16_at((packet), 0, (id))) /* Flags, RCODE, and OPCODE. */ #define FLAGS(packet) (buffer_read_u16_at((packet), 2)) #define FLAGS_SET(packet, f) (buffer_write_u16_at((packet), 2, (f))) /* Counter of the question section */ #define QDCOUNT(packet) (buffer_read_u16_at((packet), 4)) #define QDCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 4, (c))) /* Counter of the answer section */ #define ANCOUNT(packet) (buffer_read_u16_at((packet), 6)) #define ANCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 6, (c))) /* Counter of the authority section */ #define NSCOUNT(packet) (buffer_read_u16_at((packet), 8)) #define NSCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 8, (c))) /* Counter of the additional section */ #define ARCOUNT(packet) (buffer_read_u16_at((packet), 10)) #define ARCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 10, (c))) /* Miscellaneous limits */ #define MAX_PACKET_SIZE 65535 /* Maximum supported size of DNS packets. */ #define QIOBUFSZ (MAX_PACKET_SIZE + MAX_RR_SIZE) #define MAXRRSPP 10240 /* Maximum number of rr's per packet */ #define MAX_COMPRESSED_DNAMES MAXRRSPP /* Maximum number of compressed domains. */ #define MAX_COMPRESSION_OFFSET 16383 /* Compression pointers are 14 bit. */ #define IPV4_MINIMAL_RESPONSE_SIZE 1232 /* Recommended minimal edns size for IPv4 */ #define IPV6_MINIMAL_RESPONSE_SIZE 1220 /* Recommended minimal edns size for IPv6 */ /* use round robin rotation */ extern int round_robin; /* use minimal responses (more minimal, with additional only for referrals) */ extern int minimal_responses; /* * Encode RR with OWNER as owner name into QUERY. Returns the number * of RRs successfully encoded. */ int packet_encode_rr(struct query *query, domain_type *owner, rr_type *rr, uint32_t ttl); /* * Encode RRSET with OWNER as the owner name into QUERY. Returns the * number of RRs successfully encoded. If TRUNCATE_RRSET the entire * RRset is truncated in case an RR (or the RRsets signature) does not * fit. */ int packet_encode_rrset(struct query *query, domain_type *owner, rrset_type *rrset, int truncate_rrset, size_t minimal_respsize, int* done); /* * Skip the RR at the current position in PACKET. */ int packet_skip_rr(buffer_type *packet, int question_section); /* * Skip the dname at the current position in PACKET. */ int packet_skip_dname(buffer_type *packet); /* * Read the RR at the current position in PACKET. */ rr_type *packet_read_rr(region_type *region, domain_table_type *owners, buffer_type *packet, int question_section); /* * read a query entry from network packet given in buffer. * does not follow compression ptrs, checks for errors (returns 0). * Dest must be at least MAXDOMAINLEN long. */ int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass); /* read notify SOA serial from packet. buffer position is unmodified on return. * returns false on no-serial found or parse failure. */ int packet_find_notify_serial(buffer_type *packet, uint32_t* serial); #endif /* PACKET_H */ nsd-4.12.0/packet.c0000644000175000017500000002366415002373054013423 0ustar mozziemozzie/* * packet.c -- low-level DNS packet encoding and decoding functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include "packet.h" #include "query.h" #include "rdata.h" int round_robin = 0; int minimal_responses = 0; static void encode_dname(query_type *q, domain_type *domain) { while (domain->parent && query_get_dname_offset(q, domain) == 0) { query_put_dname_offset(q, domain, buffer_position(q->packet)); DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", domain_to_string(domain), (unsigned long) domain->number, query_get_dname_offset(q, domain))); buffer_write(q->packet, dname_name(domain_dname(domain)), label_length(dname_name(domain_dname(domain))) + 1U); domain = domain->parent; } if (domain->parent) { DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", domain_to_string(domain), (unsigned long) domain->number, query_get_dname_offset(q, domain))); assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); buffer_write_u16(q->packet, 0xc000 | query_get_dname_offset(q, domain)); } else { buffer_write_u8(q->packet, 0); } } int packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr, uint32_t ttl) { size_t truncation_mark; uint16_t rdlength = 0; size_t rdlength_pos; uint16_t j; assert(q); assert(owner); assert(rr); /* * If the record does not in fit in the packet the packet size * will be restored to the mark. */ truncation_mark = buffer_position(q->packet); encode_dname(q, owner); buffer_write_u16(q->packet, rr->type); buffer_write_u16(q->packet, rr->klass); buffer_write_u32(q->packet, ttl); /* Reserve space for rdlength. */ rdlength_pos = buffer_position(q->packet); buffer_skip(q->packet, sizeof(rdlength)); for (j = 0; j < rr->rdata_count; ++j) { switch (rdata_atom_wireformat_type(rr->type, j)) { case RDATA_WF_COMPRESSED_DNAME: encode_dname(q, rdata_atom_domain(rr->rdatas[j])); break; case RDATA_WF_UNCOMPRESSED_DNAME: { const dname_type *dname = domain_dname( rdata_atom_domain(rr->rdatas[j])); buffer_write(q->packet, dname_name(dname), dname->name_size); break; } default: buffer_write(q->packet, rdata_atom_data(rr->rdatas[j]), rdata_atom_size(rr->rdatas[j])); break; } } if (!query_overflow(q)) { rdlength = (buffer_position(q->packet) - rdlength_pos - sizeof(rdlength)); buffer_write_u16_at(q->packet, rdlength_pos, rdlength); return 1; } else { buffer_set_position(q->packet, truncation_mark); query_clear_dname_offsets(q, truncation_mark); assert(!query_overflow(q)); return 0; } } int packet_encode_rrset(query_type *query, domain_type *owner, rrset_type *rrset, int section, #ifdef MINIMAL_RESPONSES size_t minimal_respsize, int* done) #else size_t ATTR_UNUSED(minimal_respsize), int* ATTR_UNUSED(done)) #endif { uint16_t i; size_t truncation_mark; uint16_t added = 0; int all_added = 1; #ifdef MINIMAL_RESPONSES int minimize_response = (section >= OPTIONAL_AUTHORITY_SECTION); int truncate_rrset = (section == ANSWER_SECTION || section == AUTHORITY_SECTION); #else int truncate_rrset = (section == ANSWER_SECTION || section == AUTHORITY_SECTION || section == OPTIONAL_AUTHORITY_SECTION); #endif static int round_robin_off = 0; int do_robin = (round_robin && section == ANSWER_SECTION && query->qtype != TYPE_AXFR && query->qtype != TYPE_IXFR); uint16_t start; rrset_type *rrsig; assert(rrset->rr_count > 0); truncation_mark = buffer_position(query->packet); if(do_robin && rrset->rr_count) start = (uint16_t)(round_robin_off++ % rrset->rr_count); else start = 0; for (i = start; i < rrset->rr_count; ++i) { if (packet_encode_rr(query, owner, &rrset->rrs[i], rrset->rrs[i].ttl)) { ++added; } else { all_added = 0; start = 0; break; } } for (i = 0; i < start; ++i) { if (packet_encode_rr(query, owner, &rrset->rrs[i], rrset->rrs[i].ttl)) { ++added; } else { all_added = 0; break; } } if (all_added && query->edns.dnssec_ok && zone_is_secure(rrset->zone) && rrset_rrtype(rrset) != TYPE_RRSIG && (rrsig = domain_find_rrset(owner, rrset->zone, TYPE_RRSIG))) { for (i = 0; i < rrsig->rr_count; ++i) { if (rr_rrsig_type_covered(&rrsig->rrs[i]) == rrset_rrtype(rrset)) { if (packet_encode_rr(query, owner, &rrsig->rrs[i], rrset_rrtype(rrset)==TYPE_SOA?rrset->rrs[0].ttl:rrsig->rrs[i].ttl)) { ++added; } else { all_added = 0; break; } } } } #ifdef MINIMAL_RESPONSES if ((!all_added || buffer_position(query->packet) > minimal_respsize) && !query->tcp && minimize_response) { /* Truncate entire RRset. */ buffer_set_position(query->packet, truncation_mark); query_clear_dname_offsets(query, truncation_mark); added = 0; *done = 1; } #endif if (!all_added && truncate_rrset) { /* Truncate entire RRset and set truncate flag. */ buffer_set_position(query->packet, truncation_mark); query_clear_dname_offsets(query, truncation_mark); TC_SET(query->packet); added = 0; } return added; } int packet_skip_dname(buffer_type *packet) { while (1) { uint8_t label_size; if (!buffer_available(packet, 1)) return 0; label_size = buffer_read_u8(packet); if (label_size == 0) { return 1; } else if ((label_size & 0xc0) != 0) { if (!buffer_available(packet, 1)) return 0; buffer_skip(packet, 1); return 1; } else if (!buffer_available(packet, label_size)) { return 0; } else { buffer_skip(packet, label_size); } } } int packet_skip_rr(buffer_type *packet, int question_section) { if (!packet_skip_dname(packet)) return 0; if (question_section) { if (!buffer_available(packet, 4)) return 0; buffer_skip(packet, 4); } else { uint16_t rdata_size; if (!buffer_available(packet, 10)) return 0; buffer_skip(packet, 8); rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) return 0; buffer_skip(packet, rdata_size); } return 1; } rr_type * packet_read_rr(region_type *region, domain_table_type *owners, buffer_type *packet, int question_section) { const dname_type *owner; uint16_t rdlength; ssize_t rdata_count; rdata_atom_type *rdatas; rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type)); owner = dname_make_from_packet(region, packet, 1, 1); if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) { return NULL; } result->owner = domain_table_insert(owners, owner); result->type = buffer_read_u16(packet); result->klass = buffer_read_u16(packet); if (question_section) { result->ttl = 0; result->rdata_count = 0; result->rdatas = NULL; return result; } else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) { return NULL; } result->ttl = buffer_read_u32(packet); rdlength = buffer_read_u16(packet); if (!buffer_available(packet, rdlength)) { return NULL; } rdata_count = rdata_wireformat_to_rdata_atoms( region, owners, result->type, rdlength, packet, &rdatas); if (rdata_count == -1) { return NULL; } result->rdata_count = rdata_count; result->rdatas = rdatas; return result; } int packet_read_query_section(buffer_type *packet, uint8_t* dst, uint16_t* qtype, uint16_t* qclass) { uint8_t *query_name = buffer_current(packet); uint8_t *src = query_name; size_t len; while (*src) { /* * If we are out of buffer limits or we have a pointer * in question dname or the domain name is longer than * MAXDOMAINLEN ... */ if ((*src & 0xc0) || (src + *src + 2 > buffer_end(packet)) || (src + *src + 2 > query_name + MAXDOMAINLEN)) { return 0; } memcpy(dst, src, *src + 1); dst += *src + 1; src += *src + 1; } *dst++ = *src++; /* Make sure name is not too long or we have stripped packet... */ len = src - query_name; if (len > MAXDOMAINLEN || (src + 2*sizeof(uint16_t) > buffer_end(packet))) { return 0; } buffer_set_position(packet, src - buffer_begin(packet)); *qtype = buffer_read_u16(packet); *qclass = buffer_read_u16(packet); return 1; } int packet_find_notify_serial(buffer_type *packet, uint32_t* serial) { size_t saved_position = buffer_position(packet); /* count of further RRs after question section */ size_t rrcount = (size_t)ANCOUNT(packet) + (size_t)NSCOUNT(packet) + (size_t)ARCOUNT(packet); size_t qcount = (size_t)QDCOUNT(packet); size_t i; buffer_set_position(packet, QHEADERSZ); if(qcount > 64 || rrcount > 65530) { /* query count 0 or 1 only, rr number limited by 64k packet, * and should not be impossibly high, parse error */ buffer_set_position(packet, saved_position); return 0; } /* skip all question RRs */ for (i = 0; i < qcount; ++i) { if (!packet_skip_rr(packet, 1)) { buffer_set_position(packet, saved_position); return 0; } } /* Find the SOA RR */ for(i = 0; i < rrcount; i++) { uint16_t rdata_size; if (!packet_skip_dname(packet)) break; /* check length available for type,class,ttl,rdatalen */ if (!buffer_available(packet, 10)) break; /* check type, class */ if(buffer_read_u16(packet) == TYPE_SOA) { if(buffer_read_u16(packet) != CLASS_IN) break; buffer_skip(packet, 4); /* skip ttl */ rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) break; /* skip two dnames, then serial */ if (!packet_skip_dname(packet) || !packet_skip_dname(packet)) break; if (!buffer_available(packet, 4)) break; *serial = buffer_read_u32(packet); buffer_set_position(packet, saved_position); return 1; } /* continue to next RR */ buffer_skip(packet, 6); rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) break; buffer_skip(packet, rdata_size); } /* failed to find SOA */ buffer_set_position(packet, saved_position); return 0; } nsd-4.12.0/options.h0000644000175000017500000005320615002373054013647 0ustar mozziemozzie/* * options.h -- nsd.conf options definitions and prototypes * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef OPTIONS_H #define OPTIONS_H #include #ifdef HAVE_SSL #include #endif #include "region-allocator.h" #include "rbtree.h" struct query; struct dname; struct tsig_key; struct buffer; struct nsd; struct proxy_protocol_port_list; typedef struct nsd_options nsd_options_type; typedef struct pattern_options pattern_options_type; typedef struct zone_options zone_options_type; typedef struct range_option range_option_type; typedef struct ip_address_option ip_address_option_type; typedef struct cpu_option cpu_option_type; typedef struct cpu_map_option cpu_map_option_type; typedef struct acl_options acl_options_type; typedef struct key_options key_options_type; typedef struct tls_auth_options tls_auth_options_type; typedef struct config_parser_state config_parser_state_type; #define VERIFY_ZONE_INHERIT (2) #define VERIFIER_FEED_ZONE_INHERIT (2) #define VERIFIER_TIMEOUT_INHERIT (-1) #define CATALOG_ROLE_INHERIT (0) #define CATALOG_ROLE_CONSUMER (1) #define CATALOG_ROLE_PRODUCER (2) /* * Options global for nsd. */ struct nsd_options { /* config file name */ char* configfile; /* options for zones, by apex, contains zone_options */ rbtree_type* zone_options; /* patterns, by name, contains pattern_options */ rbtree_type* patterns; /* free space in zonelist file, contains zonelist_bucket */ rbtree_type* zonefree; /* number of free space lines in zonelist file */ size_t zonefree_number; /* zonelist file if open */ FILE* zonelist; /* last offset in file (or 0 if none) */ off_t zonelist_off; /* tree of zonestat names and their id values, entries are struct * zonestatname with malloced key=stringname. The number of items * is the max statnameid, no items are freed from this. * kept correct in the xfrd process, and on startup. */ rbtree_type* zonestatnames; /* rbtree of keys defined, by name */ rbtree_type* keys; /* rbtree of tls_auth defined, by name */ rbtree_type* tls_auths; /* list of ip addresses to bind to (or NULL for all) */ struct ip_address_option* ip_addresses; int ip_transparent; int ip_freebind; int send_buffer_size; int receive_buffer_size; int debug_mode; int verbosity; int hide_version; int hide_identity; int drop_updates; int do_ip4; int do_ip6; const char* identity; const char* version; const char* logfile; int log_only_syslog; int server_count; struct cpu_option* cpu_affinity; struct cpu_map_option* service_cpu_affinity; int tcp_count; int tcp_reject_overflow; int confine_to_zone; int tcp_query_count; int tcp_timeout; int tcp_mss; int outgoing_tcp_mss; size_t ipv4_edns_size; size_t ipv6_edns_size; const char* pidfile; const char* port; int statistics; const char* chroot; const char* username; const char* zonesdir; const char* xfrdfile; const char* xfrdir; const char* zonelistfile; const char* nsid; int xfrd_reload_timeout; int reload_config; int zonefiles_check; int zonefiles_write; int log_time_ascii; int log_time_iso; int round_robin; int minimal_responses; int refuse_any; int reuseport; /* max number of xfrd tcp sockets */ int xfrd_tcp_max; /* max number of simultaneous requests on xfrd tcp socket */ int xfrd_tcp_pipeline; /* private key file for TLS */ char* tls_service_key; /* ocsp stapling file for TLS */ char* tls_service_ocsp; /* certificate file for TLS */ char* tls_service_pem; /* TLS dedicated port */ const char* tls_port; /* TLS-AUTH dedicated port */ const char* tls_auth_port; /* TLS certificate bundle */ const char* tls_cert_bundle; /* Answer XFR only from tls_auth_port and after authentication */ int tls_auth_xfr_only; /* proxy protocol port list */ struct proxy_protocol_port_list* proxy_protocol_port; /** remote control section. enable toggle. */ int control_enable; /** the interfaces the remote control should listen on */ struct ip_address_option* control_interface; /** port number for the control port */ int control_port; /** private key file for server */ char* server_key_file; /** certificate file for server */ char* server_cert_file; /** private key file for nsd-control */ char* control_key_file; /** certificate file for nsd-control */ char* control_cert_file; #ifdef USE_METRICS /** metrics section. enable toggle. */ int metrics_enable; /** the interfaces the metrics endpoint should listen on */ struct ip_address_option* metrics_interface; /** port number for the metrics endpoint */ int metrics_port; /** HTTP path for the metrics endpoint */ char* metrics_path; #endif /* USE_METRICS */ #ifdef RATELIMIT /** number of buckets in rrl hashtable */ size_t rrl_size; /** max qps for queries, 0 is nolimit */ size_t rrl_ratelimit; /** ratio of slipped responses, 0 is noslip */ size_t rrl_slip; /** ip prefix length */ size_t rrl_ipv4_prefix_length; size_t rrl_ipv6_prefix_length; /** max qps for whitelisted queries, 0 is nolimit */ size_t rrl_whitelist_ratelimit; #endif /** if dnstap is enabled */ int dnstap_enable; /** dnstap socket path */ char* dnstap_socket_path; /** dnstap IP, if "", it uses socket path. */ char* dnstap_ip; /** dnstap TLS enable */ int dnstap_tls; /** dnstap tls server authentication name */ char* dnstap_tls_server_name; /** dnstap server cert bundle */ char* dnstap_tls_cert_bundle; /** dnstap client key for client authentication */ char* dnstap_tls_client_key_file; /** dnstap client cert for client authentication */ char* dnstap_tls_client_cert_file; /** true to send "identity" via dnstap */ int dnstap_send_identity; /** true to send "version" via dnstap */ int dnstap_send_version; /** dnstap "identity", hostname is used if "". */ char* dnstap_identity; /** dnstap "version", package version is used if "". */ char* dnstap_version; /** true to log dnstap AUTH_QUERY message events */ int dnstap_log_auth_query_messages; /** true to log dnstap AUTH_RESPONSE message events */ int dnstap_log_auth_response_messages; /** do answer with server cookie when request contained cookie option */ int answer_cookie; /** cookie secret */ char *cookie_secret; /** cookie staging secret */ char *cookie_staging_secret; /** path to cookie secret store */ char *cookie_secret_file; /** set when the cookie_secret_file whas not explicitely configured */ uint8_t cookie_secret_file_is_default; /** enable verify */ int verify_enable; /** list of ip addresses used to serve zones for verification */ struct ip_address_option* verify_ip_addresses; /** default port 5347 */ char *verify_port; /** verify zones by default */ int verify_zones; /** default command to verify zones with */ char **verifier; /** maximum number of verifiers that may run simultaneously */ int verifier_count; /** whether or not to feed the zone to the verifier over stdin */ uint8_t verifier_feed_zone; /** maximum number of seconds that a verifier may take */ uint32_t verifier_timeout; region_type* region; }; struct range_option { struct range_option* next; int first; int last; }; struct ip_address_option { struct ip_address_option* next; char* address; struct range_option* servers; int dev; int fib; }; struct cpu_option { struct cpu_option* next; int cpu; }; struct cpu_map_option { struct cpu_map_option* next; int service; int cpu; }; /* * Defines for min_expire_time_expr value */ #define EXPIRE_TIME_HAS_VALUE 0 #define EXPIRE_TIME_IS_DEFAULT 1 #define REFRESHPLUSRETRYPLUS1 2 #define REFRESHPLUSRETRYPLUS1_STR "refresh+retry+1" #define expire_time_is_default(x) (!( (x) == REFRESHPLUSRETRYPLUS1 \ || (x) == EXPIRE_TIME_HAS_VALUE )) /* * Pattern of zone options, used to contain options for zone(s). */ struct pattern_options { rbnode_type node; const char* pname; /* name of the pattern, key of rbtree */ const char* zonefile; struct acl_options* allow_notify; struct acl_options* request_xfr; struct acl_options* notify; struct acl_options* provide_xfr; struct acl_options* allow_query; struct acl_options* outgoing_interface; const char* zonestats; #ifdef RATELIMIT uint16_t rrl_whitelist; /* bitmap with rrl types */ #endif uint8_t allow_axfr_fallback; uint8_t allow_axfr_fallback_is_default; uint8_t notify_retry; uint8_t notify_retry_is_default; uint8_t implicit; /* pattern is implicit, part_of_config zone used */ uint8_t xfrd_flags; uint32_t max_refresh_time; uint8_t max_refresh_time_is_default; uint32_t min_refresh_time; uint8_t min_refresh_time_is_default; uint32_t max_retry_time; uint8_t max_retry_time_is_default; uint32_t min_retry_time; uint8_t min_retry_time_is_default; uint32_t min_expire_time; /* min_expir_time_expr is either a known value (REFRESHPLUSRETRYPLUS1 * or EXPIRE_EXPR_HAS_VALUE) or else min_expire_time is the default. * This can be tested with expire_time_is_default(x) define. */ uint8_t min_expire_time_expr; uint64_t size_limit_xfr; uint8_t multi_primary_check; uint8_t store_ixfr; uint8_t store_ixfr_is_default; uint64_t ixfr_size; uint8_t ixfr_size_is_default; uint32_t ixfr_number; uint8_t ixfr_number_is_default; uint8_t create_ixfr; uint8_t create_ixfr_is_default; uint8_t verify_zone; uint8_t verify_zone_is_default; char **verifier; uint8_t verifier_feed_zone; uint8_t verifier_feed_zone_is_default; int32_t verifier_timeout; uint8_t verifier_timeout_is_default; uint8_t catalog_role; uint8_t catalog_role_is_default; const char* catalog_member_pattern; const char* catalog_producer_zone; } ATTR_PACKED; #define PATTERN_IMPLICIT_MARKER "_implicit_" /* * Options for a zone */ struct zone_options { /* key is dname of apex */ rbnode_type node; /* is apex of the zone */ const char* name; /* if not part of config, the offset and linesize of zonelist entry */ off_t off; int linesize; /* pattern for the zone options, if zone is part_of_config, this is * a anonymous pattern created in-place */ struct pattern_options* pattern; /* zone is fixed into the main config, not in zonelist, cannot delete */ unsigned part_of_config : 1; unsigned is_catalog_member_zone: 1; } ATTR_PACKED; /* * Options for catalog member zones * assert(options->is_catalog_member_zone == 1) * when options->pattern->catalog_producer_zone is set, this is a * producer member zone, otherwise a consumer member zone. * A catalog member zone is either a member zone of a catalog producer zone * or a catalog consumer zone. They are mutually exclusive. */ struct catalog_member_zone { struct zone_options options; const struct dname* member_id; /* node in the associated catalog consumer or producer zone */ rbnode_type node; } ATTR_PACKED; typedef void (*new_member_id_type)(struct catalog_member_zone* zone); union acl_addr_storage { #ifdef INET6 struct in_addr addr; struct in6_addr addr6; #else struct in_addr addr; #endif }; /* * Access control list element */ struct acl_options { struct acl_options* next; /* options */ time_t ixfr_disabled; int bad_xfr_count; uint8_t use_axfr_only; uint8_t allow_udp; /* ip address range */ const char* ip_address_spec; uint8_t is_ipv6; unsigned int port; /* is 0(no port) or suffix @port value */ union acl_addr_storage addr; union acl_addr_storage range_mask; enum { acl_range_single = 0, /* single address */ acl_range_mask = 1, /* 10.20.30.40&255.255.255.0 */ acl_range_subnet = 2, /* 10.20.30.40/28 */ acl_range_minmax = 3 /* 10.20.30.40-10.20.30.60 (mask=max) */ } rangetype; /* key */ uint8_t nokey; uint8_t blocked; const char* key_name; struct key_options* key_options; /* tls_auth for XoT */ const char* tls_auth_name; struct tls_auth_options* tls_auth_options; } ATTR_PACKED; /* * Key definition */ struct key_options { rbnode_type node; /* key of tree is name */ char* name; char* algorithm; char* secret; struct tsig_key* tsig_key; } ATTR_PACKED; /* * TLS Auth definition for XoT */ struct tls_auth_options { rbnode_type node; /* key of tree is name */ char* name; char* auth_domain_name; char* client_cert; char* client_key; char* client_key_pw; }; /* proxy protocol port option list */ struct proxy_protocol_port_list { struct proxy_protocol_port_list* next; int port; }; /** zone list free space */ struct zonelist_free { struct zonelist_free* next; off_t off; }; /** zonelist free bucket for a particular line length */ struct zonelist_bucket { rbnode_type node; /* key is ptr to linesize */ int linesize; struct zonelist_free* list; }; /* default zonefile write interval if database is "", in seconds */ #define ZONEFILES_WRITE_INTERVAL 3600 struct zonestatname { rbnode_type node; /* key is malloced string with cooked zonestat name */ unsigned id; /* index in nsd.zonestat array */ }; /* * Used during options parsing */ struct config_parser_state { char* filename; const char* chroot; int line; int errors; struct nsd_options* opt; struct pattern_options *pattern; struct zone_options *zone; struct key_options *key; struct tls_auth_options *tls_auth; struct ip_address_option *ip; void (*err)(void*,const char*); void* err_arg; }; extern config_parser_state_type* cfg_parser; /* region will be put in nsd_options struct. Returns empty options struct. */ struct nsd_options* nsd_options_create(region_type* region); /* the number of zones that are configured */ static inline size_t nsd_options_num_zones(struct nsd_options* opt) { return opt->zone_options->count; } /* insert a zone into the main options tree, returns 0 on error */ int nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone); /* insert a pattern into the main options tree, returns 0 on error */ int nsd_options_insert_pattern(struct nsd_options* opt, struct pattern_options* pat); /* parses options file. Returns false on failure. callback, if nonNULL, * gets called with error strings, default prints. */ int parse_options_file(struct nsd_options* opt, const char* file, void (*err)(void*,const char*), void* err_arg, struct nsd_options* old_opts); struct zone_options* zone_options_create(region_type* region); void zone_options_delete(struct nsd_options* opt, struct zone_options* zone); struct catalog_member_zone* catalog_member_zone_create(region_type* region); static inline struct catalog_member_zone* as_catalog_member_zone(struct zone_options* zopt) { return zopt && zopt->is_catalog_member_zone ? (struct catalog_member_zone*)zopt : NULL; } /* find a zone by apex domain name, or NULL if not found. */ struct zone_options* zone_options_find(struct nsd_options* opt, const struct dname* apex); struct pattern_options* pattern_options_create(region_type* region); struct pattern_options* pattern_options_find(struct nsd_options* opt, const char* name); int pattern_options_equal(struct pattern_options* p, struct pattern_options* q); void pattern_options_remove(struct nsd_options* opt, const char* name); void pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p); void pattern_options_marshal(struct buffer* buffer, struct pattern_options* p); struct pattern_options* pattern_options_unmarshal(region_type* r, struct buffer* b); struct key_options* key_options_create(region_type* region); void key_options_insert(struct nsd_options* opt, struct key_options* key); struct key_options* key_options_find(struct nsd_options* opt, const char* name); void key_options_remove(struct nsd_options* opt, const char* name); int key_options_equal(struct key_options* p, struct key_options* q); void key_options_add_modify(struct nsd_options* opt, struct key_options* key); void key_options_setup(region_type* region, struct key_options* key); void key_options_desetup(region_type* region, struct key_options* key); /* TLS auth */ struct tls_auth_options* tls_auth_options_create(region_type* region); void tls_auth_options_insert(struct nsd_options* opt, struct tls_auth_options* auth); struct tls_auth_options* tls_auth_options_find(struct nsd_options* opt, const char* name); /* read in zone list file. Returns false on failure */ int parse_zone_list_file(struct nsd_options* opt); /* create (potential) catalog producer member entry and add to the zonelist */ struct zone_options* zone_list_add_or_cat(struct nsd_options* opt, const char* zname, const char* pname, new_member_id_type new_member_id); /* create zone entry and add to the zonelist file */ static inline struct zone_options* zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) { return zone_list_add_or_cat(opt, zname, pname, NULL); } /* create zonelist entry, do not insert in file (called by _add) */ struct zone_options* zone_list_zone_insert(struct nsd_options* opt, const char* nm, const char* patnm); void zone_list_del(struct nsd_options* opt, struct zone_options* zone); void zone_list_compact(struct nsd_options* opt); void zone_list_close(struct nsd_options* opt); /* create zonestat name tree , for initially created zones */ void options_zonestatnames_create(struct nsd_options* opt); /* Get zonestat id for zone options, add new entry if necessary. * instantiates the pattern's zonestat string */ unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt); /* create string, same options as zonefile but no chroot changes */ const char* config_cook_string(struct zone_options* zone, const char* input); /** check if config for remote control turns on IP-address interface * with certificates or a named pipe without certificates. */ int options_remote_is_address(struct nsd_options* cfg); #if defined(HAVE_SSL) /* tsig must be inited, adds all keys in options to tsig. */ void key_options_tsig_add(struct nsd_options* opt); #endif /* check acl list, acl number that matches if passed(0..), * or failure (-1) if dropped */ /* the reason why (the acl) is returned too (or NULL) */ int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason); int acl_addr_matches_host(struct acl_options* acl, struct acl_options* host); int acl_addr_matches(struct acl_options* acl, struct query* q); int acl_addr_matches_proxy(struct acl_options* acl, struct query* q); #ifdef HAVE_SSL int acl_tls_hostname_matches(SSL* ssl, const char* acl_cert_cn); #endif int acl_key_matches(struct acl_options* acl, struct query* q); int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz); int acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz); int acl_addr_match_range_v4(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz); /* check acl list for blocks on address, return 0 if none, -1 if blocked. */ int acl_check_incoming_block_proxy(struct acl_options* acl, struct query* q, struct acl_options** reason); /* returns true if acls are both from the same host */ int acl_same_host(struct acl_options* a, struct acl_options* b); /* find acl by number in the list */ struct acl_options* acl_find_num(struct acl_options* acl, int num); /* see if two acl lists are the same (same elements in same order, or empty) */ int acl_list_equal(struct acl_options* p, struct acl_options* q); /* see if two acl are the same */ int acl_equal(struct acl_options* p, struct acl_options* q); /* see if a zone is a slave or a master zone */ int zone_is_slave(struct zone_options* opt); /* see if a zone is a catalog consumer */ static inline int zone_is_catalog_consumer(struct zone_options* opt) { return opt && opt->pattern && opt->pattern->catalog_role == CATALOG_ROLE_CONSUMER; } static inline int zone_is_catalog_producer(struct zone_options* opt) { return opt && opt->pattern && opt->pattern->catalog_role == CATALOG_ROLE_PRODUCER; } static inline int zone_is_catalog_member(struct zone_options* opt) { return opt && opt->is_catalog_member_zone; } static inline const char* zone_is_catalog_producer_member(struct zone_options* opt) { return opt && opt->pattern && opt->pattern->catalog_producer_zone ? opt->pattern->catalog_producer_zone : NULL; } static inline int zone_is_catalog_consumer_member(struct zone_options* opt) { return zone_is_catalog_member(opt) && !zone_is_catalog_producer_member(opt); } /* create zonefile name, returns static pointer (perhaps to options data) */ const char* config_make_zonefile(struct zone_options* zone, struct nsd* nsd); #define ZONEC_PCT_TIME 5 /* seconds, then it starts to print pcts */ #define ZONEC_PCT_COUNT 100000 /* elements before pct check is done */ /* parsing helpers */ void c_error(const char* msg, ...) ATTR_FORMAT(printf, 1,2); int c_wrap(void); struct acl_options* parse_acl_info(region_type* region, char* ip, const char* key); /* true if ipv6 address, false if ipv4 */ int parse_acl_is_ipv6(const char* p); /* returns range type. mask is the 2nd part of the range */ int parse_acl_range_type(char* ip, char** mask); /* parses subnet mask, fills 0 mask as well */ void parse_acl_range_subnet(char* p, void* addr, int maxbits); /* clean up options */ void nsd_options_destroy(struct nsd_options* opt); /* replace occurrences of one with two in buf, pass length of buffer */ void replace_str(char* buf, size_t len, const char* one, const char* two); /* apply pattern to the existing pattern in the parser */ void config_apply_pattern(struct pattern_options *dest, const char* name); /* if the file is a directory, print a warning, because flex just exit()s * when a fileread fails because it is a directory, helps the user figure * out what just happened */ void warn_if_directory(const char* filetype, FILE* f, const char* fname); /* resolve interface names in the options "ip-address:" (or "interface:") * and "control-interface:" into the ip-addresses associated with those * names. */ void resolve_interface_names(struct nsd_options* options); /* See if the sockaddr port number is listed in the proxy protocol ports. */ int sockaddr_uses_proxy_protocol_port(struct nsd_options* options, struct sockaddr* addr); #endif /* OPTIONS_H */ nsd-4.12.0/options.c0000644000175000017500000025774515002373054013660 0ustar mozziemozzie/* * options.c -- options functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #ifdef HAVE_IFADDRS_H #include #endif #ifdef HAVE_SSL #include #include #endif #ifdef HAVE_STRINGS_H #include #endif #include "options.h" #include "query.h" #include "tsig.h" #include "ixfr.h" #include "difffile.h" #include "rrl.h" #include "bitset.h" #include "xfrd.h" #include "configparser.h" config_parser_state_type* cfg_parser = 0; extern FILE* c_in, *c_out; int c_parse(void); int c_lex(void); int c_wrap(void); int c_lex_destroy(void); extern char* c_text; static int rbtree_strcmp(const void* p1, const void* p2) { if(p1 == NULL && p2 == NULL) return 0; if(p1 == NULL) return -1; if(p2 == NULL) return 1; return strcmp((const char*)p1, (const char*)p2); } struct nsd_options* nsd_options_create(region_type* region) { struct nsd_options* opt; opt = (struct nsd_options*)region_alloc(region, sizeof( struct nsd_options)); opt->region = region; opt->zone_options = rbtree_create(region, (int (*)(const void *, const void *)) dname_compare); opt->configfile = NULL; opt->zonestatnames = rbtree_create(opt->region, rbtree_strcmp); opt->patterns = rbtree_create(region, rbtree_strcmp); opt->keys = rbtree_create(region, rbtree_strcmp); opt->tls_auths = rbtree_create(region, rbtree_strcmp); opt->ip_addresses = NULL; opt->ip_transparent = 0; opt->ip_freebind = 0; opt->send_buffer_size = 0; opt->receive_buffer_size = 0; opt->debug_mode = 0; opt->verbosity = 0; opt->hide_version = 0; opt->hide_identity = 0; opt->drop_updates = 0; opt->do_ip4 = 1; opt->do_ip6 = 1; opt->identity = 0; opt->version = 0; opt->nsid = 0; opt->logfile = 0; opt->log_only_syslog = 0; opt->log_time_ascii = 1; opt->log_time_iso = 0; opt->round_robin = 0; /* also packet.h::round_robin */ opt->minimal_responses = 0; /* also packet.h::minimal_responses */ opt->confine_to_zone = 0; opt->refuse_any = 0; opt->server_count = 1; opt->cpu_affinity = NULL; opt->service_cpu_affinity = NULL; opt->tcp_count = 100; opt->tcp_reject_overflow = 0; opt->tcp_query_count = 0; opt->tcp_timeout = TCP_TIMEOUT; opt->tcp_mss = 0; opt->outgoing_tcp_mss = 0; opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN; opt->ipv6_edns_size = EDNS_MAX_MESSAGE_LEN; opt->pidfile = PIDFILE; opt->port = UDP_PORT; /* deprecated? opt->port = TCP_PORT; */ opt->reuseport = 0; opt->xfrd_tcp_max = 128; opt->xfrd_tcp_pipeline = 128; opt->statistics = 0; opt->chroot = 0; opt->username = USER; opt->zonesdir = ZONESDIR; opt->xfrdfile = XFRDFILE; opt->xfrdir = XFRDIR; opt->zonelistfile = ZONELISTFILE; #ifdef RATELIMIT opt->rrl_size = RRL_BUCKETS; opt->rrl_slip = RRL_SLIP; opt->rrl_ipv4_prefix_length = RRL_IPV4_PREFIX_LENGTH; opt->rrl_ipv6_prefix_length = RRL_IPV6_PREFIX_LENGTH; # ifdef RATELIMIT_DEFAULT_OFF opt->rrl_ratelimit = 0; opt->rrl_whitelist_ratelimit = 0; # else opt->rrl_ratelimit = RRL_LIMIT/2; opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT/2; # endif #endif #ifdef USE_DNSTAP opt->dnstap_enable = 0; opt->dnstap_socket_path = DNSTAP_SOCKET_PATH; opt->dnstap_ip = ""; opt->dnstap_tls = 1; opt->dnstap_tls_server_name = NULL; opt->dnstap_tls_cert_bundle = NULL; opt->dnstap_tls_client_key_file = NULL; opt->dnstap_tls_client_cert_file = NULL; opt->dnstap_send_identity = 0; opt->dnstap_send_version = 0; opt->dnstap_identity = NULL; opt->dnstap_version = NULL; opt->dnstap_log_auth_query_messages = 0; opt->dnstap_log_auth_response_messages = 0; #endif opt->reload_config = 0; opt->zonefiles_check = 1; opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; opt->xfrd_reload_timeout = 1; opt->tls_service_key = NULL; opt->tls_service_ocsp = NULL; opt->tls_service_pem = NULL; opt->tls_port = TLS_PORT; opt->tls_auth_port = NULL; opt->tls_cert_bundle = NULL; opt->tls_auth_xfr_only = 0; opt->proxy_protocol_port = NULL; opt->answer_cookie = 0; opt->cookie_secret = NULL; opt->cookie_staging_secret = NULL; opt->cookie_secret_file = NULL; opt->cookie_secret_file_is_default = 1; opt->control_enable = 0; opt->control_interface = NULL; opt->control_port = NSD_CONTROL_PORT; opt->server_key_file = CONFIGDIR"/nsd_server.key"; opt->server_cert_file = CONFIGDIR"/nsd_server.pem"; opt->control_key_file = CONFIGDIR"/nsd_control.key"; opt->control_cert_file = CONFIGDIR"/nsd_control.pem"; #ifdef USE_METRICS opt->metrics_enable = 0; opt->metrics_interface = NULL; opt->metrics_port = NSD_METRICS_PORT; opt->metrics_path = "/metrics"; #endif /* USE_METRICS */ opt->verify_enable = 0; opt->verify_ip_addresses = NULL; opt->verify_port = VERIFY_PORT; opt->verify_zones = 1; opt->verifier = NULL; opt->verifier_count = 1; opt->verifier_feed_zone = 1; opt->verifier_timeout = 0; return opt; } int nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone) { /* create dname for lookup */ const dname_type* dname = dname_parse(opt->region, zone->name); if(!dname) return 0; zone->node.key = dname; if(!rbtree_insert(opt->zone_options, (rbnode_type*)zone)) return 0; return 1; } int nsd_options_insert_pattern(struct nsd_options* opt, struct pattern_options* pat) { if(!pat->pname) return 0; pat->node.key = pat->pname; if(!rbtree_insert(opt->patterns, (rbnode_type*)pat)) return 0; return 1; } void warn_if_directory(const char* filetype, FILE* f, const char* fname) { if(fileno(f) != -1) { struct stat st; memset(&st, 0, sizeof(st)); if(fstat(fileno(f), &st) != -1) { if(S_ISDIR(st.st_mode)) { log_msg(LOG_WARNING, "trying to read %s but it is a directory: %s", filetype, fname); } } } } int parse_options_file(struct nsd_options* opt, const char* file, void (*err)(void*,const char*), void* err_arg, struct nsd_options* old_opts) { FILE *in = 0; struct pattern_options* pat; struct acl_options* acl; if(!cfg_parser) { cfg_parser = (config_parser_state_type*)region_alloc( opt->region, sizeof(config_parser_state_type)); cfg_parser->chroot = 0; } cfg_parser->err = err; cfg_parser->err_arg = err_arg; cfg_parser->filename = (char*)file; cfg_parser->line = 1; cfg_parser->errors = 0; cfg_parser->opt = opt; cfg_parser->pattern = NULL; cfg_parser->zone = NULL; cfg_parser->key = NULL; cfg_parser->tls_auth = NULL; in = fopen(cfg_parser->filename, "r"); if(!in) { if(err) { char m[MAXSYSLOGMSGLEN]; snprintf(m, sizeof(m), "Could not open %s: %s\n", file, strerror(errno)); err(err_arg, m); } else { fprintf(stderr, "Could not open %s: %s\n", file, strerror(errno)); } return 0; } warn_if_directory("configfile", in, file); c_in = in; c_parse(); fclose(in); opt->configfile = region_strdup(opt->region, file); /* Set default cookie_secret_file value */ if(opt->cookie_secret_file_is_default && !opt->cookie_secret_file) { opt->cookie_secret_file = region_strdup(opt->region, COOKIESECRETSFILE); } /* Semantic errors */ if(opt->cookie_staging_secret && !opt->cookie_secret) { c_error("a cookie-staging-secret cannot be configured without " "also providing a cookie-secret"); } RBTREE_FOR(pat, struct pattern_options*, opt->patterns) { struct pattern_options* old_pat = old_opts ? pattern_options_find(old_opts, pat->pname) : NULL; /* lookup keys for acls */ for(acl=pat->allow_notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->request_xfr; acl; acl=acl->next) { /* Find tls_auth */ if (!acl->tls_auth_name) ; /* pass */ else if (!(acl->tls_auth_options = tls_auth_options_find(opt, acl->tls_auth_name))) c_error("tls_auth %s in pattern %s could not be found", acl->tls_auth_name, pat->pname); /* Find key */ if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->provide_xfr; acl; acl=acl->next) { /* Find tls_auth */ if (acl->tls_auth_name) { if (!(acl->tls_auth_options = tls_auth_options_find(opt, acl->tls_auth_name))) c_error("tls_auth %s in pattern %s could not be found", acl->tls_auth_name, pat->pname); } if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->allow_query; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } /* lookup zones for catalog-producer-zone options */ if(pat->catalog_producer_zone) { struct zone_options* zopt; const dname_type *dname = dname_parse(opt->region, pat->catalog_producer_zone); if(dname == NULL) { ; /* pass; already erred during parsing */ } else if (!(zopt = zone_options_find(opt, dname))) { c_error("catalog producer zone %s in pattern " "%s could not be found", pat->catalog_producer_zone, pat->pname); } else if (!zone_is_catalog_producer(zopt)) { c_error("catalog-producer-zone %s in pattern " "%s is not configered as a " "catalog: producer", pat->catalog_producer_zone, pat->pname); } } if( !old_opts /* Okay to add a cat producer member zone pat */ || (!old_pat) /* But not to add, change or del an existing */ || ( old_pat && !old_pat->catalog_producer_zone && !pat->catalog_producer_zone) || ( old_pat && old_pat->catalog_producer_zone && pat->catalog_producer_zone && strcmp( old_pat->catalog_producer_zone , pat->catalog_producer_zone) == 0)){ ; /* No existing catalog producer member zone added * or changed. Everyting is fine: pass */ } else { c_error("catalog-producer-zone in pattern %s cannot " "be removed or changed on a running NSD", pat->pname); } } if(cfg_parser->errors > 0) { if(err) { char m[MAXSYSLOGMSGLEN]; snprintf(m, sizeof(m), "read %s failed: %d errors in " "configuration file\n", file, cfg_parser->errors); err(err_arg, m); } else { fprintf(stderr, "read %s failed: %d errors in " "configuration file\n", file, cfg_parser->errors); } return 0; } return 1; } void options_zonestatnames_create(struct nsd_options* opt) { struct zone_options* zopt; /* allocate "" as zonestat 0, for zones without a zonestat */ if(!rbtree_search(opt->zonestatnames, "")) { struct zonestatname* n; n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n)); n->node.key = region_strdup(opt->region, ""); if(!n->node.key) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } n->id = (unsigned)(opt->zonestatnames->count); rbtree_insert(opt->zonestatnames, (rbnode_type*)n); } RBTREE_FOR(zopt, struct zone_options*, opt->zone_options) { /* insert into tree, so that when read in later id exists */ (void)getzonestatid(opt, zopt); } } #define ZONELIST_HEADER "# NSD zone list\n# name pattern\n" static int comp_zonebucket(const void* a, const void* b) { /* the line size is much smaller than max-int, and positive, * so the subtraction works */ return *(const int*)b - *(const int*)a; } /* insert free entry into zonelist free buckets */ static void zone_list_free_insert(struct nsd_options* opt, int linesize, off_t off) { struct zonelist_free* e; struct zonelist_bucket* b = (struct zonelist_bucket*)rbtree_search( opt->zonefree, &linesize); if(!b) { b = region_alloc_zero(opt->region, sizeof(*b)); b->linesize = linesize; b->node = *RBTREE_NULL; b->node.key = &b->linesize; rbtree_insert(opt->zonefree, &b->node); } e = (struct zonelist_free*)region_alloc_zero(opt->region, sizeof(*e)); e->next = b->list; b->list = e; e->off = off; opt->zonefree_number++; } static struct zone_options* zone_list_member_zone_insert(struct nsd_options* opt, const char* nm, const char* patnm, int linesize, off_t off, const char* mem_idnm, new_member_id_type new_member_id) { struct pattern_options* pat = pattern_options_find(opt, patnm); struct catalog_member_zone* cmz = NULL; struct zone_options* zone; char member_id_str[MAXDOMAINLEN * 5 + 3] = "ERROR!"; DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "zone_list_zone_insert(\"%s\", \"%s\"" ", %d, \"%s\")", nm, patnm, linesize, (mem_idnm ? mem_idnm : ""))); if(!pat) { log_msg(LOG_ERR, "pattern does not exist for zone %s " "pattern %s", nm, patnm); return NULL; } zone = pat->catalog_producer_zone ? &(cmz = catalog_member_zone_create(opt->region))->options : zone_options_create(opt->region); zone->part_of_config = 0; zone->name = region_strdup(opt->region, nm); zone->linesize = linesize; zone->off = off; zone->pattern = pat; if(!nsd_options_insert_zone(opt, zone)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", nm, patnm); region_recycle(opt->region, (void*)zone->name, strlen(nm)+1); region_recycle(opt->region, zone, sizeof(*zone)); return NULL; } if(!mem_idnm) { if(cmz && new_member_id) new_member_id(cmz); if(cmz && cmz->member_id) { /* Assume all bytes of member_id are printable. * plus 1 for space */ zone->linesize += label_length(dname_name(cmz->member_id)) + 1; DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "new linesize: %d", (int)zone->linesize)); } } else if(!cmz) log_msg(LOG_ERR, "member ID '%s' given, but no catalog-producer-" "zone value provided in zone '%s' or pattern '%s'", mem_idnm, nm, patnm); else if(snprintf(member_id_str, sizeof(member_id_str), "%s.zones.%s", mem_idnm, pat->catalog_producer_zone) >= (int)sizeof(member_id_str)) log_msg(LOG_ERR, "syntax error in member ID '%s.zones.%s' for " "zone '%s'", mem_idnm, pat->catalog_producer_zone, nm); else if(!(cmz->member_id = dname_parse(opt->region, member_id_str))) log_msg(LOG_ERR, "parse error in member ID '%s' for " "zone '%s'", member_id_str, nm); return zone; } struct zone_options* zone_list_zone_insert(struct nsd_options* opt,const char* nm,const char* patnm) { return zone_list_member_zone_insert(opt, nm, patnm, 0, 0, NULL, NULL); } int parse_zone_list_file(struct nsd_options* opt) { /* zonelist looks like this: # name pattern add example.com master del example.net slave add foo.bar.nl slave add rutabaga.uk config */ char hdr[64]; char buf[1024]; /* create empty data structures */ opt->zonefree = rbtree_create(opt->region, comp_zonebucket); opt->zonelist = NULL; opt->zonefree_number = 0; opt->zonelist_off = 0; /* try to open the zonelist file, an empty or nonexist file is OK */ opt->zonelist = fopen(opt->zonelistfile, "r+"); if(!opt->zonelist) { if(errno == ENOENT) return 1; /* file does not exist, it is created later */ log_msg(LOG_ERR, "could not open zone list %s: %s", opt->zonelistfile, strerror(errno)); return 0; } /* read header */ hdr[strlen(ZONELIST_HEADER)] = 0; if(fread(hdr, 1, strlen(ZONELIST_HEADER), opt->zonelist) != strlen(ZONELIST_HEADER) || strncmp(hdr, ZONELIST_HEADER, strlen(ZONELIST_HEADER)) != 0) { log_msg(LOG_ERR, "zone list %s contains bad header\n", opt->zonelistfile); fclose(opt->zonelist); opt->zonelist = NULL; return 0; } buf[sizeof(buf)-1]=0; /* read entries in file */ while(fgets(buf, sizeof(buf), opt->zonelist)) { /* skip comments and empty lines */ if(buf[0] == 0 || buf[0] == '\n' || buf[0] == '#') continue; if(strncmp(buf, "add ", 4) == 0) { int linesize = strlen(buf); /* parse the 'add' line */ /* pick last space on the line, so that the domain * name can have a space in it (but not the pattern)*/ char* space = strrchr(buf+4, ' '); char* nm, *patnm; if(!space) { /* parse error */ log_msg(LOG_ERR, "parse error in %s: '%s'", opt->zonelistfile, buf); continue; } nm = buf+4; *space = 0; patnm = space+1; if(linesize && buf[linesize-1] == '\n') buf[linesize-1] = 0; /* store offset and line size for zone entry */ /* and create zone entry in zonetree */ (void)zone_list_member_zone_insert(opt, nm, patnm, linesize, ftello(opt->zonelist)-linesize, NULL, NULL); } else if(strncmp(buf, "cat ", 4) == 0) { int linesize = strlen(buf); /* parse the 'add' line */ /* pick last space on the line, so that the domain * name can have a space in it (but not the pattern)*/ char* nm = buf + 4; char* mem_idnm = strrchr(nm, ' '), *patnm; if(!mem_idnm) { /* parse error */ log_msg(LOG_ERR, "parse error in %s: '%s'", opt->zonelistfile, buf); continue; } *mem_idnm++ = 0; patnm = strrchr(nm, ' '); if(!patnm) { *--mem_idnm = ' '; /* parse error */ log_msg(LOG_ERR, "parse error in %s: '%s'", opt->zonelistfile, buf); continue; } *patnm++ = 0; if(linesize && buf[linesize-1] == '\n') buf[linesize-1] = 0; /* store offset and line size for zone entry */ /* and create zone entry in zonetree */ (void)zone_list_member_zone_insert(opt, nm, patnm, linesize, ftello(opt->zonelist)-linesize, mem_idnm, NULL); } else if(strncmp(buf, "del ", 4) == 0) { /* store offset and line size for deleted entry */ int linesize = strlen(buf); zone_list_free_insert(opt, linesize, ftello(opt->zonelist)-linesize); } else { log_msg(LOG_WARNING, "bad data in %s, '%s'", opt->zonelistfile, buf); } } /* store EOF offset */ opt->zonelist_off = ftello(opt->zonelist); return 1; } void zone_options_delete(struct nsd_options* opt, struct zone_options* zone) { struct catalog_member_zone* member_zone = as_catalog_member_zone(zone); rbtree_delete(opt->zone_options, zone->node.key); region_recycle(opt->region, (void*)zone->node.key, dname_total_size( (dname_type*)zone->node.key)); if(!member_zone) { region_recycle(opt->region, zone, sizeof(*zone)); return; } /* Because catalog member zones are in xfrd only deleted through * catalog_del_consumer_member_zone() or through * xfrd_del_catalog_producer_member(), which both clear the node, * and because member zones in the main and serve processes are not * indexed, *member_zone->node == *RBTREE_NULL. * member_id is cleared too by those delete function, but there may be * leftover member_id's from the initial zone.list processing, which * made it to the main and serve processes. */ assert(!memcmp(&member_zone->node, RBTREE_NULL, sizeof(*RBTREE_NULL))); if(member_zone->member_id) { region_recycle(opt->region, (void*)member_zone->member_id, dname_total_size(member_zone->member_id)); } region_recycle(opt->region, member_zone, sizeof(*member_zone)); } /* add a new zone to the zonelist */ struct zone_options* zone_list_add_or_cat(struct nsd_options* opt, const char* zname, const char* pname, new_member_id_type new_member_id) { int r; struct zonelist_free* e; struct zonelist_bucket* b; char zone_list_line[6 + 5 * MAXDOMAINLEN + 2024 + 65]; struct catalog_member_zone* cmz; /* create zone entry */ struct zone_options* zone = zone_list_member_zone_insert( opt, zname, pname, 6 + strlen(zname) + strlen(pname), 0, NULL, new_member_id); if(!zone) return NULL; if(zone_is_catalog_producer_member(zone) && (cmz = as_catalog_member_zone(zone)) && cmz->member_id) { snprintf(zone_list_line, sizeof(zone_list_line), "cat %s %s %.*s\n", zname, pname, (int)label_length(dname_name(cmz->member_id)), (const char*)dname_name(cmz->member_id) + 1); } else { snprintf(zone_list_line, sizeof(zone_list_line), "add %s %s\n", zname, pname); } /* use free entry or append to file or create new file */ if(!opt->zonelist || opt->zonelist_off == 0) { /* create new file */ if(opt->zonelist) fclose(opt->zonelist); opt->zonelist = fopen(opt->zonelistfile, "w+"); if(!opt->zonelist) { log_msg(LOG_ERR, "could not create zone list %s: %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, ZONELIST_HEADER); if(r != strlen(ZONELIST_HEADER)) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } zone->off = ftello(opt->zonelist); if(zone->off == -1) log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } opt->zonelist_off = ftello(opt->zonelist); if(opt->zonelist_off == -1) log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } return zone; } b = (struct zonelist_bucket*)rbtree_search(opt->zonefree, &zone->linesize); if(!b || b->list == NULL) { /* no empty place, append to file */ zone->off = opt->zonelist_off; if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } opt->zonelist_off += zone->linesize; if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } return zone; } /* reuse empty spot */ e = b->list; zone->off = e->off; if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } /* snip off and recycle element */ b->list = e->next; region_recycle(opt->region, e, sizeof(*e)); if(b->list == NULL) { rbtree_delete(opt->zonefree, &b->linesize); region_recycle(opt->region, b, sizeof(*b)); } opt->zonefree_number--; return zone; } /* remove a zone on the zonelist */ void zone_list_del(struct nsd_options* opt, struct zone_options* zone) { if (zone_is_catalog_consumer_member(zone)) { /* catalog consumer member zones are not in the zones.list file */ zone_options_delete(opt, zone); return; } /* put its space onto the free entry */ if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); return; } fprintf(opt->zonelist, "del"); zone_list_free_insert(opt, zone->linesize, zone->off); /* remove zone_options */ zone_options_delete(opt, zone); /* see if we need to compact: it is going to halve the zonelist */ if(opt->zonefree_number > opt->zone_options->count) { zone_list_compact(opt); } else { if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } } } /* postorder delete of zonelist free space tree */ static void delbucket(region_type* region, struct zonelist_bucket* b) { struct zonelist_free* e, *f; if(!b || (rbnode_type*)b==RBTREE_NULL) return; delbucket(region, (struct zonelist_bucket*)b->node.left); delbucket(region, (struct zonelist_bucket*)b->node.right); e = b->list; while(e) { f = e->next; region_recycle(region, e, sizeof(*e)); e = f; } region_recycle(region, b, sizeof(*b)); } /* compact zonelist file */ void zone_list_compact(struct nsd_options* opt) { char outname[1024]; FILE* out; struct zone_options* zone; off_t off; int r; snprintf(outname, sizeof(outname), "%s~", opt->zonelistfile); /* useful, when : count-of-free > count-of-used */ /* write zonelist to zonelist~ */ out = fopen(outname, "w+"); if(!out) { log_msg(LOG_ERR, "could not open %s: %s", outname, strerror(errno)); return; } r = fprintf(out, ZONELIST_HEADER); if(r == -1) { log_msg(LOG_ERR, "write %s failed: %s", outname, strerror(errno)); fclose(out); return; } else if(r != strlen(ZONELIST_HEADER)) { log_msg(LOG_ERR, "write %s was partial: disk full", outname); fclose(out); return; } off = ftello(out); if(off == -1) { log_msg(LOG_ERR, "ftello(%s): %s", outname, strerror(errno)); fclose(out); return; } RBTREE_FOR(zone, struct zone_options*, opt->zone_options) { struct catalog_member_zone* cmz; if(zone->part_of_config) continue; if(zone_is_catalog_producer_member(zone) && (cmz = as_catalog_member_zone(zone)) && cmz->member_id) { r = fprintf(out, "cat %s %s %.*s\n", zone->name, zone->pattern->pname, (int)label_length(dname_name(cmz->member_id)), (const char*)dname_name(cmz->member_id) + 1); } else { r = fprintf(out, "add %s %s\n", zone->name, zone->pattern->pname); } if(r < 0) { log_msg(LOG_ERR, "write %s failed: %s", outname, strerror(errno)); fclose(out); return; } else if(r != zone->linesize) { log_msg(LOG_ERR, "write %s was partial: disk full", outname); fclose(out); return; } } if(fflush(out) != 0) { log_msg(LOG_ERR, "fflush %s: %s", outname, strerror(errno)); } /* rename zonelist~ onto zonelist */ if(rename(outname, opt->zonelistfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", outname, opt->zonelistfile, strerror(errno)); fclose(out); return; } fclose(opt->zonelist); /* set offsets */ RBTREE_FOR(zone, struct zone_options*, opt->zone_options) { if(zone->part_of_config) continue; zone->off = off; off += zone->linesize; } /* empty the free tree */ delbucket(opt->region, (struct zonelist_bucket*)opt->zonefree->root); opt->zonefree->root = RBTREE_NULL; opt->zonefree->count = 0; opt->zonefree_number = 0; /* finish */ opt->zonelist = out; opt->zonelist_off = off; } /* close zonelist file */ void zone_list_close(struct nsd_options* opt) { if(opt->zonelist) { fclose(opt->zonelist); opt->zonelist = NULL; } } static void c_error_va_list_pos(int showpos, const char* fmt, va_list args) { char* at = NULL; cfg_parser->errors++; if(showpos && c_text && c_text[0]!=0) { at = c_text; } if(cfg_parser->err) { char m[MAXSYSLOGMSGLEN]; 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: ", cfg_parser->filename, cfg_parser->line); if(at) fprintf(stderr, "at '%s': ", at); fprintf(stderr, "error: "); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } void c_error(const char *fmt, ...) { va_list ap; int showpos = 0; if (strcmp(fmt, "syntax error") == 0 || strcmp(fmt, "parse error") == 0) { showpos = 1; } va_start(ap, fmt); c_error_va_list_pos(showpos, fmt, ap); va_end(ap); } int c_wrap(void) { return 1; } struct zone_options* zone_options_create(region_type* region) { struct zone_options* zone; zone = (struct zone_options*)region_alloc(region, sizeof( struct zone_options)); zone->node = *RBTREE_NULL; zone->name = 0; zone->pattern = 0; zone->part_of_config = 0; zone->is_catalog_member_zone = 0; return zone; } struct catalog_member_zone* catalog_member_zone_create(region_type* region) { struct catalog_member_zone* member_zone; member_zone = (struct catalog_member_zone*)region_alloc(region, sizeof(struct catalog_member_zone)); member_zone->options.node = *RBTREE_NULL; member_zone->options.name = 0; member_zone->options.pattern = 0; member_zone->options.part_of_config = 0; member_zone->options.is_catalog_member_zone = 1; member_zone->member_id = NULL; member_zone->node = *RBTREE_NULL; return member_zone; } /* true is booleans are the same truth value */ #define booleq(x,y) ( ((x) && (y)) || (!(x) && !(y)) ) /* true is min_expire_time_expr has either an equal known value * or none of these known values but booleanally equal */ #define expire_expr_eq(x,y) ( ( (x) == REFRESHPLUSRETRYPLUS1 \ && (y) == REFRESHPLUSRETRYPLUS1 ) \ || ( (x) != REFRESHPLUSRETRYPLUS1 \ && (y) != REFRESHPLUSRETRYPLUS1 \ && booleq((x), (y)))) int acl_equal(struct acl_options* p, struct acl_options* q) { if(!booleq(p->use_axfr_only, q->use_axfr_only)) return 0; if(!booleq(p->allow_udp, q->allow_udp)) return 0; if(strcmp(p->ip_address_spec, q->ip_address_spec)!=0) return 0; /* the ip6, port, addr, mask, type: are derived from the ip_address_spec */ if(!booleq(p->nokey, q->nokey)) return 0; if(!booleq(p->blocked, q->blocked)) return 0; if(p->key_name && q->key_name) { if(strcmp(p->key_name, q->key_name)!=0) return 0; } else if(p->key_name && !q->key_name) return 0; else if(!p->key_name && q->key_name) return 0; /* key_options is derived from key_name */ if(p->tls_auth_name && q->tls_auth_name) { if(strcmp(p->tls_auth_name, q->tls_auth_name)!=0) return 0; } else if(p->tls_auth_name && !q->tls_auth_name) return 0; else if(!p->tls_auth_name && q->tls_auth_name) return 0; /* tls_auth_options is derived from tls_auth_name */ return 1; } int acl_list_equal(struct acl_options* p, struct acl_options* q) { /* must be same and in same order */ while(p && q) { if(!acl_equal(p, q)) return 0; p = p->next; q = q->next; } if(!p && !q) return 1; /* different lengths */ return 0; } struct pattern_options* pattern_options_create(region_type* region) { struct pattern_options* p; p = (struct pattern_options*)region_alloc(region, sizeof( struct pattern_options)); p->node = *RBTREE_NULL; p->pname = 0; p->zonefile = 0; p->zonestats = 0; p->allow_notify = 0; p->request_xfr = 0; p->size_limit_xfr = 0; p->notify = 0; p->provide_xfr = 0; p->allow_query = 0; p->outgoing_interface = 0; p->notify_retry = 5; p->notify_retry_is_default = 1; p->allow_axfr_fallback = 1; p->allow_axfr_fallback_is_default = 1; p->implicit = 0; p->xfrd_flags = 0; p->max_refresh_time = 2419200; /* 4 weeks */ p->max_refresh_time_is_default = 1; p->min_refresh_time = 0; p->min_refresh_time_is_default = 1; p->max_retry_time = 1209600; /* 2 weeks */ p->max_retry_time_is_default = 1; p->min_retry_time = 0; p->min_retry_time_is_default = 1; p->min_expire_time = 0; p->min_expire_time_expr = EXPIRE_TIME_IS_DEFAULT; #ifdef RATELIMIT p->rrl_whitelist = 0; #endif p->multi_primary_check = 0; p->store_ixfr = 0; p->store_ixfr_is_default = 1; p->ixfr_size = IXFR_SIZE_DEFAULT; p->ixfr_size_is_default = 1; p->ixfr_number = IXFR_NUMBER_DEFAULT; p->ixfr_number_is_default = 1; p->create_ixfr = 0; p->create_ixfr_is_default = 1; p->verify_zone = VERIFY_ZONE_INHERIT; p->verify_zone_is_default = 1; p->verifier = NULL; p->verifier_feed_zone = VERIFIER_FEED_ZONE_INHERIT; p->verifier_feed_zone_is_default = 1; p->verifier_timeout = VERIFIER_TIMEOUT_INHERIT; p->verifier_timeout_is_default = 1; p->catalog_role = CATALOG_ROLE_INHERIT; p->catalog_role_is_default = 1; p->catalog_member_pattern = NULL; p->catalog_producer_zone = NULL; return p; } static void acl_delete(region_type* region, struct acl_options* acl) { if(acl->ip_address_spec) region_recycle(region, (void*)acl->ip_address_spec, strlen(acl->ip_address_spec)+1); if(acl->key_name) region_recycle(region, (void*)acl->key_name, strlen(acl->key_name)+1); if(acl->tls_auth_name) region_recycle(region, (void*)acl->tls_auth_name, strlen(acl->tls_auth_name)+1); /* key_options is a convenience pointer, not owned by the acl */ region_recycle(region, acl, sizeof(*acl)); } static void acl_list_delete(region_type* region, struct acl_options* list) { struct acl_options* n; while(list) { n = list->next; acl_delete(region, list); list = n; } } static void verifier_delete(region_type* region, char **v) { if(v != NULL) { size_t vc = 0; for(vc = 0; v[vc] != NULL; vc++) region_recycle(region, v[vc], strlen(v[vc]) + 1); region_recycle(region, v, (vc + 1) * sizeof(char *)); } } void pattern_options_remove(struct nsd_options* opt, const char* name) { struct pattern_options* p = (struct pattern_options*)rbtree_delete( opt->patterns, name); /* delete p and its contents */ if (!p) return; if(p->pname) region_recycle(opt->region, (void*)p->pname, strlen(p->pname)+1); if(p->zonefile) region_recycle(opt->region, (void*)p->zonefile, strlen(p->zonefile)+1); if(p->zonestats) region_recycle(opt->region, (void*)p->zonestats, strlen(p->zonestats)+1); acl_list_delete(opt->region, p->allow_notify); acl_list_delete(opt->region, p->request_xfr); acl_list_delete(opt->region, p->notify); acl_list_delete(opt->region, p->provide_xfr); acl_list_delete(opt->region, p->allow_query); acl_list_delete(opt->region, p->outgoing_interface); verifier_delete(opt->region, p->verifier); region_recycle(opt->region, p, sizeof(struct pattern_options)); } static struct acl_options* copy_acl(region_type* region, struct acl_options* a) { struct acl_options* b; if(!a) return NULL; b = (struct acl_options*)region_alloc(region, sizeof(*b)); /* copy the whole lot */ *b = *a; /* fix the pointers */ if(a->ip_address_spec) b->ip_address_spec = region_strdup(region, a->ip_address_spec); if(a->key_name) b->key_name = region_strdup(region, a->key_name); if(a->tls_auth_name) b->tls_auth_name = region_strdup(region, a->tls_auth_name); b->next = NULL; b->key_options = NULL; b->tls_auth_options = NULL; return b; } static struct acl_options* copy_acl_list(struct nsd_options* opt, struct acl_options* a) { struct acl_options* b, *blast = NULL, *blist = NULL; while(a) { b = copy_acl(opt->region, a); /* fixup key_options */ if(b->key_name) b->key_options = key_options_find(opt, b->key_name); else b->key_options = NULL; /* fixup tls_auth_options */ if(b->tls_auth_name) b->tls_auth_options = tls_auth_options_find(opt, b->tls_auth_name); else b->tls_auth_options = NULL; /* link as last into list */ b->next = NULL; if(!blist) blist = b; else blast->next = b; blast = b; a = a->next; } return blist; } static void copy_changed_acl(struct nsd_options* opt, struct acl_options** orig, struct acl_options* anew) { if(!acl_list_equal(*orig, anew)) { acl_list_delete(opt->region, *orig); *orig = copy_acl_list(opt, anew); } } static void copy_changed_verifier(struct nsd_options* opt, char ***ov, char **nv) { size_t ovc, nvc; assert(ov != NULL); ovc = nvc = 0; if(nv != NULL) { for(; nv[nvc] != NULL; nvc++) ; } else { verifier_delete(opt->region, *ov); *ov = NULL; return; } if(*ov != NULL) { for(; (*ov)[ovc] != NULL; ovc++) { if(ovc < nvc && strcmp((*ov)[ovc], nv[ovc]) != 0) break; } if(ovc == nvc) return; verifier_delete(opt->region, *ov); *ov = NULL; } *ov = region_alloc(opt->region, (nvc + 1) * sizeof(*nv)); for(ovc = 0; nv[ovc] != NULL; ovc++) { (*ov)[ovc] = region_strdup(opt->region, nv[ovc]); } (*ov)[ovc] = NULL; assert(ovc == nvc); } static void copy_pat_fixed(region_type* region, struct pattern_options* orig, struct pattern_options* p) { orig->allow_axfr_fallback = p->allow_axfr_fallback; orig->allow_axfr_fallback_is_default = p->allow_axfr_fallback_is_default; orig->notify_retry = p->notify_retry; orig->notify_retry_is_default = p->notify_retry_is_default; orig->implicit = p->implicit; if(p->zonefile) orig->zonefile = region_strdup(region, p->zonefile); else orig->zonefile = NULL; if(p->zonestats) orig->zonestats = region_strdup(region, p->zonestats); else orig->zonestats = NULL; orig->max_refresh_time = p->max_refresh_time; orig->max_refresh_time_is_default = p->max_refresh_time_is_default; orig->min_refresh_time = p->min_refresh_time; orig->min_refresh_time_is_default = p->min_refresh_time_is_default; orig->max_retry_time = p->max_retry_time; orig->max_retry_time_is_default = p->max_retry_time_is_default; orig->min_retry_time = p->min_retry_time; orig->min_retry_time_is_default = p->min_retry_time_is_default; orig->min_expire_time = p->min_expire_time; orig->min_expire_time_expr = p->min_expire_time_expr; #ifdef RATELIMIT orig->rrl_whitelist = p->rrl_whitelist; #endif orig->multi_primary_check = p->multi_primary_check; orig->store_ixfr = p->store_ixfr; orig->store_ixfr_is_default = p->store_ixfr_is_default; orig->ixfr_size = p->ixfr_size; orig->ixfr_size_is_default = p->ixfr_size_is_default; orig->ixfr_number = p->ixfr_number; orig->ixfr_number_is_default = p->ixfr_number_is_default; orig->create_ixfr = p->create_ixfr; orig->create_ixfr_is_default = p->create_ixfr_is_default; orig->verify_zone = p->verify_zone; orig->verify_zone_is_default = p->verify_zone_is_default; orig->verifier_timeout = p->verifier_timeout; orig->verifier_timeout_is_default = p->verifier_timeout_is_default; orig->verifier_feed_zone = p->verifier_feed_zone; orig->verifier_feed_zone_is_default = p->verifier_feed_zone_is_default; orig->catalog_role = p->catalog_role; orig->catalog_role_is_default = p->catalog_role_is_default; if(p->catalog_member_pattern) orig->catalog_member_pattern = region_strdup(region, p->catalog_member_pattern); else orig->catalog_member_pattern = NULL; if(p->catalog_producer_zone) orig->catalog_producer_zone = region_strdup(region, p->catalog_producer_zone); else orig->catalog_producer_zone = NULL; } void pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p) { struct pattern_options* orig = pattern_options_find(opt, p->pname); if(!orig) { /* needs to be copied to opt region */ orig = pattern_options_create(opt->region); orig->pname = region_strdup(opt->region, p->pname); copy_pat_fixed(opt->region, orig, p); orig->allow_notify = copy_acl_list(opt, p->allow_notify); orig->request_xfr = copy_acl_list(opt, p->request_xfr); orig->notify = copy_acl_list(opt, p->notify); orig->provide_xfr = copy_acl_list(opt, p->provide_xfr); orig->allow_query = copy_acl_list(opt, p->allow_query); orig->outgoing_interface = copy_acl_list(opt, p->outgoing_interface); copy_changed_verifier(opt, &orig->verifier, p->verifier); nsd_options_insert_pattern(opt, orig); } else { /* modify in place so pointers stay valid (and copy into region). Do not touch unchanged acls. */ if(orig->zonefile) region_recycle(opt->region, (char*)orig->zonefile, strlen(orig->zonefile)+1); if(orig->zonestats) region_recycle(opt->region, (char*)orig->zonestats, strlen(orig->zonestats)+1); copy_pat_fixed(opt->region, orig, p); copy_changed_acl(opt, &orig->allow_notify, p->allow_notify); copy_changed_acl(opt, &orig->request_xfr, p->request_xfr); copy_changed_acl(opt, &orig->notify, p->notify); copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr); copy_changed_acl(opt, &orig->allow_query, p->allow_query); copy_changed_acl(opt, &orig->outgoing_interface, p->outgoing_interface); copy_changed_verifier(opt, &orig->verifier, p->verifier); } } struct pattern_options* pattern_options_find(struct nsd_options* opt, const char* name) { return (struct pattern_options*)rbtree_search(opt->patterns, name); } static int pattern_verifiers_equal(const char **vp, const char **vq) { size_t vpc, vqc; if(vp == NULL) return vq == NULL; if(vq == NULL) return 0; for(vpc = 0; vp[vpc] != NULL; vpc++) ; for(vqc = 0; vq[vqc] != NULL; vqc++) ; if(vpc != vqc) return 0; for(vpc = 0; vp[vpc] != NULL; vpc++) { assert(vq[vpc] != NULL); if (strcmp(vp[vpc], vq[vpc]) != 0) return 0; } return 1; } int pattern_options_equal(struct pattern_options* p, struct pattern_options* q) { if(strcmp(p->pname, q->pname) != 0) return 0; if(!p->zonefile && q->zonefile) return 0; else if(p->zonefile && !q->zonefile) return 0; else if(p->zonefile && q->zonefile) { if(strcmp(p->zonefile, q->zonefile) != 0) return 0; } if(!p->zonestats && q->zonestats) return 0; else if(p->zonestats && !q->zonestats) return 0; else if(p->zonestats && q->zonestats) { if(strcmp(p->zonestats, q->zonestats) != 0) return 0; } if(!booleq(p->allow_axfr_fallback, q->allow_axfr_fallback)) return 0; if(!booleq(p->allow_axfr_fallback_is_default, q->allow_axfr_fallback_is_default)) return 0; if(p->notify_retry != q->notify_retry) return 0; if(!booleq(p->notify_retry_is_default, q->notify_retry_is_default)) return 0; if(!booleq(p->implicit, q->implicit)) return 0; if(!acl_list_equal(p->allow_notify, q->allow_notify)) return 0; if(!acl_list_equal(p->request_xfr, q->request_xfr)) return 0; if(!acl_list_equal(p->notify, q->notify)) return 0; if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0; if(!acl_list_equal(p->allow_query, q->allow_query)) return 0; if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface)) return 0; if(p->max_refresh_time != q->max_refresh_time) return 0; if(!booleq(p->max_refresh_time_is_default, q->max_refresh_time_is_default)) return 0; if(p->min_refresh_time != q->min_refresh_time) return 0; if(!booleq(p->min_refresh_time_is_default, q->min_refresh_time_is_default)) return 0; if(p->max_retry_time != q->max_retry_time) return 0; if(!booleq(p->max_retry_time_is_default, q->max_retry_time_is_default)) return 0; if(p->min_retry_time != q->min_retry_time) return 0; if(!booleq(p->min_retry_time_is_default, q->min_retry_time_is_default)) return 0; if(p->min_expire_time != q->min_expire_time) return 0; if(!expire_expr_eq(p->min_expire_time_expr, q->min_expire_time_expr)) return 0; #ifdef RATELIMIT if(p->rrl_whitelist != q->rrl_whitelist) return 0; #endif if(!booleq(p->multi_primary_check,q->multi_primary_check)) return 0; if(p->size_limit_xfr != q->size_limit_xfr) return 0; if(!booleq(p->store_ixfr,q->store_ixfr)) return 0; if(!booleq(p->store_ixfr_is_default,q->store_ixfr_is_default)) return 0; if(p->ixfr_size != q->ixfr_size) return 0; if(!booleq(p->ixfr_size_is_default,q->ixfr_size_is_default)) return 0; if(p->ixfr_number != q->ixfr_number) return 0; if(!booleq(p->ixfr_number_is_default,q->ixfr_number_is_default)) return 0; if(!booleq(p->create_ixfr,q->create_ixfr)) return 0; if(!booleq(p->create_ixfr_is_default,q->create_ixfr_is_default)) return 0; if(p->verify_zone != q->verify_zone) return 0; if(!booleq(p->verify_zone_is_default, q->verify_zone_is_default)) return 0; if(!pattern_verifiers_equal((const char **)p->verifier, (const char **)q->verifier)) return 0; if(p->verifier_feed_zone != q->verifier_feed_zone) return 0; if(!booleq(p->verifier_feed_zone_is_default, q->verifier_feed_zone_is_default)) return 0; if(p->verifier_timeout != q->verifier_timeout) return 0; if(!booleq(p->verifier_timeout_is_default, q->verifier_timeout_is_default)) return 0; if(p->catalog_role != q->catalog_role) return 0; if(!booleq(p->catalog_role_is_default, q->catalog_role_is_default)) return 0; if(!p->catalog_member_pattern && q->catalog_member_pattern) return 0; else if(p->catalog_member_pattern && !q->catalog_member_pattern) return 0; else if(p->catalog_member_pattern && q->catalog_member_pattern) { if(strcmp(p->catalog_member_pattern, q->catalog_member_pattern) != 0) return 0; } if(!p->catalog_producer_zone && q->catalog_producer_zone) return 0; else if(p->catalog_producer_zone && !q->catalog_producer_zone) return 0; else if(p->catalog_producer_zone && q->catalog_producer_zone) { if(strcmp(p->catalog_producer_zone, q->catalog_producer_zone) != 0) return 0; } return 1; } static void marshal_u8(struct buffer* b, uint8_t v) { buffer_reserve(b, 1); buffer_write_u8(b, v); } static uint8_t unmarshal_u8(struct buffer* b) { return buffer_read_u8(b); } static void marshal_u64(struct buffer* b, uint64_t v) { buffer_reserve(b, 8); buffer_write_u64(b, v); } static uint64_t unmarshal_u64(struct buffer* b) { return buffer_read_u64(b); } #ifdef RATELIMIT static void marshal_u16(struct buffer* b, uint16_t v) { buffer_reserve(b, 2); buffer_write_u16(b, v); } #endif #ifdef RATELIMIT static uint16_t unmarshal_u16(struct buffer* b) { return buffer_read_u16(b); } #endif static void marshal_u32(struct buffer* b, uint32_t v) { buffer_reserve(b, 4); buffer_write_u32(b, v); } static uint32_t unmarshal_u32(struct buffer* b) { return buffer_read_u32(b); } static void marshal_str(struct buffer* b, const char* s) { if(!s) marshal_u8(b, 0); else { size_t len = strlen(s); marshal_u8(b, 1); buffer_reserve(b, len+1); buffer_write(b, s, len+1); } } static char* unmarshal_str(region_type* r, struct buffer* b) { uint8_t nonnull = unmarshal_u8(b); if(nonnull) { char* result = region_strdup(r, (char*)buffer_current(b)); size_t len = strlen((char*)buffer_current(b)); buffer_skip(b, len+1); return result; } else return NULL; } static void marshal_acl(struct buffer* b, struct acl_options* acl) { buffer_reserve(b, sizeof(*acl)); buffer_write(b, acl, sizeof(*acl)); marshal_str(b, acl->ip_address_spec); marshal_str(b, acl->key_name); marshal_str(b, acl->tls_auth_name); } static struct acl_options* unmarshal_acl(region_type* r, struct buffer* b) { struct acl_options* acl = (struct acl_options*)region_alloc(r, sizeof(*acl)); buffer_read(b, acl, sizeof(*acl)); acl->next = NULL; acl->key_options = NULL; acl->tls_auth_options = NULL; acl->ip_address_spec = unmarshal_str(r, b); acl->key_name = unmarshal_str(r, b); acl->tls_auth_name = unmarshal_str(r, b); return acl; } static void marshal_acl_list(struct buffer* b, struct acl_options* list) { while(list) { marshal_u8(b, 1); /* is there a next one marker */ marshal_acl(b, list); list = list->next; } marshal_u8(b, 0); /* end of list marker */ } static struct acl_options* unmarshal_acl_list(region_type* r, struct buffer* b) { struct acl_options* a, *last=NULL, *list=NULL; while(unmarshal_u8(b)) { a = unmarshal_acl(r, b); /* link in */ a->next = NULL; if(!list) list = a; else last->next = a; last = a; } return list; } static void marshal_strv(struct buffer* b, char **strv) { uint32_t i, n; assert(b != NULL); if (strv == NULL) { marshal_u32(b, 0); return; } for(n = 0; strv[n]; n++) { /* do nothing */ } marshal_u32(b, n); for(i = 0; strv[i] != NULL; i++) { marshal_str(b, strv[i]); } marshal_u8(b, 0); } static char ** unmarshal_strv(region_type* r, struct buffer* b) { uint32_t i, n; char **strv; assert(r != NULL); assert(b != NULL); if ((n = unmarshal_u32(b)) == 0) { return NULL; } strv = region_alloc_zero(r, (n + 1) * sizeof(char *)); for(i = 0; i <= n; i++) { strv[i] = unmarshal_str(r, b); } assert(i == (n + 1)); assert(strv[i - 1] == NULL); return strv; } void pattern_options_marshal(struct buffer* b, struct pattern_options* p) { marshal_str(b, p->pname); marshal_str(b, p->zonefile); marshal_str(b, p->zonestats); #ifdef RATELIMIT marshal_u16(b, p->rrl_whitelist); #endif marshal_u8(b, p->allow_axfr_fallback); marshal_u8(b, p->allow_axfr_fallback_is_default); marshal_u8(b, p->notify_retry); marshal_u8(b, p->notify_retry_is_default); marshal_u8(b, p->implicit); marshal_u64(b, p->size_limit_xfr); marshal_acl_list(b, p->allow_notify); marshal_acl_list(b, p->request_xfr); marshal_acl_list(b, p->notify); marshal_acl_list(b, p->provide_xfr); marshal_acl_list(b, p->allow_query); marshal_acl_list(b, p->outgoing_interface); marshal_u32(b, p->max_refresh_time); marshal_u8(b, p->max_refresh_time_is_default); marshal_u32(b, p->min_refresh_time); marshal_u8(b, p->min_refresh_time_is_default); marshal_u32(b, p->max_retry_time); marshal_u8(b, p->max_retry_time_is_default); marshal_u32(b, p->min_retry_time); marshal_u8(b, p->min_retry_time_is_default); marshal_u32(b, p->min_expire_time); marshal_u8(b, p->min_expire_time_expr); marshal_u8(b, p->multi_primary_check); marshal_u8(b, p->store_ixfr); marshal_u8(b, p->store_ixfr_is_default); marshal_u64(b, p->ixfr_size); marshal_u8(b, p->ixfr_size_is_default); marshal_u32(b, p->ixfr_number); marshal_u8(b, p->ixfr_number_is_default); marshal_u8(b, p->create_ixfr); marshal_u8(b, p->create_ixfr_is_default); marshal_u8(b, p->verify_zone); marshal_u8(b, p->verify_zone_is_default); marshal_strv(b, p->verifier); marshal_u8(b, p->verifier_feed_zone); marshal_u8(b, p->verifier_feed_zone_is_default); marshal_u32(b, p->verifier_timeout); marshal_u8(b, p->verifier_timeout_is_default); marshal_u8(b, p->catalog_role); marshal_u8(b, p->catalog_role_is_default); marshal_str(b, p->catalog_member_pattern); marshal_str(b, p->catalog_producer_zone); } struct pattern_options* pattern_options_unmarshal(region_type* r, struct buffer* b) { struct pattern_options* p = pattern_options_create(r); p->pname = unmarshal_str(r, b); p->zonefile = unmarshal_str(r, b); p->zonestats = unmarshal_str(r, b); #ifdef RATELIMIT p->rrl_whitelist = unmarshal_u16(b); #endif p->allow_axfr_fallback = unmarshal_u8(b); p->allow_axfr_fallback_is_default = unmarshal_u8(b); p->notify_retry = unmarshal_u8(b); p->notify_retry_is_default = unmarshal_u8(b); p->implicit = unmarshal_u8(b); p->size_limit_xfr = unmarshal_u64(b); p->allow_notify = unmarshal_acl_list(r, b); p->request_xfr = unmarshal_acl_list(r, b); p->notify = unmarshal_acl_list(r, b); p->provide_xfr = unmarshal_acl_list(r, b); p->allow_query = unmarshal_acl_list(r, b); p->outgoing_interface = unmarshal_acl_list(r, b); p->max_refresh_time = unmarshal_u32(b); p->max_refresh_time_is_default = unmarshal_u8(b); p->min_refresh_time = unmarshal_u32(b); p->min_refresh_time_is_default = unmarshal_u8(b); p->max_retry_time = unmarshal_u32(b); p->max_retry_time_is_default = unmarshal_u8(b); p->min_retry_time = unmarshal_u32(b); p->min_retry_time_is_default = unmarshal_u8(b); p->min_expire_time = unmarshal_u32(b); p->min_expire_time_expr = unmarshal_u8(b); p->multi_primary_check = unmarshal_u8(b); p->store_ixfr = unmarshal_u8(b); p->store_ixfr_is_default = unmarshal_u8(b); p->ixfr_size = unmarshal_u64(b); p->ixfr_size_is_default = unmarshal_u8(b); p->ixfr_number = unmarshal_u32(b); p->ixfr_number_is_default = unmarshal_u8(b); p->create_ixfr = unmarshal_u8(b); p->create_ixfr_is_default = unmarshal_u8(b); p->verify_zone = unmarshal_u8(b); p->verify_zone_is_default = unmarshal_u8(b); p->verifier = unmarshal_strv(r, b); p->verifier_feed_zone = unmarshal_u8(b); p->verifier_feed_zone_is_default = unmarshal_u8(b); p->verifier_timeout = unmarshal_u32(b); p->verifier_timeout_is_default = unmarshal_u8(b); p->catalog_role = unmarshal_u8(b); p->catalog_role_is_default = unmarshal_u8(b); p->catalog_member_pattern = unmarshal_str(r, b); p->catalog_producer_zone = unmarshal_str(r, b); return p; } struct key_options* key_options_create(region_type* region) { struct key_options* key; key = (struct key_options*)region_alloc_zero(region, sizeof(struct key_options)); return key; } struct tls_auth_options* tls_auth_options_create(region_type* region) { struct tls_auth_options* tls_auth_options; tls_auth_options = (struct tls_auth_options*)region_alloc_zero(region, sizeof(struct tls_auth_options)); return tls_auth_options; } void key_options_insert(struct nsd_options* opt, struct key_options* key) { if(!key->name) return; key->node.key = key->name; (void)rbtree_insert(opt->keys, &key->node); } struct key_options* key_options_find(struct nsd_options* opt, const char* name) { return (struct key_options*)rbtree_search(opt->keys, name); } void tls_auth_options_insert(struct nsd_options* opt, struct tls_auth_options* auth) { if(!auth->name) return; auth->node.key = auth->name; (void)rbtree_insert(opt->tls_auths, &auth->node); } struct tls_auth_options* tls_auth_options_find(struct nsd_options* opt, const char* name) { return (struct tls_auth_options*)rbtree_search(opt->tls_auths, name); } /** remove tsig_key contents */ void key_options_desetup(region_type* region, struct key_options* key) { /* keep tsig_key pointer so that existing references keep valid */ if(!key->tsig_key) return; /* name stays the same */ if(key->tsig_key->data) { /* wipe secret! */ memset(key->tsig_key->data, 0xdd, key->tsig_key->size); region_recycle(region, key->tsig_key->data, key->tsig_key->size); key->tsig_key->data = NULL; key->tsig_key->size = 0; } } /** add tsig_key contents */ void key_options_setup(region_type* region, struct key_options* key) { uint8_t data[16384]; /* 16KB */ int size; if(!key->tsig_key) { /* create it */ key->tsig_key = (tsig_key_type *) region_alloc(region, sizeof(tsig_key_type)); /* create name */ key->tsig_key->name = dname_parse(region, key->name); if(!key->tsig_key->name) { log_msg(LOG_ERR, "Failed to parse tsig key name %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = 0; key->tsig_key->data = NULL; } size = b64_pton(key->secret, data, sizeof(data)); if(size == -1) { log_msg(LOG_ERR, "Failed to parse tsig key data %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = size; key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size); } void key_options_remove(struct nsd_options* opt, const char* name) { struct key_options* k = key_options_find(opt, name); if(!k) return; (void)rbtree_delete(opt->keys, name); if(k->name) region_recycle(opt->region, k->name, strlen(k->name)+1); if(k->algorithm) region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1); if(k->secret) { memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */ region_recycle(opt->region, k->secret, strlen(k->secret)+1); } if(k->tsig_key) { tsig_del_key(k->tsig_key); if(k->tsig_key->name) region_recycle(opt->region, (void*)k->tsig_key->name, dname_total_size(k->tsig_key->name)); key_options_desetup(opt->region, k); region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type)); } region_recycle(opt->region, k, sizeof(struct key_options)); } int key_options_equal(struct key_options* p, struct key_options* q) { return strcmp(p->name, q->name)==0 && strcmp(p->algorithm, q->algorithm)==0 && strcmp(p->secret, q->secret)==0; } void key_options_add_modify(struct nsd_options* opt, struct key_options* key) { struct key_options* orig = key_options_find(opt, key->name); if(!orig) { /* needs to be copied to opt region */ orig = key_options_create(opt->region); orig->name = region_strdup(opt->region, key->name); orig->algorithm = region_strdup(opt->region, key->algorithm); orig->secret = region_strdup(opt->region, key->secret); key_options_setup(opt->region, orig); tsig_add_key(orig->tsig_key); key_options_insert(opt, orig); } else { /* modify entries in existing key, and copy to opt region */ key_options_desetup(opt->region, orig); region_recycle(opt->region, orig->algorithm, strlen(orig->algorithm)+1); orig->algorithm = region_strdup(opt->region, key->algorithm); region_recycle(opt->region, orig->secret, strlen(orig->secret)+1); orig->secret = region_strdup(opt->region, key->secret); key_options_setup(opt->region, orig); } } int acl_check_incoming_block_proxy(struct acl_options* acl, struct query* q, struct acl_options** reason) { /* check each acl element. * if it is blocked, return -1. * return false if no matches for blocked elements. */ if(reason) *reason = NULL; while(acl) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "proxy testing acl %s %s", acl->ip_address_spec, acl->nokey?"NOKEY": (acl->blocked?"BLOCKED":acl->key_name))); if(acl_addr_matches_proxy(acl, q) && acl->blocked) { if(reason) *reason = acl; return -1; } acl = acl->next; } return 0; } int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason) { /* check each acl element. if 1 blocked element matches - return -1. if any element matches - return number. else return -1. */ int found_match = -1; int number = 0; struct acl_options* match = 0; if(reason) *reason = NULL; while(acl) { #ifdef HAVE_SSL DEBUG(DEBUG_XFRD,2, (LOG_INFO, "testing acl %s %s %s", acl->ip_address_spec, acl->nokey?"NOKEY": (acl->blocked?"BLOCKED":acl->key_name), (acl->tls_auth_name && q->tls_auth)?acl->tls_auth_name:"")); #else DEBUG(DEBUG_XFRD,2, (LOG_INFO, "testing acl %s %s", acl->ip_address_spec, acl->nokey?"NOKEY": (acl->blocked?"BLOCKED":acl->key_name))); #endif if(acl_addr_matches(acl, q) && acl_key_matches(acl, q)) { if(!match) { match = acl; /* remember first match */ found_match=number; } if(acl->blocked) { if(reason) *reason = acl; return -1; } } #ifdef HAVE_SSL /* we are in a acl with tls_auth */ if (acl->tls_auth_name && q->tls_auth) { /* we have auth_domain_name in tls_auth */ if (acl->tls_auth_options && acl->tls_auth_options->auth_domain_name) { if (!acl_tls_hostname_matches(q->tls_auth, acl->tls_auth_options->auth_domain_name)) { VERBOSITY(3, (LOG_WARNING, "client cert does not match %s %s", acl->tls_auth_name, acl->tls_auth_options->auth_domain_name)); q->cert_cn = NULL; return -1; } VERBOSITY(5, (LOG_INFO, "%s %s verified", acl->tls_auth_name, acl->tls_auth_options->auth_domain_name)); q->cert_cn = acl->tls_auth_options->auth_domain_name; } else { /* nsd gives error on start for this, but check just in case */ log_msg(LOG_ERR, "auth-domain-name not defined in %s", acl->tls_auth_name); } } #endif number++; acl = acl->next; } if(reason) *reason = match; return found_match; } #ifdef INET6 int acl_addr_matches_ipv6host(struct acl_options* acl, struct sockaddr_storage* addr_storage, unsigned int port) { struct sockaddr_in6* addr = (struct sockaddr_in6*)addr_storage; if(acl->port != 0 && acl->port != port) return 0; switch(acl->rangetype) { case acl_range_mask: case acl_range_subnet: if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) return 0; break; case acl_range_minmax: if(!acl_addr_match_range_v6((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) return 0; break; case acl_range_single: default: if(memcmp(&addr->sin6_addr, &acl->addr.addr6, sizeof(struct in6_addr)) != 0) return 0; break; } return 1; } #endif int acl_addr_matches_ipv4host(struct acl_options* acl, struct sockaddr_in* addr, unsigned int port) { if(acl->port != 0 && acl->port != port) return 0; switch(acl->rangetype) { case acl_range_mask: case acl_range_subnet: if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) return 0; break; case acl_range_minmax: if(!acl_addr_match_range_v4((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) return 0; break; case acl_range_single: default: if(memcmp(&addr->sin_addr, &acl->addr.addr, sizeof(struct in_addr)) != 0) return 0; break; } return 1; } int acl_addr_matches_host(struct acl_options* acl, struct acl_options* host) { if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_storage* addr = (struct sockaddr_storage*)&host->addr; if(!host->is_ipv6) return 0; return acl_addr_matches_ipv6host(acl, addr, host->port); #else return 0; /* no inet6, no match */ #endif } else { struct sockaddr_in* addr = (struct sockaddr_in*)&host->addr; if(host->is_ipv6) return 0; return acl_addr_matches_ipv4host(acl, addr, host->port); } /* ENOTREACH */ return 0; } int acl_addr_matches(struct acl_options* acl, struct query* q) { if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->client_addr; if(addr->ss_family != AF_INET6) return 0; return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); #else return 0; /* no inet6, no match */ #endif } else { struct sockaddr_in* addr = (struct sockaddr_in*)&q->client_addr; if(addr->sin_family != AF_INET) return 0; return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); } /* ENOTREACH */ return 0; } int acl_addr_matches_proxy(struct acl_options* acl, struct query* q) { if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->remote_addr; if(addr->ss_family != AF_INET6) return 0; return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); #else return 0; /* no inet6, no match */ #endif } else { struct sockaddr_in* addr = (struct sockaddr_in*)&q->remote_addr; if(addr->sin_family != AF_INET) return 0; return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); } /* ENOTREACH */ return 0; } int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz) { size_t i; #ifndef NDEBUG assert(sz % 4 == 0); #endif sz /= 4; for(i=0; i *x) return 0; if(*maxval < *x) return 0; return 1; } #ifdef INET6 int acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz) { size_t i; uint8_t checkmin = 1, checkmax = 1; #ifndef NDEBUG assert(sz % 4 == 0); #endif /* check treats x as one huge number */ sz /= 4; for(i=0; i x[i]) return 0; if(checkmax) if(maxval[i] < x[i]) return 0; /* if x is equal to a bound, that bound needs further checks */ if(checkmin && minval[i]!=x[i]) checkmin = 0; if(checkmax && maxval[i]!=x[i]) checkmax = 0; if(!checkmin && !checkmax) return 1; /* will always match */ } return 1; } #endif /* INET6 */ #ifdef HAVE_SSL /* Code in for matches_subject_alternative_name and matches_common_name * functions is from https://wiki.openssl.org/index.php/Hostname_validation * with modifications. * * Obtained from: https://github.com/iSECPartners/ssl-conservatory * Copyright (C) 2012, iSEC Partners. * License: MIT License * Author: Alban Diquet */ static int matches_subject_alternative_name( const char *acl_cert_cn, size_t acl_cert_cn_len, const X509 *cert) { int result = 0; int san_names_nb = -1; STACK_OF(GENERAL_NAME) *san_names = NULL; /* Try to extract the names within the SAN extension from the certificate */ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (san_names == NULL) return 0; san_names_nb = sk_GENERAL_NAME_num(san_names); /* Check each name within the extension */ for (int i = 0; i < san_names_nb && !result; i++) { int len; const char *str; const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); /* Skip non-DNS SAN entries. */ if (current_name->type != GEN_DNS) continue; #if HAVE_ASN1_STRING_GET0_DATA str = (const char *)ASN1_STRING_get0_data(current_name->d.dNSName); #else str = (const char *)ASN1_STRING_data(current_name->d.dNSName); #endif if (str == NULL) continue; len = ASN1_STRING_length(current_name->d.dNSName); if (acl_cert_cn_len == (size_t)len && strncasecmp(str, acl_cert_cn, len) == 0) { result = 1; } else { /* Make sure there isn't an embedded NUL character in the DNS name */ /* From the man page: In general it cannot be assumed that the data * returned by ASN1_STRING_data() is null terminated or does not * contain embedded nulls. */ int pos = 0; while (pos < len && str[pos] != 0) pos++; if (pos == len) { DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "SAN %*s does not match acl for %s", len, str, acl_cert_cn)); } else { DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "Malformed SAN in certificate")); break; } } } sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); return result; } static int matches_common_name( const char *acl_cert_cn, size_t acl_cert_cn_len, const X509 *cert) { int len; int common_name_loc = -1; const char *common_name_str = NULL; X509_NAME *subject_name = NULL; X509_NAME_ENTRY *common_name_entry = NULL; ASN1_STRING *common_name_asn1 = NULL; if ((subject_name = X509_get_subject_name(cert)) == NULL) return 0; /* Find the position of the CN field in the Subject field of the certificate */ common_name_loc = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1); if (common_name_loc < 0) return 0; /* Extract the CN field */ common_name_entry = X509_NAME_get_entry(subject_name, common_name_loc); if (common_name_entry == NULL) return 0; /* Convert the CN field to a C string */ common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); if (common_name_asn1 == NULL) return 0; #if HAVE_ASN1_STRING_GET0_DATA common_name_str = (const char *)ASN1_STRING_get0_data(common_name_asn1); #else common_name_str = (const char *)ASN1_STRING_data(common_name_asn1); #endif len = ASN1_STRING_length(common_name_asn1); if (acl_cert_cn_len == (size_t)len && strncasecmp(acl_cert_cn, common_name_str, len) == 0) { return 1; } else { /* Make sure there isn't an embedded NUL character in the CN */ int pos = 0; while (pos < len && common_name_str[pos] != 0) pos++; if (pos == len) { DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "CN %*s does not match acl for %s", len, common_name_str, acl_cert_cn)); } else { DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "Malformed CN in certificate")); } } return 0; } int acl_tls_hostname_matches(SSL* tls_auth, const char *acl_cert_cn) { int result = 0; size_t acl_cert_cn_len; X509 *client_cert; assert(acl_cert_cn != NULL); #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE client_cert = SSL_get1_peer_certificate(tls_auth); #else client_cert = SSL_get_peer_certificate(tls_auth); #endif if (client_cert == NULL) return 0; /* OpenSSL provides functions for hostname checking from certificate * Following code should work but it doesn't. * Keep it for future test in order to not use custom code * * X509_VERIFY_PARAM *vpm = SSL_get0_param(tls_auth); * Hostname check is done here: * X509_VERIFY_PARAM_set1_host(vpm, acl_cert_cn, 0); // recommended * X509_check_host() // can also be used instead. Not recommended DANE-EE * SSL_get_verify_result(tls_auth) != X509_V_OK) // NOT ok * const char *peername = X509_VERIFY_PARAM_get0_peername(vpm); // NOT ok */ acl_cert_cn_len = strlen(acl_cert_cn); /* semi follow RFC6125#section-6.4.4 check SAN DNS first */ if (!(result = matches_subject_alternative_name(acl_cert_cn, acl_cert_cn_len, client_cert))) result = matches_common_name(acl_cert_cn, acl_cert_cn_len, client_cert); X509_free(client_cert); return result; } #endif int acl_key_matches(struct acl_options* acl, struct query* q) { if(acl->blocked) return 1; if(acl->nokey) { if(q->tsig.status == TSIG_NOT_PRESENT) return 1; return 0; } /* check name of tsig key */ if(q->tsig.status != TSIG_OK) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail query has no TSIG")); return 0; /* query has no TSIG */ } if(q->tsig.error_code != TSIG_ERROR_NOERROR) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail, tsig has error")); return 0; /* some tsig error */ } if(!acl->key_options->tsig_key) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail no config")); return 0; /* key not properly configured */ } if(dname_compare(q->tsig.key_name, acl->key_options->tsig_key->name) != 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail wrong key name")); return 0; /* wrong key name */ } if(tsig_strlowercmp(q->tsig.algorithm->short_name, acl->key_options->algorithm) != 0 && ( strncmp("hmac-", q->tsig.algorithm->short_name, 5) != 0 || tsig_strlowercmp(q->tsig.algorithm->short_name+5, acl->key_options->algorithm) != 0) ) { DEBUG(DEBUG_XFRD,2, (LOG_ERR, "query tsig wrong algorithm")); return 0; /* no such algo */ } return 1; } int acl_same_host(struct acl_options* a, struct acl_options* b) { if(a->is_ipv6 && !b->is_ipv6) return 0; if(!a->is_ipv6 && b->is_ipv6) return 0; if(a->port != b->port) return 0; if(a->rangetype != b->rangetype) return 0; if(!a->is_ipv6) { if(memcmp(&a->addr.addr, &b->addr.addr, sizeof(struct in_addr)) != 0) return 0; if(a->rangetype != acl_range_single && memcmp(&a->range_mask.addr, &b->range_mask.addr, sizeof(struct in_addr)) != 0) return 0; } else { #ifdef INET6 if(memcmp(&a->addr.addr6, &b->addr.addr6, sizeof(struct in6_addr)) != 0) return 0; if(a->rangetype != acl_range_single && memcmp(&a->range_mask.addr6, &b->range_mask.addr6, sizeof(struct in6_addr)) != 0) return 0; #else return 0; #endif } return 1; } #if defined(HAVE_SSL) void key_options_tsig_add(struct nsd_options* opt) { struct key_options* optkey; RBTREE_FOR(optkey, struct key_options*, opt->keys) { key_options_setup(opt->region, optkey); tsig_add_key(optkey->tsig_key); } } #endif int zone_is_slave(struct zone_options* opt) { return opt && opt->pattern && opt->pattern->request_xfr != 0; } /* get a character in string (or replacement char if not long enough) */ static const char* get_char(const char* str, size_t i) { static char res[2]; if(i >= strlen(str)) return "."; res[0] = str[i]; res[1] = 0; return res; } /* get end label of the zone name (or .) */ static const char* get_end_label(struct zone_options* zone, int i) { const dname_type* d = (const dname_type*)zone->node.key; if(i >= d->label_count) { return "."; } return wirelabel2str(dname_label(d, i)); } /* replace occurrences of one with two */ void replace_str(char* str, size_t len, const char* one, const char* two) { char* pos; char* at = str; while( (pos=strstr(at, one)) ) { if(strlen(str)+strlen(two)-strlen(one) >= len) return; /* no more space to replace */ /* stuff before pos is fine */ /* move the stuff after pos to make space for two, add * one to length of remainder to also copy the 0 byte end */ memmove(pos+strlen(two), pos+strlen(one), strlen(pos+strlen(one))+1); /* copy in two */ memmove(pos, two, strlen(two)); /* at is end of the newly inserted two (avoids recursion if * two contains one) */ at = pos+strlen(two); } } const char* config_cook_string(struct zone_options* zone, const char* input) { static char f[1024]; /* if not a template, return as-is */ if(!strchr(input, '%')) { return input; } strlcpy(f, input, sizeof(f)); if(strstr(f, "%1")) replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); if(strstr(f, "%2")) replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); if(strstr(f, "%3")) replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); if(strstr(f, "%z")) replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); if(strstr(f, "%y")) replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); if(strstr(f, "%x")) replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); if(strstr(f, "%s")) replace_str(f, sizeof(f), "%s", zone->name); return f; } const char* config_make_zonefile(struct zone_options* zone, struct nsd* nsd) { static char f[1024]; /* if not a template, return as-is */ if(!strchr(zone->pattern->zonefile, '%')) { if (nsd->chrootdir && nsd->chrootdir[0] && zone->pattern->zonefile && zone->pattern->zonefile[0] == '/' && strncmp(zone->pattern->zonefile, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) /* -1 because chrootdir ends in trailing slash */ return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1; return zone->pattern->zonefile; } strlcpy(f, zone->pattern->zonefile, sizeof(f)); if(strstr(f, "%1")) replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); if(strstr(f, "%2")) replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); if(strstr(f, "%3")) replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); if(strstr(f, "%z")) replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); if(strstr(f, "%y")) replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); if(strstr(f, "%x")) replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); if(strstr(f, "%s")) replace_str(f, sizeof(f), "%s", zone->name); if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' && strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) /* -1 because chrootdir ends in trailing slash */ return f + strlen(nsd->chrootdir) - 1; return f; } struct zone_options* zone_options_find(struct nsd_options* opt, const struct dname* apex) { return (struct zone_options*) rbtree_search(opt->zone_options, apex); } struct acl_options* acl_find_num(struct acl_options* acl, int num) { int count = num; if(num < 0) return 0; while(acl && count > 0) { acl = acl->next; count--; } if(count == 0) return acl; return 0; } /* true if ipv6 address, false if ipv4 */ int parse_acl_is_ipv6(const char* p) { /* see if addr is ipv6 or ipv4 -- by : and . */ while(*p) { if(*p == '.') return 0; if(*p == ':') return 1; ++p; } return 0; } /* returns range type. mask is the 2nd part of the range */ int parse_acl_range_type(char* ip, char** mask) { char *p; if((p=strchr(ip, '&'))!=0) { *p = 0; *mask = p+1; return acl_range_mask; } if((p=strchr(ip, '/'))!=0) { *p = 0; *mask = p+1; return acl_range_subnet; } if((p=strchr(ip, '-'))!=0) { *p = 0; *mask = p+1; return acl_range_minmax; } *mask = 0; return acl_range_single; } /* parses subnet mask, fills 0 mask as well */ void parse_acl_range_subnet(char* p, void* addr, int maxbits) { int subnet_bits = atoi(p); uint8_t* addr_bytes = (uint8_t*)addr; if(subnet_bits == 0 && strcmp(p, "0")!=0) { c_error("bad subnet range '%s'", p); return; } if(subnet_bits < 0 || subnet_bits > maxbits) { c_error("subnet of %d bits out of range [0..%d]", subnet_bits, maxbits); return; } /* fill addr with n bits of 1s (struct has been zeroed) */ while(subnet_bits >= 8) { *addr_bytes++ = 0xff; subnet_bits -= 8; } if(subnet_bits > 0) { uint8_t shifts[] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; *addr_bytes = shifts[subnet_bits]; } } struct acl_options* parse_acl_info(region_type* region, char* ip, const char* key) { char* p; struct acl_options* acl = (struct acl_options*)region_alloc(region, sizeof(struct acl_options)); acl->next = 0; /* ip */ acl->ip_address_spec = region_strdup(region, ip); acl->use_axfr_only = 0; acl->allow_udp = 0; acl->ixfr_disabled = 0; acl->bad_xfr_count = 0; acl->key_options = 0; acl->tls_auth_options = 0; acl->tls_auth_name = 0; acl->is_ipv6 = 0; acl->port = 0; memset(&acl->addr, 0, sizeof(union acl_addr_storage)); memset(&acl->range_mask, 0, sizeof(union acl_addr_storage)); if((p=strrchr(ip, '@'))!=0) { if(atoi(p+1) == 0) c_error("expected port number after '@'"); else acl->port = atoi(p+1); *p=0; } acl->rangetype = parse_acl_range_type(ip, &p); if(parse_acl_is_ipv6(ip)) { acl->is_ipv6 = 1; #ifdef INET6 if(inet_pton(AF_INET6, ip, &acl->addr.addr6) != 1) c_error("Bad ip6 address '%s'", ip); if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) { assert(p); if(inet_pton(AF_INET6, p, &acl->range_mask.addr6) != 1) c_error("Bad ip6 address mask '%s'", p); } if(acl->rangetype==acl_range_subnet) { assert(p); parse_acl_range_subnet(p, &acl->range_mask.addr6, 128); } #else c_error("encountered IPv6 address '%s'.", ip); #endif /* INET6 */ } else { acl->is_ipv6 = 0; if(inet_pton(AF_INET, ip, &acl->addr.addr) != 1) c_error("Bad ip4 address '%s'", ip); if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) { assert(p); if(inet_pton(AF_INET, p, &acl->range_mask.addr) != 1) c_error("Bad ip4 address mask '%s'", p); } if(acl->rangetype==acl_range_subnet) { assert(p); parse_acl_range_subnet(p, &acl->range_mask.addr, 32); } } /* key */ if(strcmp(key, "NOKEY")==0) { acl->nokey = 1; acl->blocked = 0; acl->key_name = 0; } else if(strcmp(key, "BLOCKED")==0) { acl->nokey = 0; acl->blocked = 1; acl->key_name = 0; } else { acl->nokey = 0; acl->blocked = 0; acl->key_name = region_strdup(region, key); } return acl; } /* copy acl list at end of parser start, update current */ static void copy_and_append_acls(struct acl_options** start, struct acl_options* list) { struct acl_options *tail = NULL; assert(start != NULL); tail = *start; if(tail) { while(tail->next) { tail = tail->next; } } while(list) { struct acl_options* acl = copy_acl(cfg_parser->opt->region, list); acl->next = NULL; if(tail) { tail->next = acl; } else { *start = acl; } tail = acl; list = list->next; } } void config_apply_pattern(struct pattern_options *dest, const char* name) { /* find the pattern */ struct pattern_options* pat = pattern_options_find(cfg_parser->opt, name); if(!pat) { c_error("could not find pattern %s", name); return; } if( (!dest->pname || strncmp(dest->pname, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)) == 0) && pat->catalog_producer_zone) { c_error("patterns with an catalog-producer-zone option are to " "be used with \"nsd-control addzone\" only and cannot " "be included from zone clauses in the config file"); return; } if((dest->catalog_role == CATALOG_ROLE_PRODUCER && pat->request_xfr) || ( pat->catalog_role == CATALOG_ROLE_PRODUCER && dest->request_xfr)){ c_error("catalog producer zones cannot be secondary zones"); } /* apply settings */ if(pat->zonefile) dest->zonefile = region_strdup(cfg_parser->opt->region, pat->zonefile); if(pat->zonestats) dest->zonestats = region_strdup(cfg_parser->opt->region, pat->zonestats); if(!pat->allow_axfr_fallback_is_default) { dest->allow_axfr_fallback = pat->allow_axfr_fallback; dest->allow_axfr_fallback_is_default = 0; } if(!pat->notify_retry_is_default) { dest->notify_retry = pat->notify_retry; dest->notify_retry_is_default = 0; } if(!pat->max_refresh_time_is_default) { dest->max_refresh_time = pat->max_refresh_time; dest->max_refresh_time_is_default = 0; } if(!pat->min_refresh_time_is_default) { dest->min_refresh_time = pat->min_refresh_time; dest->min_refresh_time_is_default = 0; } if(!pat->max_retry_time_is_default) { dest->max_retry_time = pat->max_retry_time; dest->max_retry_time_is_default = 0; } if(!pat->min_retry_time_is_default) { dest->min_retry_time = pat->min_retry_time; dest->min_retry_time_is_default = 0; } if(!expire_time_is_default(pat->min_expire_time_expr)) { dest->min_expire_time = pat->min_expire_time; dest->min_expire_time_expr = pat->min_expire_time_expr; } if(!pat->store_ixfr_is_default) { dest->store_ixfr = pat->store_ixfr; dest->store_ixfr_is_default = 0; } if(!pat->ixfr_size_is_default) { dest->ixfr_size = pat->ixfr_size; dest->ixfr_size_is_default = 0; } if(!pat->ixfr_number_is_default) { dest->ixfr_number = pat->ixfr_number; dest->ixfr_number_is_default = 0; } if(!pat->create_ixfr_is_default) { dest->create_ixfr = pat->create_ixfr; dest->create_ixfr_is_default = 0; } dest->size_limit_xfr = pat->size_limit_xfr; #ifdef RATELIMIT dest->rrl_whitelist |= pat->rrl_whitelist; #endif /* append acl items */ copy_and_append_acls(&dest->allow_notify, pat->allow_notify); copy_and_append_acls(&dest->request_xfr, pat->request_xfr); copy_and_append_acls(&dest->notify, pat->notify); copy_and_append_acls(&dest->provide_xfr, pat->provide_xfr); copy_and_append_acls(&dest->allow_query, pat->allow_query); copy_and_append_acls(&dest->outgoing_interface, pat->outgoing_interface); if(pat->multi_primary_check) dest->multi_primary_check = pat->multi_primary_check; if(!pat->verify_zone_is_default) { dest->verify_zone = pat->verify_zone; dest->verify_zone_is_default = 0; } if(!pat->verifier_timeout_is_default) { dest->verifier_timeout = pat->verifier_timeout; dest->verifier_timeout_is_default = 0; } if(!pat->verifier_feed_zone_is_default) { dest->verifier_feed_zone = pat->verifier_feed_zone; dest->verifier_feed_zone_is_default = 0; } if(pat->verifier != NULL) { size_t cnt; char **vec; region_type *region = cfg_parser->opt->region; for(cnt = 0; pat->verifier[cnt] != NULL; cnt++) ; vec = region_alloc(region, (cnt + 1) * sizeof(char *)); for(cnt = 0; pat->verifier[cnt] != NULL; cnt++) { vec[cnt] = region_strdup(region, pat->verifier[cnt]); } vec[cnt] = NULL; if(dest->verifier != NULL) { size_t size; for(cnt = 0; dest->verifier[cnt] != NULL; cnt++) { size = strlen(dest->verifier[cnt]) + 1; region_recycle( region, dest->verifier[cnt], size); } size = (cnt + 1) * sizeof(char *); region_recycle(region, dest->verifier, size); } dest->verifier = vec; } if(!pat->catalog_role_is_default) { dest->catalog_role = pat->catalog_role; dest->catalog_role_is_default = 0; } if(pat->catalog_member_pattern) dest->catalog_member_pattern = region_strdup( cfg_parser->opt->region, pat->catalog_member_pattern); if(pat->catalog_producer_zone) dest->catalog_producer_zone = region_strdup( cfg_parser->opt->region, pat->catalog_producer_zone); } void nsd_options_destroy(struct nsd_options* opt) { region_destroy(opt->region); #ifdef MEMCLEAN /* OS collects memory pages */ c_lex_destroy(); #endif } unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt) { #ifdef USE_ZONE_STATS const char* statname; struct zonestatname* n; rbnode_type* res; /* try to find the instantiated zonestat name */ if(!zopt->pattern->zonestats || zopt->pattern->zonestats[0]==0) return 0; /* no zone stats */ statname = config_cook_string(zopt, zopt->pattern->zonestats); res = rbtree_search(opt->zonestatnames, statname); if(res) return ((struct zonestatname*)res)->id; /* create it */ n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n)); n->node.key = region_strdup(opt->region, statname); if(!n->node.key) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } n->id = (unsigned)(opt->zonestatnames->count); rbtree_insert(opt->zonestatnames, (rbnode_type*)n); return n->id; #else /* USE_ZONE_STATS */ (void)opt; (void)zopt; return 0; #endif /* USE_ZONE_STATS */ } /** check if config turns on IP-address interface with certificates or a * named pipe without certificates. */ int options_remote_is_address(struct nsd_options* cfg) { if(!cfg->control_enable) return 0; if(!cfg->control_interface) return 1; if(!cfg->control_interface->address) return 1; if(cfg->control_interface->address[0] == 0) return 1; return (cfg->control_interface->address[0] != '/'); } #ifdef HAVE_GETIFADDRS static void resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addresses, size_t *ip_addresses_size) { struct ifaddrs *ifa; size_t last_ip_addresses_size = *ip_addresses_size; for(ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { sa_family_t family; const char* atsign; #ifdef INET6 /* | address ip | % | ifa name | @ | port | nul */ char addr_buf[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1 + 16 + 1]; #else char addr_buf[INET_ADDRSTRLEN + 1 + 16 + 1]; #endif if((atsign=strrchr(search_ifa, '@')) != NULL) { if(strlen(ifa->ifa_name) != (size_t)(atsign-search_ifa) || strncmp(ifa->ifa_name, search_ifa, atsign-search_ifa) != 0) continue; } else { if(strcmp(ifa->ifa_name, search_ifa) != 0) continue; atsign = ""; } if(ifa->ifa_addr == NULL) continue; family = ifa->ifa_addr->sa_family; if(family == AF_INET) { char a4[INET_ADDRSTRLEN + 1]; struct sockaddr_in *in4 = (struct sockaddr_in *) ifa->ifa_addr; if(!inet_ntop(family, &in4->sin_addr, a4, sizeof(a4))) error("inet_ntop"); snprintf(addr_buf, sizeof(addr_buf), "%s%s", a4, atsign); } #ifdef INET6 else if(family == AF_INET6) { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ifa->ifa_addr; char a6[INET6_ADDRSTRLEN + 1]; char if_index_name[IF_NAMESIZE + 1]; if_index_name[0] = 0; if(!inet_ntop(family, &in6->sin6_addr, a6, sizeof(a6))) error("inet_ntop"); if_indextoname(in6->sin6_scope_id, (char *)if_index_name); if (strlen(if_index_name) != 0) { snprintf(addr_buf, sizeof(addr_buf), "%s%%%s%s", a6, if_index_name, atsign); } else { snprintf(addr_buf, sizeof(addr_buf), "%s%s", a6, atsign); } } #endif else { continue; } VERBOSITY(4, (LOG_INFO, "interface %s has address %s", search_ifa, addr_buf)); *ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1)); (*ip_addresses)[*ip_addresses_size] = xstrdup(addr_buf); (*ip_addresses_size)++; } if (*ip_addresses_size == last_ip_addresses_size) { *ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1)); (*ip_addresses)[*ip_addresses_size] = xstrdup(search_ifa); (*ip_addresses_size)++; } } static void resolve_interface_names_for_ref(struct ip_address_option** ip_addresses_ref, struct ifaddrs *addrs, region_type* region) { struct ip_address_option *ip_addr; struct ip_address_option *last = NULL; struct ip_address_option *first = NULL; /* replace the list of ip_adresses with a new list where the * interface names are replaced with their ip-address strings * from getifaddrs. An interface can have several addresses. */ for(ip_addr = *ip_addresses_ref; ip_addr; ip_addr = ip_addr->next) { char **ip_addresses = NULL; size_t ip_addresses_size = 0, i; resolve_ifa_name(addrs, ip_addr->address, &ip_addresses, &ip_addresses_size); for (i = 0; i < ip_addresses_size; i++) { struct ip_address_option *current; /* this copies the range_option, dev, and fib from * the original ip_address option to the new ones * with the addresses spelled out by resolve_ifa_name*/ current = region_alloc_init(region, ip_addr, sizeof(*ip_addr)); current->address = region_strdup(region, ip_addresses[i]); current->next = NULL; free(ip_addresses[i]); if(first == NULL) { first = current; } else { last->next = current; } last = current; } free(ip_addresses); } *ip_addresses_ref = first; } #endif /* HAVE_GETIFADDRS */ void resolve_interface_names(struct nsd_options* options) { #ifdef HAVE_GETIFADDRS struct ifaddrs *addrs; if(getifaddrs(&addrs) == -1) error("failed to list interfaces"); resolve_interface_names_for_ref(&options->ip_addresses, addrs, options->region); resolve_interface_names_for_ref(&options->control_interface, addrs, options->region); #ifdef USE_METRICS resolve_interface_names_for_ref(&options->metrics_interface, addrs, options->region); #endif /* USE_METRICS */ freeifaddrs(addrs); #else (void)options; #endif /* HAVE_GETIFADDRS */ } int sockaddr_uses_proxy_protocol_port(struct nsd_options* options, struct sockaddr* addr) { struct proxy_protocol_port_list* p; int port; #ifdef INET6 struct sockaddr_storage* ss = (struct sockaddr_storage*)addr; if(ss->ss_family == AF_INET6) { struct sockaddr_in6* a6 = (struct sockaddr_in6*)addr; port = ntohs(a6->sin6_port); } else if(ss->ss_family == AF_INET) { #endif struct sockaddr_in* a = (struct sockaddr_in*)addr; #ifndef INET6 if(a->sin_family != AF_INET) return 0; /* unknown family */ #endif port = ntohs(a->sin_port); #ifdef INET6 } else { return 0; /* unknown family */ } #endif p = options->proxy_protocol_port; while(p) { if(p->port == port) return 1; p = p->next; } return 0; } nsd-4.12.0/nsec3.h0000644000175000017500000001013415002373054013160 0ustar mozziemozzie/* * nsec3.h -- nsec3 handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef NSEC3_H #define NSEC3_H #ifdef NSEC3 struct udb_ptr; struct domain; struct dname; struct region; struct zone; struct namedb; struct query; struct answer; struct rr; /* * calculate prehash information for zone. */ void prehash_zone(struct namedb* db, struct zone* zone); /* * calculate prehash for zone, assumes no partial precompile or prehashlist */ void prehash_zone_complete(struct namedb* db, struct zone* zone); /* * finds nsec3 that covers the given domain hash. * returns true if the find is exact. */ int nsec3_find_cover(struct zone* zone, uint8_t* hash, size_t hashlen, struct domain** result); /* * _answer_ Routines used to add the correct nsec3 record to a query answer. * cnames etc may have been followed, hence original name. */ /* * add proof for wildcards that the name below the wildcard.parent * does not exist */ void nsec3_answer_wildcard(struct query* query, struct answer* answer, struct domain* wildcard, const struct dname* qname); /* * add NSEC3 to provide domain name but not rrset exists, * this could be a query for a DS or NSEC3 type */ void nsec3_answer_nodata(struct query *query, struct answer *answer, struct domain *original); /* * add NSEC3 for a delegation (optout stuff) */ void nsec3_answer_delegation(struct query *query, struct answer *answer); /* * add NSEC3 for authoritative answers. * match==0 is an nxdomain. */ void nsec3_answer_authoritative(struct domain** match, struct query *query, struct answer *answer, struct domain* closest_encloser, const struct dname* qname); /* * True if domain is a NSEC3 (+RRSIG) data only variety. * pass nonNULL zone to filter for particular zone. */ int domain_has_only_NSEC3(struct domain* domain, struct zone* zone); /* get hashed bytes */ void nsec3_hash_and_store(struct zone* zone, const struct dname* dname, uint8_t* store); /* see if NSEC3 record uses the params in use for the zone */ int nsec3_rr_uses_params(struct rr* rr, struct zone* zone); /* number of NSEC3s that are in the zone chain */ int nsec3_in_chain_count(struct domain* domain, struct zone* zone); /* find previous NSEC3, or, lastinzone, or, NULL */ struct domain* nsec3_chain_find_prev(struct zone* zone, struct domain* domain); /* clear nsec3 precompile for the zone */ void nsec3_clear_precompile(struct namedb* db, struct zone* zone); /* if domain is part of nsec3hashed domains of a zone */ int nsec3_domain_part_of_zone(struct domain* d, struct zone* z); /* condition when a domain is precompiled */ int nsec3_condition_hash(struct domain* d, struct zone* z); /* condition when a domain is ds precompiled */ int nsec3_condition_dshash(struct domain* d, struct zone* z); /* set nsec3param for this zone or NULL if no NSEC3 available */ void nsec3_find_zone_param(struct namedb* db, struct zone* zone, struct rr* avoid_rr, int checkchain); /* hash domain and wcchild, and lookup nsec3 in tree, and precompile */ void nsec3_precompile_domain(struct namedb* db, struct domain* domain, struct zone* zone, struct region* tmpregion); /* hash ds_parent_cover, and lookup nsec3 and precompile */ void nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, struct zone* zone); /* put nsec3 into nsec3tree and adjust zonelast */ void nsec3_precompile_nsec3rr(struct namedb* db, struct domain* domain, struct zone* zone); /* precompile entire zone, assumes all is null at start */ void nsec3_precompile_newparam(struct namedb* db, struct zone* zone); /* create b32.zone for a hash, allocated in the region */ const struct dname* nsec3_b32_create(struct region* region, struct zone* zone, unsigned char* hash); /* create trees for nsec3 updates and lookups in zone */ void nsec3_zone_trees_create(struct region* region, struct zone* zone); /* lookup zone that contains domain's nsec3 trees */ struct zone* nsec3_tree_zone(struct namedb* db, struct domain* domain); /* lookup zone that contains domain's ds tree */ struct zone* nsec3_tree_dszone(struct namedb* db, struct domain* domain); #endif /* NSEC3 */ #endif /* NSEC3_H*/ nsd-4.12.0/nsec3.c0000644000175000017500000010733515002373054013165 0ustar mozziemozzie/* * nsec3.c -- nsec3 handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #ifdef NSEC3 #include #include #include "nsec3.h" #include "iterated_hash.h" #include "namedb.h" #include "nsd.h" #include "answer.h" #include "options.h" #define NSEC3_RDATA_BITMAP 5 /* compare nsec3 hashes in nsec3 tree */ static int cmp_hash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); if(!b->nsec3->hash_wc) return 1; return memcmp(a->nsec3->hash_wc->hash.hash, b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN); } /* compare nsec3 hashes in nsec3 wc tree */ static int cmp_wchash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); if(!b->nsec3->hash_wc) return 1; return memcmp(a->nsec3->hash_wc->wc.hash, b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN); } /* compare nsec3 hashes in nsec3 ds tree */ static int cmp_dshash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0); if(!b->nsec3->ds_parent_hash) return 1; return memcmp(a->nsec3->ds_parent_hash->hash, b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN); } /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are * stored in the domain name of the node */ static int cmp_nsec3_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; /* labelcount + 32long label */ assert(dname_name(domain_dname_const(a))[0] == 32); assert(dname_name(domain_dname_const(b))[0] == 32); return memcmp(dname_name(domain_dname_const(a)), dname_name(domain_dname_const(b)), 33); } void nsec3_zone_trees_create(struct region* region, zone_type* zone) { if(!zone->nsec3tree) zone->nsec3tree = rbtree_create(region, cmp_nsec3_tree); if(!zone->hashtree) zone->hashtree = rbtree_create(region, cmp_hash_tree); if(!zone->wchashtree) zone->wchashtree = rbtree_create(region, cmp_wchash_tree); if(!zone->dshashtree) zone->dshashtree = rbtree_create(region, cmp_dshash_tree); } static void detect_nsec3_params(rr_type* nsec3_apex, const unsigned char** salt, int* salt_len, int* iter) { assert(salt && salt_len && iter); assert(nsec3_apex); *salt_len = rdata_atom_data(nsec3_apex->rdatas[3])[0]; *salt = (unsigned char*)(rdata_atom_data(nsec3_apex->rdatas[3])+1); *iter = read_uint16(rdata_atom_data(nsec3_apex->rdatas[2])); } const dname_type * nsec3_b32_create(region_type* region, zone_type* zone, unsigned char* hash) { const dname_type* dname; char b32[SHA_DIGEST_LENGTH*2+1]; b32_ntop(hash, SHA_DIGEST_LENGTH, b32, sizeof(b32)); dname=dname_parse(region, b32); dname=dname_concatenate(region, dname, domain_dname(zone->apex)); return dname; } void nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store) { const unsigned char* nsec3_salt = NULL; int nsec3_saltlength = 0; int nsec3_iterations = 0; detect_nsec3_params(zone->nsec3_param, &nsec3_salt, &nsec3_saltlength, &nsec3_iterations); assert(nsec3_iterations >= 0 && nsec3_iterations <= 65536); iterated_hash((unsigned char*)store, nsec3_salt, nsec3_saltlength, dname_name(dname), dname->name_size, nsec3_iterations); } #define STORE_HASH(x,y) memmove(domain->nsec3->x,y,NSEC3_HASH_LEN); domain->nsec3->have_##x =1; /** find hash or create it and store it */ static void nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone, const dname_type* dname, domain_type* domain, region_type* tmpregion) { const dname_type* wcard; if(domain->nsec3->hash_wc) { return; } /* lookup failed; disk failure or so */ domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *) region_alloc(region, sizeof(nsec3_hash_wc_node_type)); domain->nsec3->hash_wc->hash.node.key = NULL; domain->nsec3->hash_wc->wc.node.key = NULL; nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash); wcard = dname_parse(tmpregion, "*"); wcard = dname_concatenate(tmpregion, wcard, dname); nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash); } static void nsec3_lookup_hash_ds(region_type* region, zone_type* zone, const dname_type* dname, domain_type* domain) { if(domain->nsec3->ds_parent_hash) { return; } /* lookup failed; disk failure or so */ domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *) region_alloc(region, sizeof(nsec3_hash_node_type)); domain->nsec3->ds_parent_hash->node.key = NULL; nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash); } static int nsec3_has_soa(rr_type* rr) { if(rdata_atom_size(rr->rdatas[NSEC3_RDATA_BITMAP]) >= 3 && /* has types in bitmap */ rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP])[0] == 0 && /* first window = 0, */ /* [1]: bitmap length must be >= 1 */ /* [2]: bit[6] = SOA, thus mask first bitmap octet with 0x02 */ rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP])[2]&0x02) { /* SOA bit set */ return 1; } return 0; } static rr_type* check_apex_soa(namedb_type* namedb, zone_type *zone, int nolog) { uint8_t h[NSEC3_HASH_LEN]; domain_type* domain; const dname_type* hashed_apex, *dname = domain_dname(zone->apex); unsigned j; rrset_type* nsec3_rrset; region_type* tmpregion; nsec3_hash_and_store(zone, dname, h); tmpregion = region_create(xalloc, free); hashed_apex = nsec3_b32_create(tmpregion, zone, h); domain = domain_table_find(namedb->domains, hashed_apex); if(!domain) { if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry has no hash(apex).", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); if(!nsec3_rrset) { if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } for(j=0; jrr_count; j++) { if(nsec3_has_soa(&nsec3_rrset->rrs[j])) { region_destroy(tmpregion); return &nsec3_rrset->rrs[j]; } } if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } static void nsec3param_to_str(struct rr* rr, char* str, size_t buflen) { rdata_atom_type* rd = rr->rdatas; size_t len; len = snprintf(str, buflen, "%u %u %u ", (unsigned)rdata_atom_data(rd[0])[0], (unsigned)rdata_atom_data(rd[1])[0], (unsigned)read_uint16(rdata_atom_data(rd[2]))); if(rdata_atom_data(rd[3])[0] == 0) { if(buflen > len + 2) str[len++] = '-'; } else { len += hex_ntop(rdata_atom_data(rd[3])+1, rdata_atom_data(rd[3])[0], str+len, buflen-len-1); } if(buflen > len + 1) str[len] = 0; } static struct rr* db_find_nsec3param(struct namedb* db, struct zone* z, struct rr* avoid_rr, int checkchain) { unsigned i; rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); if(!rrset) /* no NSEC3PARAM in mem */ return NULL; /* find first nsec3param we can support (SHA1, no flags) */ for(i=0; irr_count; i++) { rdata_atom_type* rd = rrset->rrs[i].rdatas; /* do not use the RR that is going to be deleted (in IXFR) */ if(&rrset->rrs[i] == avoid_rr) continue; if(rrset->rrs[i].rdata_count < 4) continue; if(rdata_atom_data(rd[0])[0] == NSEC3_SHA1_HASH && rdata_atom_data(rd[1])[0] == 0) { if(checkchain) { z->nsec3_param = &rrset->rrs[i]; if(!check_apex_soa(db, z, 1)) { char str[MAX_RDLENGTH*2+16]; nsec3param_to_str(z->nsec3_param, str, sizeof(str)); VERBOSITY(1, (LOG_WARNING, "zone %s NSEC3PARAM %s has broken chain, ignoring", domain_to_string(z->apex), str)); continue; /* don't use broken chain */ } } if(2 <= verbosity) { char str[MAX_RDLENGTH*2+16]; nsec3param_to_str(&rrset->rrs[i], str, sizeof(str)); VERBOSITY(2, (LOG_INFO, "rehash of zone %s with parameters %s", domain_to_string(z->apex), str)); } return &rrset->rrs[i]; } } return NULL; } void nsec3_find_zone_param(struct namedb* db, struct zone* zone, struct rr* avoid_rr, int checkchain) { /* avoid using the rr that is going to be deleted, avoid_rr */ zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, checkchain); } /* check params ok for one RR */ static int nsec3_rdata_params_ok(rdata_atom_type* prd, rdata_atom_type* rd) { return (rdata_atom_data(rd[0])[0] == rdata_atom_data(prd[0])[0] && /* hash algo */ rdata_atom_data(rd[2])[0] == rdata_atom_data(prd[2])[0] && /* iterations 0 */ rdata_atom_data(rd[2])[1] == rdata_atom_data(prd[2])[1] && /* iterations 1 */ rdata_atom_data(rd[3])[0] == rdata_atom_data(prd[3])[0] && /* salt length */ memcmp(rdata_atom_data(rd[3])+1, rdata_atom_data(prd[3])+1, rdata_atom_data(rd[3])[0]) == 0 ); } int nsec3_rr_uses_params(rr_type* rr, zone_type* zone) { if(!rr || rr->rdata_count < 4) return 0; return nsec3_rdata_params_ok(zone->nsec3_param->rdatas, rr->rdatas); } int nsec3_in_chain_count(domain_type* domain, zone_type* zone) { rrset_type* rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); unsigned i; int count = 0; if(!rrset || !zone->nsec3_param) return 0; /* no NSEC3s, none in the chain */ for(i=0; irr_count; i++) { if(nsec3_rr_uses_params(&rrset->rrs[i], zone)) count++; } return count; } struct domain* nsec3_chain_find_prev(struct zone* zone, struct domain* domain) { if(domain->nsec3 && domain->nsec3->nsec3_node.key) { /* see if there is a prev */ rbnode_type* r = rbtree_previous(&domain->nsec3->nsec3_node); if(r != RBTREE_NULL) { /* found a previous, which is not the root-node in * the prehash tree (and thus points to the tree) */ return (domain_type*)r->key; } } if(zone->nsec3_last && zone->nsec3_last != domain) return zone->nsec3_last; return NULL; } /** clear hash tree. Called from nsec3_clear_precompile() only. */ static void hash_tree_clear(rbtree_type* tree) { if(!tree) return; /* Previously (before commit 4ca61188b3f7a0e077476875810d18a5d439871f * and/or svn commit 4776) prehashes and corresponding rbtree nodes * were part of struct nsec3_domain_data. Clearing the hash_tree would * then mean setting the key value of the nodes to NULL to indicate * absence of the prehash. * But since prehash structs are separatly allocated, this is no longer * necessary as currently the prehash structs are simply recycled and * NULLed. * * rbnode_type* n; * for(n=rbtree_first(tree); n!=RBTREE_NULL; n=rbtree_next(n)) { * n->key = NULL; * } */ tree->count = 0; tree->root = RBTREE_NULL; } void nsec3_clear_precompile(struct namedb* db, zone_type* zone) { domain_type* walk; /* clear prehash items (there must not be items for other zones) */ prehash_clear(db->domains); /* clear trees */ hash_tree_clear(zone->nsec3tree); hash_tree_clear(zone->hashtree); hash_tree_clear(zone->wchashtree); hash_tree_clear(zone->dshashtree); /* wipe hashes */ /* wipe precompile */ walk = zone->apex; while(walk && domain_is_subdomain(walk, zone->apex)) { if(walk->nsec3) { if(nsec3_condition_hash(walk, zone)) { walk->nsec3->nsec3_node.key = NULL; walk->nsec3->nsec3_cover = NULL; walk->nsec3->nsec3_wcard_child_cover = NULL; walk->nsec3->nsec3_is_exact = 0; if (walk->nsec3->hash_wc) { region_recycle(db->domains->region, walk->nsec3->hash_wc, sizeof(nsec3_hash_wc_node_type)); walk->nsec3->hash_wc = NULL; } } if(nsec3_condition_dshash(walk, zone)) { walk->nsec3->nsec3_ds_parent_cover = NULL; walk->nsec3->nsec3_ds_parent_is_exact = 0; if (walk->nsec3->ds_parent_hash) { region_recycle(db->domains->region, walk->nsec3->ds_parent_hash, sizeof(nsec3_hash_node_type)); walk->nsec3->ds_parent_hash = NULL; } } } walk = domain_next(walk); } zone->nsec3_last = NULL; } /* see if domain name is part of (existing names in) the nsec3 zone */ int nsec3_domain_part_of_zone(domain_type* d, zone_type* z) { while(d) { if(d->is_apex) return (z->apex == d); /* zonecut, if right zone*/ d = d->parent; } return 0; } /* condition when a domain is precompiled */ int nsec3_condition_hash(domain_type* d, zone_type* z) { return d->is_existing && !domain_has_only_NSEC3(d, z) && nsec3_domain_part_of_zone(d, z) && !domain_is_glue(d, z); } /* condition when a domain is ds precompiled */ int nsec3_condition_dshash(domain_type* d, zone_type* z) { return d->is_existing && !domain_has_only_NSEC3(d, z) && (domain_find_rrset(d, z, TYPE_DS) || domain_find_rrset(d, z, TYPE_NS)) && d != z->apex && nsec3_domain_part_of_zone(d->parent, z); } zone_type* nsec3_tree_zone(namedb_type* db, domain_type* d) { /* see nsec3_domain_part_of_zone; domains part of zone that has * apex above them */ /* this does not use the rrset->zone pointer because there may be * no rrsets left at apex (no SOA), e.g. during IXFR */ while(d) { if(d->is_apex) { /* we can try a SOA if its present (faster than tree)*/ /* DNSKEY and NSEC3PARAM are also good indicators */ rrset_type *rrset; for (rrset = d->rrsets; rrset; rrset = rrset->next) if (rrset_rrtype(rrset) == TYPE_SOA || rrset_rrtype(rrset) == TYPE_DNSKEY || rrset_rrtype(rrset) == TYPE_NSEC3PARAM) return rrset->zone; return namedb_find_zone(db, domain_dname(d)); } d = d->parent; } return NULL; } zone_type* nsec3_tree_dszone(namedb_type* db, domain_type* d) { /* the DStree does not contain nodes with d==z->apex */ if(d->is_apex) d = d->parent; while (d) { if (d->is_apex) { zone_type *zone = NULL; for (rrset_type *rrset = d->rrsets; rrset; rrset = rrset->next) if (rrset_rrtype(rrset) == TYPE_SOA || rrset_rrtype(rrset) == TYPE_DNSKEY || rrset_rrtype(rrset) == TYPE_NSEC3PARAM) zone = rrset->zone; if (!zone) zone = namedb_find_zone(db, domain_dname(d)); if (zone && zone->dshashtree) return zone; } d = d->parent; } return NULL; } int nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t hashlen, domain_type** result) { rbnode_type* r = NULL; int exact; domain_type d; uint8_t n[48]; /* nsec3tree is sorted by b32 encoded domain name of the NSEC3 */ b32_ntop(hash, hashlen, (char*)(n+5), sizeof(n)-5); #ifdef USE_RADIX_TREE d.dname = (dname_type*)n; #else d.node.key = n; #endif n[0] = 34; /* name_size */ n[1] = 2; /* label_count */ n[2] = 0; /* label_offset[0] */ n[3] = 0; /* label_offset[1] */ n[4] = 32; /* label-size[0] */ assert(result); assert(zone->nsec3_param && zone->nsec3tree); exact = rbtree_find_less_equal(zone->nsec3tree, &d, &r); if(r) { *result = (domain_type*)r->key; } else { *result = zone->nsec3_last; } return exact; } void nsec3_precompile_domain(struct namedb* db, struct domain* domain, struct zone* zone, region_type* tmpregion) { domain_type* result = 0; int exact; allocate_domain_nsec3(db->domains, domain); /* hash it */ nsec3_lookup_hash_and_wc(db->region, zone, domain_dname(domain), domain, tmpregion); /* add into tree */ zone_add_domain_in_hash_tree(db->region, &zone->hashtree, cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node); zone_add_domain_in_hash_tree(db->region, &zone->wchashtree, cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node); /* lookup in tree cover ptr (or exact) */ exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash, sizeof(domain->nsec3->hash_wc->hash.hash), &result); domain->nsec3->nsec3_cover = result; if(exact) domain->nsec3->nsec3_is_exact = 1; else domain->nsec3->nsec3_is_exact = 0; /* find cover for *.domain for wildcard denial */ (void)nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash, sizeof(domain->nsec3->hash_wc->wc.hash), &result); domain->nsec3->nsec3_wcard_child_cover = result; } void nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, struct zone* zone) { domain_type* result = 0; int exact; allocate_domain_nsec3(db->domains, domain); /* hash it : it could have different hash parameters then the other hash for this domain name */ nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain); /* lookup in tree cover ptr (or exact) */ exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash, sizeof(domain->nsec3->ds_parent_hash->hash), &result); domain->nsec3->nsec3_ds_parent_is_exact = exact != 0; domain->nsec3->nsec3_ds_parent_cover = result; /* add into tree */ zone_add_domain_in_hash_tree(db->region, &zone->dshashtree, cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node); } static void parse_nsec3_name(const dname_type* dname, uint8_t* hash, size_t buflen) { /* first label must be the match, */ size_t lablen = (buflen-1) * 8 / 5; const uint8_t* wire = dname_name(dname); assert(lablen == 32 && buflen == NSEC3_HASH_LEN+1); /* labels of length 32 for SHA1, and must have space+1 for convert */ if(wire[0] != lablen) { /* not NSEC3 */ memset(hash, 0, buflen); return; } (void)b32_pton((char*)wire+1, hash, buflen); } void nsec3_precompile_nsec3rr(namedb_type* db, struct domain* domain, struct zone* zone) { allocate_domain_nsec3(db->domains, domain); /* add into nsec3tree */ zone_add_domain_in_hash_tree(db->region, &zone->nsec3tree, cmp_nsec3_tree, domain, &domain->nsec3->nsec3_node); /* fixup the last in the zone */ if(rbtree_last(zone->nsec3tree)->key == domain) { zone->nsec3_last = domain; } } void nsec3_precompile_newparam(namedb_type* db, zone_type* zone) { region_type* tmpregion = region_create(xalloc, free); domain_type* walk; time_t s = time(NULL); unsigned long n = 0, c = 0; /* add nsec3s of chain to nsec3tree */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk = domain_next(walk)) { n++; if(nsec3_in_chain_count(walk, zone) != 0) { nsec3_precompile_nsec3rr(db, walk, zone); } } /* hash and precompile zone */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk = domain_next(walk)) { if(nsec3_condition_hash(walk, zone)) { nsec3_precompile_domain(db, walk, zone, tmpregion); region_free_all(tmpregion); } if(nsec3_condition_dshash(walk, zone)) nsec3_precompile_domain_ds(db, walk, zone); if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > s + ZONEC_PCT_TIME) { s = time(NULL); VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%", zone->opts->name, (n==0)?0:(int)(c*((unsigned long)100)/n))); } } region_destroy(tmpregion); } void prehash_zone_complete(struct namedb* db, struct zone* zone) { /* robust clear it */ nsec3_clear_precompile(db, zone); /* find zone settings */ assert(db && zone); nsec3_find_zone_param(db, zone, NULL, 1); if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; return; } nsec3_zone_trees_create(db->region, zone); nsec3_precompile_newparam(db, zone); } static void init_lookup_key_hash_tree(domain_type* d, uint8_t* hash) { memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); } static void init_lookup_key_wc_tree(domain_type* d, uint8_t* hash) { memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); } static void init_lookup_key_ds_tree(domain_type* d, uint8_t* hash) { memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); } /* find first in the tree and true if the first to process it */ static int process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p, void (*init)(domain_type*, uint8_t*)) { domain_type d; struct nsec3_domain_data n; nsec3_hash_wc_node_type hash_wc; nsec3_hash_node_type ds_parent_hash; if(!tree) { *p = RBTREE_NULL; return 0; } hash_wc.hash.node.key = NULL; hash_wc.wc.node.key = NULL; n.hash_wc = &hash_wc; ds_parent_hash.node.key = NULL; n.ds_parent_hash = &ds_parent_hash; d.nsec3 = &n; init(&d, hash); if(rbtree_find_less_equal(tree, &d, p)) { /* found an exact match */ return 1; } if(!*p) /* before first, go from first */ *p = rbtree_first(tree); /* the inexact, smaller, match we found, does not itself need to * be edited */ else *p = rbtree_next(*p); /* if this becomes NULL, nothing to do */ return 0; } /* set end pointer if possible */ static void process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p, void (*init)(domain_type*, uint8_t*)) { domain_type d; struct nsec3_domain_data n; nsec3_hash_wc_node_type hash_wc; nsec3_hash_node_type ds_parent_hash; if(!tree) { *p = RBTREE_NULL; return; } hash_wc.hash.node.key = NULL; hash_wc.wc.node.key = NULL; n.hash_wc = &hash_wc; ds_parent_hash.node.key = NULL; n.ds_parent_hash = &ds_parent_hash; d.nsec3 = &n; init(&d, hash); if(rbtree_find_less_equal(tree, &d, p)) { /* an exact match, fine, because this one does not get * processed */ return; } /* inexact element, but if NULL, until first element in tree */ if(!*p) { *p = rbtree_first(tree); return; } /* inexact match, use next element, if possible, the smaller * element is part of the range */ *p = rbtree_next(*p); /* if next returns null, we go until the end of the tree */ } /* prehash domains in hash range start to end */ static void process_range(zone_type* zone, domain_type* start, domain_type* end, domain_type* nsec3) { /* start NULL means from first in tree */ /* end NULL means to last in tree */ rbnode_type *p = RBTREE_NULL, *pwc = RBTREE_NULL, *pds = RBTREE_NULL; rbnode_type *p_end = RBTREE_NULL, *pwc_end = RBTREE_NULL, *pds_end = RBTREE_NULL; /* because the nodes are on the prehashlist, the domain->nsec3 is * already allocated, and we need not allocate it here */ /* set start */ if(start) { uint8_t hash[NSEC3_HASH_LEN+1]; parse_nsec3_name(domain_dname(start), hash, sizeof(hash)); /* if exact match on first, set is_exact */ if(process_first(zone->hashtree, hash, &p, init_lookup_key_hash_tree)) { ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 1; p = rbtree_next(p); } (void)process_first(zone->wchashtree, hash, &pwc, init_lookup_key_wc_tree); if(process_first(zone->dshashtree, hash, &pds, init_lookup_key_ds_tree)){ ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_cover = nsec3; ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_is_exact = 1; pds = rbtree_next(pds); } } else { if(zone->hashtree) p = rbtree_first(zone->hashtree); if(zone->wchashtree) pwc = rbtree_first(zone->wchashtree); if(zone->dshashtree) pds = rbtree_first(zone->dshashtree); } /* set end */ if(end) { uint8_t hash[NSEC3_HASH_LEN+1]; parse_nsec3_name(domain_dname(end), hash, sizeof(hash)); process_end(zone->hashtree, hash, &p_end, init_lookup_key_hash_tree); process_end(zone->wchashtree, hash, &pwc_end, init_lookup_key_wc_tree); process_end(zone->dshashtree, hash, &pds_end, init_lookup_key_ds_tree); } /* precompile */ while(p != RBTREE_NULL && p != p_end) { ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 0; p = rbtree_next(p); } while(pwc != RBTREE_NULL && pwc != pwc_end) { ((domain_type*)(pwc->key))->nsec3-> nsec3_wcard_child_cover = nsec3; pwc = rbtree_next(pwc); } while(pds != RBTREE_NULL && pds != pds_end) { ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_cover = nsec3; ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_is_exact = 0; pds = rbtree_next(pds); } } /* prehash a domain from the prehash list */ static void process_prehash_domain(domain_type* domain, zone_type* zone) { /* in the hashtree, wchashtree, dshashtree walk through to next NSEC3 * and set precompile pointers to point to this domain (or is_exact), * the first domain can be is_exact. If it is the last NSEC3, also * process the initial part (before the first) */ rbnode_type* nx; /* this domain is part of the prehash list and therefore the * domain->nsec3 is allocated and need not be allocated here */ assert(domain->nsec3 && domain->nsec3->nsec3_node.key); nx = rbtree_next(&domain->nsec3->nsec3_node); if(nx != RBTREE_NULL) { /* process until next nsec3 */ domain_type* end = (domain_type*)nx->key; process_range(zone, domain, end, domain); } else { /* first is root, but then comes the first nsec3 */ domain_type* first = (domain_type*)(rbtree_first( zone->nsec3tree)->key); /* last in zone */ process_range(zone, domain, NULL, domain); /* also process before first in zone */ process_range(zone, NULL, first, domain); } } void prehash_zone(struct namedb* db, struct zone* zone) { domain_type* d; if(!zone->nsec3_param) { prehash_clear(db->domains); return; } if(!check_apex_soa(db, zone, 1)) { /* the zone fails apex soa check, prehash complete may * detect other valid chains */ prehash_clear(db->domains); prehash_zone_complete(db, zone); return; } /* process prehash list */ for(d = db->domains->prehash_list; d; d = d->nsec3->prehash_next) { process_prehash_domain(d, zone); } /* clear prehash list */ prehash_clear(db->domains); if(!check_apex_soa(db, zone, 0)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; } } /* add the NSEC3 rrset to the query answer at the given domain */ static void nsec3_add_rrset(struct query* query, struct answer* answer, rr_section_type section, struct domain* domain) { if(domain) { rrset_type* rrset = domain_find_rrset(domain, query->zone, TYPE_NSEC3); if(rrset) answer_add_rrset(answer, section, domain, rrset); } } /* this routine does hashing at query-time. slow. */ static void nsec3_add_nonexist_proof(struct query* query, struct answer* answer, struct domain* encloser, const dname_type* qname) { uint8_t hash[NSEC3_HASH_LEN]; const dname_type* to_prove; domain_type* cover=0; assert(encloser); /* if query=a.b.c.d encloser=c.d. then proof needed for b.c.d. */ /* if query=a.b.c.d encloser=*.c.d. then proof needed for b.c.d. */ to_prove = dname_partial_copy(query->region, qname, dname_label_match_count(qname, domain_dname(encloser))+1); /* generate proof that one label below closest encloser does not exist */ nsec3_hash_and_store(query->zone, to_prove, hash); if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover)) { /* exact match, hash collision */ domain_type* walk; char hashbuf[512]; char reversebuf[512]; (void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf)); snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)"); walk = query->zone->apex; while(walk) { if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) { snprintf(reversebuf, sizeof(reversebuf), "%s %s", domain_to_string(walk), walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match"); if(walk->nsec3->nsec3_is_exact) break; } if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) { snprintf(reversebuf, sizeof(reversebuf), "%s %s", domain_to_string(walk), walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match"); if(walk->nsec3->nsec3_ds_parent_is_exact) break; } walk = domain_next(walk); } /* the hashed name of the query corresponds to an existing name. */ VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s", dname_to_string(to_prove, NULL), hashbuf, reversebuf)); RCODE_SET(query->packet, RCODE_SERVFAIL); /* RFC 8914 - Extended DNS Errors * 4.21. Extended DNS Error Code 0 - Other */ ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede, EDE_OTHER, "NSEC3 hash collision"); return; } else { /* cover proves the qname does not exist */ nsec3_add_rrset(query, answer, AUTHORITY_SECTION, cover); } } static void nsec3_add_closest_encloser_proof( struct query* query, struct answer* answer, struct domain* closest_encloser, const dname_type* qname) { if(!closest_encloser) return; /* prove that below closest encloser nothing exists */ nsec3_add_nonexist_proof(query, answer, closest_encloser, qname); /* proof that closest encloser exists */ if(closest_encloser->nsec3 && closest_encloser->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover); } void nsec3_answer_wildcard(struct query *query, struct answer *answer, struct domain *wildcard, const dname_type* qname) { if(!wildcard) return; if(!query->zone->nsec3_param) return; nsec3_add_nonexist_proof(query, answer, wildcard, qname); } static void nsec3_add_ds_proof(struct query *query, struct answer *answer, struct domain *domain, int delegpt) { /* assert we are above the zone cut */ assert(domain != query->zone->apex); if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) { /* use NSEC3 record from above the zone cut. */ nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_ds_parent_cover); } else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact && nsec3_domain_part_of_zone(domain->nsec3->nsec3_cover, query->zone)) { nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_cover); } else { /* prove closest provable encloser */ domain_type* par = domain->parent; domain_type* prev_par = 0; while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact)) { prev_par = par; par = par->parent; } assert(par); /* parent zone apex must be provable, thus this ends */ if(!par->nsec3) return; nsec3_add_rrset(query, answer, AUTHORITY_SECTION, par->nsec3->nsec3_cover); /* we took several steps to go to the provable parent, so the one below it has no exact nsec3, disprove it. disprove is easy, it has a prehashed cover ptr. */ if(prev_par && prev_par->nsec3) { assert(prev_par != domain && !prev_par->nsec3->nsec3_is_exact); nsec3_add_rrset(query, answer, AUTHORITY_SECTION, prev_par->nsec3->nsec3_cover); } else { /* the exact case was handled earlier, so this is * with a closest-encloser proof, if in the part * before the else the closest encloser proof is done, * then we do not need to add a DS here because * the optout proof is already complete. If not, * we add the nsec3 here to complete the closest * encloser proof with a next closer */ /* add optout range from parent zone */ /* note: no check of optout bit, resolver checks it */ if(domain->nsec3) { nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_ds_parent_cover); } } } } void nsec3_answer_nodata(struct query* query, struct answer* answer, struct domain* original) { if(!query->zone->nsec3_param) return; /* nodata when asking for secure delegation */ if(query->qtype == TYPE_DS) { if(original == query->zone->apex) { /* DS at zone apex, but server not authoritative for parent zone */ /* so answer at the child zone level */ if(original->nsec3 && original->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); return; } /* query->zone must be the parent zone */ nsec3_add_ds_proof(query, answer, original, 0); /* if the DS is from a wildcard match */ if (original==original->wildcard_child_closest_match && label_is_wildcard(dname_name(domain_dname(original)))) { /* denial for wildcard is already there */ /* add parent proof to have a closest encloser proof for wildcard parent */ /* in other words: nsec3 matching closest encloser */ if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->parent->nsec3->nsec3_cover); } } /* the nodata is result from a wildcard match */ else if (original==original->wildcard_child_closest_match && label_is_wildcard(dname_name(domain_dname(original)))) { /* denial for wildcard is already there */ /* add parent proof to have a closest encloser proof for wildcard parent */ /* in other words: nsec3 matching closest encloser */ if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->parent->nsec3->nsec3_cover); /* proof for wildcard itself */ /* in other words: nsec3 matching source of synthesis */ if(original->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); } else { /* add nsec3 to prove rrset does not exist */ if(original->nsec3) { if(!original->nsec3->nsec3_is_exact) { /* go up to an existing parent */ while(original->parent && original->parent->nsec3 && !original->parent->nsec3->nsec3_is_exact) original = original->parent; } nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); if(!original->nsec3->nsec3_is_exact) { if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->parent->nsec3->nsec3_cover); } } } } void nsec3_answer_delegation(struct query *query, struct answer *answer) { if(!query->zone->nsec3_param) return; nsec3_add_ds_proof(query, answer, query->delegation_domain, 1); } int domain_has_only_NSEC3(struct domain* domain, struct zone* zone) { /* check for only NSEC3/RRSIG */ rrset_type* rrset = domain->rrsets; int nsec3_seen = 0; while(rrset) { if(!zone || rrset->zone == zone) { if(rrset->rrs[0].type == TYPE_NSEC3) nsec3_seen = 1; else if(rrset->rrs[0].type != TYPE_RRSIG) return 0; } rrset = rrset->next; } return nsec3_seen; } void nsec3_answer_authoritative(struct domain** match, struct query *query, struct answer *answer, struct domain* closest_encloser, const dname_type* qname) { if(!query->zone->nsec3_param) return; assert(match); /* there is a match, this has 1 RRset, which is NSEC3, but qtype is not. */ /* !is_existing: no RR types exist at the QNAME, nor at any descendant of QNAME */ if(*match && !(*match)->is_existing && #if 0 query->qtype != TYPE_NSEC3 && #endif domain_has_only_NSEC3(*match, query->zone)) { /* act as if the NSEC3 domain did not exist, name error */ *match = 0; /* all nsec3s are directly below the apex, that is closest encloser */ if(query->zone->apex->nsec3 && query->zone->apex->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex->nsec3->nsec3_cover); /* disprove the nsec3 record. */ if(closest_encloser->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover); /* disprove a wildcard */ if(query->zone->apex->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex->nsec3->nsec3_wcard_child_cover); if (domain_wildcard_child(query->zone->apex)) { /* wildcard exists below the domain */ /* wildcard and nsec3 domain clash. server failure. */ RCODE_SET(query->packet, RCODE_SERVFAIL); /* RFC 8914 - Extended DNS Errors * 4.21. Extended DNS Error Code 0 - Other */ ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede, EDE_OTHER, "Wildcard and NSEC3 domain clash"); } return; } else if(*match && (*match)->is_existing && #if 0 query->qtype != TYPE_NSEC3 && #endif (domain_has_only_NSEC3(*match, query->zone) || !domain_find_any_rrset(*match, query->zone))) { /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */ nsec3_answer_nodata(query, answer, *match); return; } if(!*match) { /* name error, domain does not exist */ nsec3_add_closest_encloser_proof(query, answer, closest_encloser, qname); if(closest_encloser->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_wcard_child_cover); } } #endif /* NSEC3 */ nsd-4.12.0/nsd.h0000644000175000017500000003152115002373054012734 0ustar mozziemozzie/* * nsd.h -- nsd(8) definitions and prototypes * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef NSD_H #define NSD_H #include #include #ifndef IFNAMSIZ # ifdef IF_NAMESIZE # define IFNAMSIZ IF_NAMESIZE # else # define IFNAMSIZ 16 # endif #endif #ifdef HAVE_OPENSSL_SSL_H #include #endif #include "dns.h" #include "edns.h" #include "bitset.h" struct netio_handler; struct nsd_options; struct udb_base; struct daemon_remote; #ifdef USE_METRICS struct daemon_metrics; #endif /* USE_METRICS */ #ifdef USE_DNSTAP struct dt_collector; #endif /* The NSD runtime states and NSD ipc command values */ #define NSD_RUN 0 #define NSD_RELOAD 1 #define NSD_SHUTDOWN 2 #define NSD_STATS 3 #define NSD_REAP_CHILDREN 4 #define NSD_QUIT 5 /* * RELOAD_REQ is sent when parent receives a SIGHUP and tells * xfrd that it wants to initiate a reload (and thus task swap). */ #define NSD_RELOAD_REQ 7 /* * RELOAD_DONE is sent at the end of a reload pass. * xfrd then knows that reload phase is over. */ #define NSD_RELOAD_DONE 8 /* * QUIT_SYNC is sent to signify a synchronisation of ipc * channel content during reload */ #define NSD_QUIT_SYNC 9 /* * QUIT_CHILD is sent at exit, to make sure the child has exited so that * port53 is free when all of nsd's processes have exited at shutdown time */ #define NSD_QUIT_CHILD 11 /* * This is the exit code of a nsd "new master" child process to indicate to * the master process that some zones failed verification and that it should * reload again, reprocessing the difffiles. The master process will resend * the command to xfrd so it will not reload from xfrd yet. */ #define NSD_RELOAD_FAILED 14 #define NSD_SERVER_MAIN 0x0U #define NSD_SERVER_UDP 0x1U #define NSD_SERVER_TCP 0x2U #define NSD_SERVER_BOTH (NSD_SERVER_UDP | NSD_SERVER_TCP) #ifdef INET6 #define DEFAULT_AI_FAMILY AF_UNSPEC #else #define DEFAULT_AI_FAMILY AF_INET #endif #ifdef BIND8_STATS /* Counter for statistics */ typedef unsigned long stc_type; #define LASTELEM(arr) (sizeof(arr) / sizeof(arr[0]) - 1) #define STATUP(nsd, stc) nsd->st->stc++ /* #define STATUP2(nsd, stc, i) ((i) <= (LASTELEM(nsd->st->stc) - 1)) ? nsd->st->stc[(i)]++ : \ nsd->st.stc[LASTELEM(nsd->st->stc)]++ */ #define STATUP2(nsd, stc, i) nsd->st->stc[(i) <= (LASTELEM(nsd->st->stc) - 1) ? i : LASTELEM(nsd->st->stc)]++ #else /* BIND8_STATS */ #define STATUP(nsd, stc) /* Nothing */ #define STATUP2(nsd, stc, i) /* Nothing */ #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS /* increment zone statistic, checks if zone-nonNULL and zone array bounds */ #define ZTATUP(nsd, zone, stc) ( \ (zone && zone->zonestatid < nsd->zonestatsizenow) ? \ nsd->zonestatnow[zone->zonestatid].stc++ \ : 0) #define ZTATUP2(nsd, zone, stc, i) ( \ (zone && zone->zonestatid < nsd->zonestatsizenow) ? \ (nsd->zonestatnow[zone->zonestatid].stc[(i) <= (LASTELEM(nsd->zonestatnow[zone->zonestatid].stc) - 1) ? i : LASTELEM(nsd->zonestatnow[zone->zonestatid].stc)]++ ) \ : 0) #else /* USE_ZONE_STATS */ #define ZTATUP(nsd, zone, stc) /* Nothing */ #define ZTATUP2(nsd, zone, stc, i) /* Nothing */ #endif /* USE_ZONE_STATS */ #ifdef BIND8_STATS /* Data structure to keep track of statistics */ struct nsdst { time_t boot; stc_type qtype[257]; /* Counters per qtype */ stc_type qclass[4]; /* Class IN or Class CH or other */ stc_type qudp, qudp6; /* Number of queries udp and udp6 */ stc_type ctcp, ctcp6; /* Number of tcp and tcp6 connections */ stc_type ctls, ctls6; /* Number of tls and tls6 connections */ stc_type rcode[17], opcode[6]; /* Rcodes & opcodes */ /* Dropped, truncated, queries for nonconfigured zone, tx errors */ stc_type dropped, truncated, wrongzone, txerr, rxerr; stc_type edns, ednserr, raxfr, nona, rixfr; uint64_t db_disk, db_mem; }; #endif /* BIND8_STATS */ #define NSD_SOCKET_IS_OPTIONAL (1<<0) #define NSD_BIND_DEVICE (1<<1) struct nsd_addrinfo { int ai_flags; int ai_family; int ai_socktype; socklen_t ai_addrlen; struct sockaddr_storage ai_addr; }; struct nsd_socket { struct nsd_addrinfo addr; int s; int flags; struct nsd_bitset *servers; char device[IFNAMSIZ]; int fib; }; struct nsd_child { #ifdef HAVE_CPUSET_T /* Processor(s) that child process must run on (if applicable). */ cpuset_t *cpuset; #endif /* The type of child process (UDP or TCP handler). */ int kind; /* 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. */ int child_fd; /* * Socket used by the child process to receive commands and * send responses from/to the parent process. */ int parent_fd; /* * IPC info, buffered for nonblocking writes to the child */ uint8_t need_to_send_STATS, need_to_send_QUIT; uint8_t need_to_exit, has_exited; /* * The handler for handling the commands from the child. */ struct netio_handler* handler; #ifdef BIND8_STATS stc_type query_count; #endif }; #define NSD_COOKIE_HISTORY_SIZE 2 #define NSD_COOKIE_SECRET_SIZE 16 struct cookie_secret { /** cookie secret */ uint8_t cookie_secret[NSD_COOKIE_SECRET_SIZE]; }; typedef struct cookie_secret cookie_secret_type; typedef cookie_secret_type cookie_secrets_type[NSD_COOKIE_HISTORY_SIZE]; enum cookie_secrets_source { COOKIE_SECRETS_NONE = 0, COOKIE_SECRETS_GENERATED = 1, COOKIE_SECRETS_FROM_FILE = 2, COOKIE_SECRETS_FROM_CONFIG = 3 }; typedef enum cookie_secrets_source cookie_secrets_source_type; /* NSD configuration and run-time variables */ typedef struct nsd nsd_type; struct nsd { /* * Global region that is not deallocated until NSD shuts down. */ region_type *region; /* Run-time variables */ pid_t pid; volatile sig_atomic_t mode; volatile sig_atomic_t signal_hint_reload_hup; volatile sig_atomic_t signal_hint_reload; volatile sig_atomic_t signal_hint_child; volatile sig_atomic_t signal_hint_quit; volatile sig_atomic_t signal_hint_shutdown; volatile sig_atomic_t signal_hint_stats; volatile sig_atomic_t signal_hint_statsusr; volatile sig_atomic_t quit_sync_done; unsigned server_kind; struct namedb *db; int debug; size_t child_count; struct nsd_child *children; int restart_children; int reload_failed; /* NULL if this is the parent process. */ struct nsd_child *this_child; /* mmaps with data exchange from xfrd and reload */ struct udb_base* task[2]; int mytask; /* the base used by this (child)process */ struct event_base* event_base; /* the server_region used by this (child)process */ region_type* server_region; struct netio_handler* xfrd_listener; struct daemon_remote* rc; #ifdef USE_METRICS struct daemon_metrics* metrics; #endif /* USE_METRICS */ /* Configuration */ const char *pidfile; const char *log_filename; const char *username; uid_t uid; gid_t gid; const char *chrootdir; const char *version; const char *identity; uint16_t nsid_len; unsigned char *nsid; uint8_t file_rotation_ok; #ifdef HAVE_CPUSET_T int use_cpu_affinity; cpuset_t* cpuset; cpuset_t* xfrd_cpuset; #endif /* number of interfaces */ size_t ifs; /* non0 if so_reuseport is in use, if so, tcp, udp array increased */ int reuseport; /* TCP specific configuration (array size ifs) */ struct nsd_socket* tcp; /* UDP specific configuration (array size ifs) */ struct nsd_socket* udp; /* Interfaces used for zone verification */ size_t verify_ifs; struct nsd_socket *verify_tcp; struct nsd_socket *verify_udp; struct zone *next_zone_to_verify; size_t verifier_count; /* Number of active verifiers */ size_t verifier_limit; /* Maximum number of active verifiers */ int verifier_pipe[2]; /* Pipe to trigger verifier exit handler */ struct verifier *verifiers; edns_data_type edns_ipv4; #if defined(INET6) edns_data_type edns_ipv6; #endif int maximum_tcp_count; int current_tcp_count; int tcp_query_count; int tcp_timeout; int tcp_mss; int outgoing_tcp_mss; size_t ipv4_edns_size; size_t ipv6_edns_size; #ifdef BIND8_STATS /* statistics for this server */ struct nsdst* st; /* Produce statistics dump every st_period seconds */ int st_period; /* per zone stats, each an array per zone-stat-idx, stats per zone is * add of [0][zoneidx] and [1][zoneidx]. */ struct nsdst* zonestat[2]; /* fd for zonestat mapping (otherwise mmaps cannot be shared between * processes and resized) */ int zonestatfd[2]; /* filenames */ char* zonestatfname[2]; /* size of the mmapped zone stat array (number of array entries) */ size_t zonestatsize[2], zonestatdesired, zonestatsizenow; /* current zonestat array to use */ struct nsdst* zonestatnow; /* filenames for stat file mappings */ char* statfname; /* fd for stat mapping (otherwise mmaps cannot be shared between * processes and resized) */ int statfd; /* statistics array, of size child_count*2, twice for old and new * server processes. */ struct nsdst* stat_map; /* statistics array of size child_count, twice */ struct nsdst* stats_per_child[2]; /* current stats_per_child array that is in use for the child set */ int stat_current; /* start value for per process statistics printout, to clear it */ struct nsdst stat_proc; #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* the dnstap collector process info */ struct dt_collector* dt_collector; /* the pipes from server processes to the dt_collector, * arrays of size child_count * 2. Kept open for (re-)forks. */ int *dt_collector_fd_send, *dt_collector_fd_recv; /* the pipes from server processes to the dt_collector. Initially * these point halfway into dt_collector_fd_send, but during reload * the pointer is swapped with dt_collector_fd_send in order to * to prevent writing to the dnstap collector by old serve childs * simultaneous with new serve childs. */ int *dt_collector_fd_swap; #endif /* USE_DNSTAP */ /* the pipes from the serve processes to xfrd, for passing through * NOTIFY messages, arrays of size child_count * 2. * Kept open for (re-)forks. */ int *serve2xfrd_fd_send, *serve2xfrd_fd_recv; /* the pipes from the serve processes to the xfrd. Initially * these point halfway into serve2xfrd_fd_send, but during reload * the pointer is swapped with serve2xfrd_fd_send so that only one * serve child will write to the same fd simultaneously. */ int *serve2xfrd_fd_swap; /* ratelimit for errors, time value */ time_t err_limit_time; /* ratelimit for errors, packet count */ unsigned int err_limit_count; /* do answer with server cookie when request contained cookie option */ int do_answer_cookie; /* how many cookies are there in the cookies array */ size_t cookie_count; /* keep track of the last `NSD_COOKIE_HISTORY_SIZE` * cookies as per rfc requirement .*/ cookie_secrets_type cookie_secrets; /* From where came the configured cookies */ cookie_secrets_source_type cookie_secrets_source; /* The cookie secrets filename when they came from file; when * cookie_secrets_source == COOKIE_SECRETS_FROM_FILE */ char* cookie_secrets_filename; struct nsd_options* options; #ifdef HAVE_SSL /* TLS specific configuration */ SSL_CTX *tls_ctx; SSL_CTX *tls_auth_ctx; #endif }; extern struct nsd nsd; /* nsd.c */ pid_t readpid(const char *file); int writepid(struct nsd *nsd); void unlinkpid(const char* file, const char* username); void sig_handler(int sig); void bind8_stats(struct nsd *nsd); /* server.c */ int server_init(struct nsd *nsd); int server_prepare(struct nsd *nsd); void server_main(struct nsd *nsd); void server_child(struct nsd *nsd); void server_shutdown(struct nsd *nsd) ATTR_NORETURN; void server_close_all_sockets(struct nsd_socket sockets[], size_t n); const char* nsd_event_vs(void); const char* nsd_event_method(void); struct event_base* nsd_child_event_base(void); void service_remaining_tcp(struct nsd* nsd); /* extra domain numbers for temporary domains */ #define EXTRA_DOMAIN_NUMBERS 1024 #define SLOW_ACCEPT_TIMEOUT 2 /* in seconds */ /* ratelimit for error responses */ #define ERROR_RATELIMIT 100 /* qps */ /* allocate zonestat structures */ void server_zonestat_alloc(struct nsd* nsd); /* remap the mmaps for zonestat isx, to bytesize sz. Caller has to set * the zonestatsize */ void zonestat_remap(struct nsd* nsd, int idx, size_t sz); /* allocate stat structures */ void server_stat_alloc(struct nsd* nsd); /* free stat mmap file, unlinks it */ void server_stat_free(struct nsd* nsd); /* allocate and init xfrd variables */ void server_prepare_xfrd(struct nsd *nsd); /* start xfrdaemon (again) */ void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active); /* send SOA serial numbers to xfrd */ void server_send_soa_xfrd(struct nsd *nsd, int shortsoa); #ifdef HAVE_SSL SSL_CTX* server_tls_ctx_setup(char* key, char* pem, char* verifypem); SSL_CTX* server_tls_ctx_create(struct nsd *nsd, char* verifypem, char* ocspfile); void perform_openssl_init(void); #endif ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout); #endif /* NSD_H */ nsd-4.12.0/nsd.conf.sample.in0000644000175000017500000004760615002373054015332 0ustar mozziemozzie# # nsd.conf -- the NSD(8) configuration file, nsd.conf(5). # # Copyright (c) 2001-2011, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # This is a comment. # Sample configuration file # include: "file" # include that file's text over here. Globbed, "*.conf" # options for the nsd server server: # Number of NSD servers to fork. Put the number of CPUs to use here. # server-count: 1 # Set overall CPU affinity for NSD processes on Linux and FreeBSD. # Any server/xfrd CPU affinity value will be masked by this value. # cpu-affinity: 0 1 2 3 # Bind NSD server(s), configured by server-count (1-based), to a # dedicated core. Single core affinity improves L1/L2 cache hits and # reduces pipeline stalls/flushes. # # server-1-cpu-affinity: 0 # server-2-cpu-affinity: 1 # ... # server--cpu-affinity: 2 # Bind xfrd to a dedicated core. # xfrd-cpu-affinity: 3 # 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 # # IP addresses can be configured per-server to avoid waking up more # than one server when a packet comes in (thundering herd problem) or # to partition sockets across servers to improve select/poll # performance. # # ip-address: 1.2.3.4 servers="1-2 3" # ip-address: 1.2.3.4@5678 servers="4-5 6" # # When several interfaces are configured to listen on the same subnet, # care must be taken to ensure responses go out the same interface the # corresponding query came in on to avoid problems with load balancers # and VLAN tagged interfaces. Linux offers the SO_BINDTODEVICE socket # option to bind a socket to a specified device. For FreeBSD, to # achieve the same result, specify the routing table to use after the # IP address to use SO_SETFIB. # # Complement with socket partitioning and CPU affinity for attack # mitigation benefits. i.e. only a single core is maxed out if a # specific IP address is under attack. # # ip-address: 1.2.3.4 setfib=0 bindtodevice=yes # ip-address: 1.2.3.5@6789 setfib=1 bindtodevice=yes # Allow binding to non local addresses. Default no. # ip-transparent: no # Allow binding to addresses that are down. Default no. # ip-freebind: no # Use SO_REUSEPORT socket option for performance. Default no. # reuseport: no # override maximum socket send buffer size. Default of 0 results in # send buffer size being set to 1048576 (bytes). # send-buffer-size: 1048576 # override maximum socket receive buffer size. Default of 0 results in # receive buffer size being set to 1048576 (bytes). # receive-buffer-size: 1048576 # enable debug mode, does not fork daemon process into the background. # debug-mode: no # listen on IPv4 connections # do-ip4: yes # listen on IPv6 connections # do-ip6: yes # port to answer queries on. default is 53. # port: 53 # Verbosity level. # verbosity: 0 # After binding socket, drop user privileges. # can be a username, id or id.gid. # username: @user@ # Run NSD in a chroot-jail. # make sure to have pidfile reachable from there. # by default, no chroot-jail is used. # chroot: "@configdir@" # The directory for zonefile: files. The daemon chdirs here. # zonesdir: "@zonesdir@" # the list of dynamically added zones. # zonelistfile: "@zonelistfile@" # log messages to file. Default to stderr and syslog (with # facility LOG_DAEMON). stderr disappears when daemon goes to bg. # logfile: "@logfile@" # log only to syslog. # log-only-syslog: no # File to store pid for nsd in. # pidfile: "@pidfile@" # The file where secondary zone refresh and expire timeouts are kept. # If you delete this file, all secondary zones are forced to be # 'refreshing' (as if nsd got a notify). Set to "" to disable. # xfrdfile: "@xfrdfile@" # The directory where zone transfers are stored, in a subdir of it. # xfrdir: "@xfrdir@" # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries # hide-version: no # don't answer HOSTNAME.BIND and ID.SERVER CHAOS class queries # hide-identity: no # Drop UPDATE queries # drop-updates: no # version string the server responds with for chaos queries. # default is 'NSD x.y.z' with the server's version number. # version: "NSD" # identify the server (CH TXT ID.SERVER entry). # identity: "unidentified server" # NSID identity (hex string, or "ascii_somestring"). default disabled. # nsid: "aabbccdd" # Maximum number of concurrent TCP connections per server. # tcp-count: 100 # Accept (and immediately close) TCP connections after maximum number # of connections is reached to prevent kernel connection queue from # growing. # tcp-reject-overflow: no # Maximum number of queries served on a single TCP connection. # By default 0, which means no maximum. # tcp-query-count: 0 # Override the default (120 seconds) TCP timeout. # tcp-timeout: 120 # Maximum segment size (MSS) of TCP socket on which the server # responds to queries. Default is 0, system default MSS. # tcp-mss: 0 # Maximum segment size (MSS) of TCP socket for outgoing AXFR request. # Default is 0, system default MSS. # outgoing-tcp-mss: 0 # reduce these settings to save memory for NSD, to about # xfrd-tcp-max: 32 and xfrd-tcp-pipeline: 128, also rrl-size: 1000 # other memory is determined by server-count, tcp-count and zone data # max number of sockets used for outgoing zone transfers. # Increase this to allow more sockets for zone transfers. # xfrd-tcp-max: 128 # max number of simultaneous outgoing zone transfers over one socket. # xfrd-tcp-pipeline: 128 # Preferred EDNS buffer size for IPv4. # ipv4-edns-size: 1232 # Preferred EDNS buffer size for IPv6. # ipv6-edns-size: 1232 # statistics are produced every number of seconds. Prints to log. # Default is 0, meaning no statistics are produced. # statistics: 3600 # Number of seconds between reloads triggered by xfrd. # xfrd-reload-timeout: 1 # log timestamp in ascii (y-m-d h:m:s.msec), yes is default. # log-time-ascii: yes # log timestamp in ISO8601 format if also log-time-ascii is enabled. # (y-m-dTh:m:s.msec[+-]tzhours:tzminutes) # log-time-iso: no # round robin rotation of records in the answer. # round-robin: no # minimal-responses only emits extra data for referrals. # minimal-responses: no # Do not return additional information if the apex zone of the # additional information is configured but does not match the apex zone # of the initial query. # confine-to-zone: no # refuse queries of type ANY. For stopping floods. # refuse-any: no # check mtime of all zone files on start and sighup # zonefiles-check: yes # write changed zonefiles to disk, every N seconds. # default is 3600. # zonefiles-write: 3600 # Reload nsd.conf and update TSIG keys and zones on SIGHUP. # reload-config: no # RRLconfig # Response Rate Limiting, size of the hashtable. Default 1000000. # rrl-size: 1000000 # Response Rate Limiting, maximum QPS allowed (from one query source). # If set to 0, ratelimiting is disabled. Also set # rrl-whitelist-ratelimit to 0 to disable ratelimit processing. # Default is @ratelimit_default@. # rrl-ratelimit: 200 # Response Rate Limiting, number of packets to discard before # sending a SLIP response (a truncated one, allowing an honest # resolver to retry with TCP). Default is 2 (one half of the # queries will receive a SLIP response, 0 disables SLIP (all # packets are discarded), 1 means every request will get a # SLIP response. When the ratelimit is hit the traffic is # divided by the rrl-slip value. # rrl-slip: 2 # Response Rate Limiting, IPv4 prefix length. Addresses are # grouped by netblock. # rrl-ipv4-prefix-length: 24 # Response Rate Limiting, IPv6 prefix length. Addresses are # grouped by netblock. # rrl-ipv6-prefix-length: 64 # Response Rate Limiting, maximum QPS allowed (from one query source) # for whitelisted types. Default is @ratelimit_default@. # rrl-whitelist-ratelimit: 2000 # RRLend # Service clients over TLS (on the TCP sockets), with plain DNS inside # the TLS stream. Give the certificate to use and private key. # Default is "" (disabled). Requires restart to take effect. # tls-service-key: "path/to/privatekeyfile.key" # tls-service-pem: "path/to/publiccertfile.pem" # tls-service-ocsp: "path/to/ocsp.pem" # tls-port: 853 # Provides a dedidated TLS port where only authenticated clients can # connect. Used for zone transfers to secondary servers. It uses # tls-service-key and tls-service-pem and verifies client certificates # using tls-cert-bundle. # Default is "" (disabled). Requires restart to take effect. # tls-auth-port: "" # Allow zone transfers only on the tls-auth-port port and only to # authenticated clients. Requests for zone transfers on other ports # are refused. Default is no. Requires restart to change it. # tls-auth-xfr-only: no # Certificates used to authenticate connections made upstream for # Transfers over TLS (XoT). Default is "" (default verify locations). # tls-cert-bundle: "path/to/ca-bundle.pem" # The interfaces that use these listed port numbers will support and # expect PROXYv2. For UDP and TCP/TLS interfaces. # proxy-protocol-port: portno for each of the port numbers. # Enable the prometheus metrics HTTP endpoint. Default is no. # metrics-enable: no # Interfaces to expose the HTTP endpoint on, default is on localhost. # Interfaces can be specified by IP address or interface name. # With an interface name, all IP addresses associated with that # interface are used. Default is 127.0.0.1 and ::1. # metrics-interface: 127.0.0.1 # metrics-interface: ::1 # metrics-interface: lo # Port number for the HTTP metrics endpoint. Default is 9100. # metrics-port: 9100 # HTTP path for the metrics endpoint. Default is "/metrics". # metrics-path: "/metrics" verify: # Enable zone verification. Default is no. # enable: no # Port to answer verifier queries on. Default is 5347. # port: 5347 # Interfaces to bind for zone verification (default are the localhost # interfaces, usually 127.0.0.1 and ::1). To bind to to multiple IP # addresses, list them one by one. Socket options cannot be specified # for verify ip-address options. # ip-address: 127.0.0.1 # ip-address: 127.0.0.1@5347 # ip-address: ::1 # Verify zones by default. Default is yes. # verify-zones: yes # Command to execute for zone verification. # verifier: ldns-verify-zone # verifier: validns - # verifier: drill -k @127.0.0.1 -p 5347 example.com SOA # Maximum number of verifiers to run concurrently. Default is 1. # verifier-count: 1 # Feed updated zone to verifier over standard input. Default is yes. # verifier-feed-zone: yes # Number of seconds before verifier is killed (0 is forever). # verifier-timeout: 0 # DNSTAP config section, if compiled with that # dnstap: # set this to yes and set one or more of dnstap-log-..-messages to yes. # dnstap-enable: no # dnstap-socket-path: "@dnstap_socket_path@" # for dnstap-ip, "" is disabled, use TCP or TLS with like 127.0.0.1@3333 # dnstap-ip: "" # dnstap-tls: yes # dnstap-tls-server-name: "" # dnstap-tls-cert-bundle: "path/to/bundle.pem" # dnstap-tls-client-key-file: "" # dnstap-tls-client-cert-file: "" # dnstap-send-identity: no # dnstap-send-version: no # dnstap-identity: "" # dnstap-version: "" # dnstap-log-auth-query-messages: no # dnstap-log-auth-response-messages: no # Remote control config section. remote-control: # Enable remote control with nsd-control(8) here. # set up the keys and certificates with nsd-control-setup. # control-enable: no # what interfaces are listened to for control, default is on localhost. # interfaces can be specified by IP address or interface name. # with an interface name, all IP addresses associated with that # interface are used. # control-interface: 127.0.0.1 # control-interface: ::1 # control-interface: lo # with an absolute path, a unix local named pipe is used for control # (and key and cert files are not needed, use directory permissions). # control-interface: @runstatedir@/nsd/nsd.sock # port number for remote control operations (uses TLS over TCP). # control-port: 8952 # nsd server key file for remote control. # server-key-file: "@configdir@/nsd_server.key" # nsd server certificate file for remote control. # server-cert-file: "@configdir@/nsd_server.pem" # nsd-control key file. # control-key-file: "@configdir@/nsd_control.key" # nsd-control certificate file. # control-cert-file: "@configdir@/nsd_control.pem" # Secret keys for TSIGs that secure zone transfers. # You could include: "secret.keys" and put the 'key:' statements in there, # and give that file special access control permissions. # # key: # The key name is sent to the other party, it must be the same #name: "keyname" # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512 #algorithm: sha256 # secret material, must be the same as the other party uses. # base64 encoded random number. # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64 #secret: "K2tf3TRjvQkVCmJF3/Z9vA==" # The tls-auth clause establishes authentication attributes to use when # authenticating the far end of an outgoing TLS connection in access control # lists used for XFR-over-TLS. If authentication fails, the XFR request will not # be made. Support for TLS 1.3 is required for XFR-over-TLS. It has the # following attributes: # # tls-auth: # The tls-auth name. Used to refer to this TLS auth information in the access control list. #name: "tls-authname" # The authentication domain name as defined in RFC8310. #auth-domain-name: "example.com" # Client certificate and private key for Mutual TLS authentication #client-cert: "path/to/clientcert.pem" #client-key: "path/to/clientkey.key" #client-key-pw: "password" # Patterns have zone configuration and they are shared by one or more zones. # # pattern: # name by which the pattern is referred to #name: "myzones" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # The allow-query allows an access control list to be specified # for a zone to be queried. Without an allow-query option, any # IP address is allowed to send queries for the zone. # This could be useful for example to not leak content from a zone # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY # If no primary and secondary access control elements are provided, # this zone will not be served to/from other servers. # A primary zone needs notify: and provide-xfr: lists. A secondary # may also allow zone transfer (for debug or other secondaries). # notify these secondaries when the primary zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. #notify: 192.0.2.1 NOKEY # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 #provide-xfr: 192.0.2.0/24 my_tsig_key_name # set the number of retries for notify. #notify-retry: 5 # if yes, store and provide IXFRs. #store-ixfr: no # number of IXFR versions to store, at most. #ixfr-number: 5 # size in bytes of max storage to use for IXFR versions. #ixfr-size: 1048576 # if yes, create IXFR when a zonefile is read by the server. #create-ixfr: no # uncomment to provide AXFR to all the world # provide-xfr: 0.0.0.0/0 NOKEY # provide-xfr: ::0/0 NOKEY # A secondary zone needs allow-notify: and request-xfr: lists. #allow-notify: 2001:db8::0/64 my_tsig_key_name # By default, a secondary will request a zone transfer with IXFR/TCP. # If you want to make use of IXFR/UDP use: UDP addr tsigkey # for a primary that only speaks AXFR use AXFR addr tsigkey # If you want to require use of XFR-over-TLS use: addr tsigkey tlsauthname #request-xfr: 192.0.2.2 the_tsig_key_name #request-xfr: 192.0.2.2 the_tsig_key_name the_tls_auth_name # Attention: You cannot use UDP and AXFR together. AXFR is always over # TCP. If you use UDP, we highly recommend you to deploy TSIG. # Allow AXFR fallback if the primary does not support IXFR. Default # is yes. #allow-axfr-fallback: yes # set local interface for sending zone transfer requests. # default is let the OS choose. #outgoing-interface: 10.0.0.10 # limit the refresh and retry interval in seconds. #max-refresh-time: 2419200 #min-refresh-time: 0 #max-retry-time: 1209600 #min-retry-time: 0 # Lower bound of expire interval in seconds. The value can be "refresh+retry+1" # in which case the lower bound of expire interval is the sum of the refresh and # retry values (limited to the bounds given with the above parameters), plus 1. #min-expire-time: 0 # Secondary server tries zone transfer to all primaries and picks highest # zone version available, for when primaries have different versions. #multi-primary-check: no # limit the zone transfer size (in bytes), stops very large transfers # 0 is no limits enforced. # size-limit-xfr: 0 # if compiled with --enable-zone-stats, give name of stat block for # this zone (or group of zones). Output from nsd-control stats. # zonestats: "%s" # if you give another pattern name here, at this point the settings # from that pattern are inserted into this one (as if it were a # macro). The statement can be given in between other statements, # because the order of access control elements can make a difference # (which primary to request from first, which secondary to notify first). #include-pattern: "common-primaries" # Verify zone before publishing. # Default is value of verify-zones in verify. # verify-zone: yes # Command to execute for zone verification. # Default is verifier in verify. # verifier: ldns-verify-zone # verifier: validns - # verifier: drill -k @127.0.0.1 -p 5347 example.com SOA # Feed updated zone to verifier over standard input. # Default is value of verifier-feed-zone in verify. # verifier-feed-zone: yes # Number of seconds before verifier is killed (0 is forever). # Default is verifier-timeout in verify. # verifier-timeout: 0 # Turn this zone into a catalog consumer zone. # The catalog-member-pattern option is the default pattern that # will be used for members without or with invalid group property. # catalog: consumer # catalog-member-pattern: "example-pattern" # Turn this zone into a catalog producer zone. # Member zones can be added using nsd-control addzone # where is a pattern containing a catalog-producer-zone # option pointing to this zone. # catalog: producer # Use this pattern to add catalog producer members. "catalog1.invalid" # needs to be a valid catalog producer zone; i.e. a primary zone # without a request-xfr option and with and catalog option set to # producer. # catalog-producer-member: "catalog1.invalid" # Fixed zone entries. Here you can config zones that cannot be deleted. # Zones that are dynamically added and deleted are put in the zonelist file. # # zone: # name: "example.com" # you can give a pattern here, all the settings from that pattern # are then inserted at this point # include-pattern: "primary" # You can also specify (additional) options directly for this zone. # zonefile: "example.com.zone" # request-xfr: 192.0.2.1 example.com.key # RRLconfig # Response Rate Limiting, whitelist types # rrl-whitelist: nxdomain # rrl-whitelist: error # rrl-whitelist: referral # rrl-whitelist: any # rrl-whitelist: rrsig # rrl-whitelist: wildcard # rrl-whitelist: nodata # rrl-whitelist: dnskey # rrl-whitelist: positive # rrl-whitelist: all # RRLend nsd-4.12.0/nsd.conf.5.in0000644000175000017500000015654015002373060014210 0ustar mozziemozzie.TH "nsd.conf" "5" "Apr 24, 2025" "NLnet Labs" "nsd 4.12.0" .\" Copyright (c) 2001\-2024, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd.conf \- NSD configuration file .SH "SYNOPSIS" .B nsd.conf .SH "DESCRIPTION" This file is used to configure nsd(8). It specifies options for the nsd server, zone files, primaries and secondaries. .sp The file format has attributes and values. Some attributes have attributes inside them. The notation is: .sp attribute: value .sp Comments start with # and last to the end of line. Empty lines are ignored, as is whitespace at the beginning of a line. Quotes must be used for values with spaces in them, eg. "file name.zone". .SH "EXAMPLE" An example of a short nsd.conf file is below. .sp .nf # Example nsd.conf file for example.com. # This is a comment. .sp server: server-count: 1 # use this number of cpu cores username: @user@ zonelistfile: @zonelistfile@ logfile: @logfile@ pidfile: @pidfile@ xfrdfile: @xfrdfile@ .sp zone: name: example.com zonefile: @configdir@/example.com.zone .sp zone: # this server is the primary and 192.0.2.1 is the secondary. name: primaryzone.com zonefile: @configdir@/primaryzone.com.zone notify: 192.0.2.1 NOKEY provide-xfr: 192.0.2.1 NOKEY .sp zone: # this server is the secondary and 192.0.2.2 is the primary. name: secondaryzone.com zonefile: @configdir@/secondaryzone.com.zone allow-notify: 192.0.2.2 NOKEY request-xfr: 192.0.2.2 NOKEY .fi .sp Then, use kill \-HUP to reload changes from primary zone files. And use kill \-TERM to stop the server. .SH "FILE FORMAT" There must be whitespace between keywords. Attribute keywords end with a colon ':'. An attribute is followed by its containing attributes, or a value. .sp At the top level, only .BR server: , .BR verify: , .BR key: , .BR pattern: , .BR zone: , .BR tls-auth: , and .B remote-control: are allowed. These are followed by their attributes or a new top-level keyword. The .B zone: attribute is followed by zone options. The .B server: attribute is followed by global options for the .B NSD server. The .B verify: attribute is used to control zone verification. A .B key: attribute is used to define keys for authentication. The .B pattern: attribute is followed by the zone options for zones that use the pattern. A .B tls-auth: attribute is used to define authentication attributes for TLS connections used for XFR-over-TLS. .sp Files can be included using the .B include: directive. It can appear anywhere, and takes a single filename as an argument. Processing continues as if the text from the included file were copied into the config file at that point. If a chroot is used, an absolute filename is needed (with the chroot prepended), so that the include can be parsed before and after application of the chroot (and the knowledge of what that chroot is). You can use '*' to include a wildcard match of files, eg. "foo/nsd.d/*.conf". Also '?', '{}', '[]', and '~' work, see \fBglob\fR(7). If no files match the pattern, this is not an error. .SS "Server Options" The global options (if not overridden from the NSD command-line) are taken from the .B server: clause. There may only be one .B server: clause. .TP .B ip\-address:\fR [@port] [servers] [bindtodevice] [setfib] NSD will bind to the listed ip\-address. Can be given multiple times to bind multiple ip\-addresses. Optionally, a port number can be given. If none are given NSD listens to the wildcard interface. Same as command-line option .BR \-a. .sp To limit which NSD server(s) listen on the given interface, specify one or more servers separated by whitespace after [@port]. Ranges can be used as a shorthand to specify multiple consecutive servers. By default every server will listen. .sp If an interface name is used instead of ip4 or ip6, the list of IP addresses associated with that interface is picked up and used at server start. .sp 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 [@port] [servers] [bindtodevice] [setfib] Same as ip\-address (for ease of compatibility with unbound.conf). .TP .B ip\-transparent:\fR Allows NSD to bind to non local addresses. This is useful to have NSD 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 ip\-freebind:\fR Set the IP_FREEBIND option to bind to nonlocal addresses and interfaces that are down. Similar to ip\-transparent. Default is no. .TP .B reuseport:\fR 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 no. It works on Linux, but does not work on FreeBSD, and likely does not work on other systems. .TP .B send\-buffer\-size:\fR Set the send buffer size for query-servicing sockets. Set to 0 to use the default settings. .TP .B receive\-buffer\-size:\fR Set the receive buffer size for query-servicing sockets. Set to 0 to use the default settings. .TP .B debug\-mode:\fR Turns on debugging mode for nsd, does not fork a daemon process. Default is no. Same as command-line option .BR \-d. If set to yes it does not fork and stays in the foreground, which can be helpful for command-line debugging, but is also used by certain server supervisor processes to ascertain that the server is running. .TP .B do\-ip4:\fR If yes, NSD listens to IPv4 connections. Default yes. .TP .B do\-ip6:\fR If yes, NSD listens to IPv6 connections. Default yes. .TP .B database:\fR This option is ignored by NSD versions 4.8.0 and newer, because the database feature has been removed. .TP .B zonelistfile:\fR By default .I @zonelistfile@ is used. The specified file is used to store the dynamically added list of zones. The list is written to by NSD to add and delete zones. It is a text file with a zone\-name and pattern\-name on each line. This file is used for the nsd\-control addzone and delzone commands. .TP .B identity:\fR Returns the specified identity when asked for CH TXT ID.SERVER. Default is the name as returned by gethostname(3). Same as command-line option .BR \-i . See hide\-identity to set the server to not respond to such queries. .TP .B version:\fR Returns the specified version string when asked for CH TXT version.server, and version.bind queries. Default is the compiled package version. See hide\-version to set the server to not respond to such queries. .TP .B nsid:\fR Add the specified nsid to the EDNS section of the answer when queried with an NSID EDNS enabled packet. As a sequence of hex characters or with ascii_ prefix and then an ascii string. Same as command-line option .BR \-I . .TP .B logfile:\fR Log messages to the logfile. The default is to log to stderr and syslog (with facility LOG_DAEMON). Same as command-line option .BR \-l . .TP .B log\-only\-syslog:\fR Log messages only to syslog. Useful with systemd so that print to stderr does not cause duplicate log strings in journald. Before syslog has been opened, the server uses stderr. Stderr is also used if syslog is not available. Default is no. .TP .B server\-count:\fR Start this many NSD servers. Default is 1. Same as command-line option .BR \-N . .TP .B cpu\-affinity:\fR ... Overall CPU affinity for NSD server(s). Default is no affinity. .TP .B server\-N\-cpu\-affinity:\fR Bind NSD server specified by N to a specific core. Default is to have affinity set to every core specified in cpu\-affinity. This setting only takes effect if cpu\-affinity is enabled. .TP .B xfrd\-cpu\-affinity:\fR Bind xfrd to a specific core. Default is to have affinity set to every core specified in cpu\-affinity. This setting only takes effect if cpu\-affinity is enabled. .TP .B tcp\-count:\fR The maximum number of concurrent, active TCP connections by each server. Default is 100. Same as command-line option .BR \-n . That is the number of requests from clients to this server. .TP .B tcp\-reject\-overflow:\fR If set to yes, TCP connections made beyond the maximum set by tcp-count will be dropped immediately (accepted and closed). Default is no. .TP .B tcp\-query\-count:\fR The maximum number of queries served on a single TCP connection. Default is 0, meaning there is no maximum. .TP .B tcp\-timeout:\fR Overrides the default TCP timeout. This also affects zone transfers over TCP. The default is 120 seconds. .TP .B tcp-mss:\fR Maximum segment size (MSS) of TCP socket on which the server responds to queries. Value lower than common MSS on Ethernet (1220 for example) will address path MTU problem. Note that not all platform supports socket option to set MSS (TCP_MAXSEG). Default is system default MSS determined by interface MTU and negotiation between server and client. .TP .B outgoing\-tcp\-mss:\fR Maximum segment size (MSS) of TCP socket for outgoing XFR request to other nameservers. Value lower than common MSS on Ethernet (1220 for example) will address path MTU problem. Note that not all platform supports socket option to set MSS (TCP_MAXSEG). Default is system default MSS determined by interface MTU and negotiation between NSD and other servers. .TP .B xfrd\-tcp\-max:\fR Number of sockets for xfrd to use for outgoing zone transfers. Default 128. Increase it to allow more zone transfer sockets, like to 256. That is for zone transfers requested by this server from other servers. To save memory, this can be lowered, set it lower together with some other settings to have reduced memory footprint for NSD. xfrd\-tcp\-max: 32 and xfrd\-tcp\-pipeline: 128 and rrl\-size: 1000 .sp This reduces memory footprint, other memory usage is caused mainly by the server\-count setting, the number of server processes, and the tcp\-count setting, which keeps buffers per server process, and by the size of the zone data. .TP .B xfrd\-tcp\-pipeline:\fR Number of simultaneous outgoing zone transfers that are possible on the tcp sockets of xfrd. Max is 65536, default is 128. That is for zone transfers requested by this server from other servers. .TP .B ipv4\-edns\-size:\fR Preferred EDNS buffer size for IPv4. Default 1232. .TP .B ipv6\-edns\-size:\fR Preferred EDNS buffer size for IPv6. Default 1232. .TP .B pidfile:\fR Use the pid file instead of the platform specific default, usually "\fI@pidfile@\fR". Same as command-line option .BR \-P . With "" there is no pidfile, for some startup management setups, where a pidfile is not useful to have. The default can be set at compile time, sometimes to "". Then the config option and commandline option can be used to specify that a pidfile is used, different from its compile time default value. The file is not chowned to the user from the \fBusername:\fR option, for permission safety reasons. It remains owned to the user by which the server was started. The file may not be removed after the server is finished and quit, since permissions for the username may not make this possible. .TP .B port:\fR Answer queries on the specified port. Default is 53. Same as command-line option .BR \-p . .TP .B statistics:\fR If not present no statistics are dumped. Statistics are produced every number seconds. Same as command-line option .BR \-s . .TP .B chroot:\fR NSD will chroot on startup to the specified directory. Note that if elsewhere in the configuration you specify an absolute pathname to a file inside the chroot, you have to prepend the \fBchroot\fR path. That way, you can switch the chroot option on and off without having to modify anything else in the configuration. Set the value to "" (the empty string) to disable the chroot. By default "\fI@chrootdir@\fR" is used. Same as command-line option .BR \-t . .TP .B username:\fR After binding the socket, drop user privileges and assume the username. Can be username, id or id.gid. Same as command-line option .BR \-u . .TP .B zonesdir:\fR Change the working directory to the specified directory before accessing zone files. Also, NSD will access \fBzonelistfile\fR, \fBlogfile\fR, \fBpidfile\fR, \fBxfrdfile\fR, \fBxfrdir\fR, \fBserver-key-file\fR, \fBserver-cert-file\fR, \fBcontrol-key-file\fR and \fBcontrol-cert-file\fR relative to this directory. Set the value to "" (the empty string) to disable the change of working directory. By default "\fI@zonesdir@\fR" is used. .TP .B difffile:\fR Ignored, for compatibility with NSD3 config files. .TP .B xfrdfile:\fR The soa timeout and zone transfer daemon in NSD will save its state to this file. State is read back after a restart. The state file can be deleted without too much harm, but timestamps of zones will be gone. If it is configured as "", the state file is not used, all secondary zones are checked for updates upon startup. For more details see the section on zone expiry behavior of NSD. Default is .IR @xfrdfile@ . .TP .B xfrdir:\fR The zone transfers are stored here before they are processed. A directory is created here that is removed when NSD exits. Default is .IR @xfrdir@ . .TP .B xfrd\-reload\-timeout:\fR If this value is \-1, xfrd will not trigger a reload after a zone transfer. If positive xfrd will trigger a reload after a zone transfer, then it will wait for the number of seconds before it will trigger a new reload. Setting this value throttles the reloads to once per the number of seconds. The default is 1 second. .TP .B verbosity:\fR 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. 3 prints more information. Same as command-line option .BR \-V . .sp Verbosity 0 will print warnings and errors, and other events that are important to keep NSD running. .sp Verbosity 1 prints additionally messages of interest. Successful notifies, successful incoming zone transfer (the zone is updated), failed incoming zone transfers or the inability to process zone updates. .sp Verbosity 2 prints additionally soft errors, like connection resets over TCP. And notify refusal, and axfr request refusals. .TP .B hide\-version:\fR Prevent NSD from replying with the version string on CHAOS class queries. Default is no. .TP .B hide\-identity:\fR Prevent NSD from replying with the identity string on CHAOS class queries. Default is no. .TP .B drop\-updates:\fR If set to yes, drop received packets with the UPDATE opcode. Default is no. .TP .B use\-systemd:\fR This option is deprecated and ignored. If compiled with libsystemd, NSD signals readiness to systemd and use of the option is not necessary. .TP .B log\-time\-ascii:\fR Log time in ascii, if "no" then in seconds epoch. Default is yes. This chooses the format when logging to file. The printout via syslog has a timestamp formatted by syslog. .TP .B log\-time\-iso:\fR Log time in ISO8601 format, if \fBlog\-time\-ascii:\fR yes is also set. Default is no. .TP .B round\-robin:\fR Enable round robin rotation of records in the answer. This changes the order of records in the answer and this may balance load across them. The default is no. .TP .B minimal\-responses:\fR Enable minimal responses for smaller answers. This makes packets smaller. Extra data is only added for referrals, when it is really necessary. This is different from the \-\-enable-minimal-responses configure time option, that reduces packets, but exactly to the fragmentation length, the nsd.conf option reduces packets as small as possible. The default is no. .TP .B confine\-to\-zone:\fR If set to yes, additional information will not be added to the response if the apex zone of the additional information does not match the apex zone of the initial query (E.G. CNAME resolution). Default is no. .TP .B refuse\-any:\fR Refuse queries of type ANY. This is useful to stop query floods trying to get large responses. Note that rrl ratelimiting also has type ANY as a ratelimiting type. It sends truncation in response to UDP type ANY queries, and it allows TCP type ANY queries like normal. The default is no. With the option turned off, NSD behaves according to RFC 8482 4.1. It minimizes the response with one RRset. Popular and not large types, like A, AAAA and MX are preferred, and large types, like DNSKEY and RRSIG are picked with a lower preference than other types. This makes the response smaller. .TP .B reload\-config:\fR Reload configuration file and update TSIG keys and zones on SIGHUP. Default is no. .TP .B zonefiles\-check:\fR Make NSD check the mtime of zone files on start and sighup. If you disable it it starts faster (less disk activity in case of a lot of zones). The default is yes. The nsd\-control reload command reloads zone files regardless of this option. .TP .B zonefiles\-write:\fR Write updated secondary zones to their zonefile every N seconds. If the zone or pattern's "zonefile" option is set to "" (empty string), no zonefile is written. The default is 3600 (1 hour). .\" rrlstart .TP .B rrl\-size:\fR This option gives the size of the hashtable. Default 1000000. More buckets use more memory, and reduce the chance of hash collisions. .TP .B rrl\-ratelimit:\fR The max qps allowed (from one query source). Default is @ratelimit_default@ (with a suggested 200 qps). If set to 0 then it is disabled (unlimited rate), also set the whitelist\-ratelimit to 0 to disable ratelimit processing. If you set verbosity to 2 the blocked and unblocked subnets are logged. Blocked queries are blocked and some receive TCP fallback replies. Once the rate limit is reached, NSD begins dropping responses. However, one in every "rrl\-slip" number of responses is allowed, with the TC bit set. If slip is set to 2, the returned response rate will be halved. If it's set to 3, the returned response rate will be one\-third, and so on. If you set rrl\-slip to 10, traffic is reduced to 1/10th. Ratelimit options rrl\-ratelimit, rrl\-size and rrl\-whitelist\-ratelimit are updated when nsd\-control reconfig is done (also the zone\-specific ratelimit options are updated). .TP .B rrl\-slip:\fR This option controls the number of packets discarded before we send back a SLIP response (a response with "truncated" bit set to one). 0 disables the sending of SLIP packets, 1 means every query will get a SLIP response. Default is 2, cuts traffic in half and legit users have a fair chance to get a +TC response. .TP .B rrl\-ipv4\-prefix\-length:\fR IPv4 prefix length. Addresses are grouped by netblock. Default 24. .TP .B rrl\-ipv6\-prefix\-length:\fR IPv6 prefix length. Addresses are grouped by netblock. Default 64. .TP .B rrl\-whitelist\-ratelimit:\fR The max qps for query sorts for a source, which have been whitelisted. Default @ratelimit_default@ (with a suggested 2000 qps). With the rrl\-whitelist option you can set specific queries to receive this qps limit instead of the normal limit. With the value 0 the rate is unlimited. .\" rrlend .TP .B answer\-cookie:\fR Enable to answer to requests containing DNS Cookies as specified in RFC7873. Default is no. .sp DNS Cookies increase transaction security and provide limited protection against denial-off-service amplification attacks. Server cookies will be created and included in responses. Server cookies are created based on the client cookie in the request, the current time, the client's IP address and a secret. When a client includes a valid server cookie in successive requests, the client will not be subjected to Request Rate Limiting (see \fBrrl\-ratelimit\fR). .sp Servers in an anycast deployment need to be able to verify each other's server cookies. For this they need to share the secret used to construct and verify the cookies. These cookie secrets can be specified in the configuration files with the \fBcookie\-secret\fR and \fBcookie\-staging\-secret\fR options. .sp If no cookie secrets are provided via configuration file, server cookie secrets can be added, dropped and activated with the \fInsd\-control\fR(8) tool. These secrets will be stored persistently in the cookie secret file for which the location can be specified with the \fBcookie\-secret\-file\fR option. .sp If no cookie secrets are provided via configuration file, and there is no or an empty cookie secret file, a random cookie secret is generated. .TP .B cookie\-secret:\fR <128 bit hex string> The cookie secret with which server cookies are created and can be verified. If a \fBcookie\-secret\fR is specified via configuration file, cookie secrets from the cookie secret file will be ignored. .TP .B cookie\-staging\-secret:\fR <128 bit hex string> A cookie secret with which server cookies can be verified, but will not be created. This is helpful in rolling cookie secrets in anycast setups. .sp A \fBcookie\-staging\-secret\fR can only be configured when there is also a \fBcookie\-secret\fR configured. .TP .B cookie\-secret\-file:\fR File from which the secrets are read used in DNS Cookie calculations. Secrets will only be read from this file if no cookie secrets are given in the configuration file via the \fBcookie\-secret\fR and \fBcookie\-staging\-secret\fR options. Default is "@cookiesecretsfile@" .sp In NSD version 4.10.1 and earlier, the default location of the cookie secret file was "@configdir@/nsd_cookiesecrets.txt". For migration purposes, cookie secrets will be read from that location if no value is given for the \fBcookie\-secret\-file\fR option and when the current default location ("@cookiesecretsfile@") does not exist. .sp The content of the cookie secret file must be manipulated with the \fBadd_cookie_secret\fR, \fBdrop_cookie_secret\fR and \fBactivate_cookie_secret\fR commands to the \fInsd\-control\fR(8) tool. Please see that manpage how to perform a safe cookie secret rollover. .TP .B tls\-service\-key:\fR If enabled, the server provides TLS service on TCP sockets with the TLS service port number. The port number (853) is configured with tls\-port. To turn it on, create an interface: option line in config with @port appended to the IP-address. This creates the extra socket on which the DNS over TLS service is provided. .sp The file is the private key for the TLS session. The public certificate is in the tls-service-pem file. Default is "", turned off. Requires a restart (a reload is not enough) if changed, because the private key is read while root permissions are held and before chroot (if any). .TP .B tls\-service\-pem:\fR The public key certificate pem file for the tls service. Default is "", turned off. .TP .B tls\-service\-ocsp:\fR The ocsp pem file for the tls service, for OCSP stapling. Default is "", turned off. An external process prepares and updates the OCSP stapling data. Like this, .sp .nf openssl ocsp -no_nonce \\ -respout /path/to/ocsp.pem \\ -CAfile /path/to/ca_and_any_intermediate.pem \\ -issuer /path/to/direct_issuer.pem \\ -cert /path/to/cert.pem \\ -url "$( openssl x509 -noout -ocsp_uri -in /path/to/cert.pem )" .fi .TP .B tls\-port:\fR The port number on which to provide TCP TLS service, default is 853, only interfaces configured with that port number as @number get DNS over TLS service. .TP .B tls\-auth\-port:\fR The port number on which to provide TCP TLS service to authenticated clients only. If you want to use mutual TLS authentication in Transfer over TLS (XoT) connections, this is where the primary server enables a dedicated port for this purpose. Certificates in .BR tls-cert-bundle are used for verifying the authenticity of a client or a secondary server. .sp Client (secondary) must enable .BR tls-auth , configure .BR client-cert and .BR client-key and enable .BR tls-auth in zone configuration in order to authenticate to a remote (primary) server. .TP .B tls\-auth\-xfr\-only:\fR Allow zone transfers only on the .BR tls-auth-port port and only to authenticated clients. This works globally for all zones. A .BR provide-xfr access control list with .BR tls-auth is also required to allow and verify a connection. Requests for zone transfers on other ports are refused. .TP .B tls\-cert\-bundle:\fR If null or "", the default verify locations are used. Set it to the certificate bundle file, for example "/etc/pki/tls/certs/ca-bundle.crt". These certificates are used for authenticating Transfer over TLS (XoT) connections. .TP .B proxy\-protocol\-port:\fR The port number for proxy protocol service. If the statement is given multiple times, additional port numbers can be used for proxy protocol service. The interface definitions that use this port number expect PROXYv2 proxy protocol traffic, for UDP, TCP and for TLS service. .TP .B metrics\-enable:\fR Enable the prometheus metrics HTTP endpoint. It exposes the same statistics as the \fInsd\-control\fR(8) stats_noreset command, but with metric names following the prometheus specification. (Requires libevent2) Beware, that when using \fInsd\-control\fR(8) stats (instead of stats_noreset), the statistics will be reset for the HTTP metrics endpoint as well. .TP .B metrics\-interface:\fR NSD will bind to the listed addresses or interfaces to serve the prometheus metrics. Can be given multiple times to bind multiple ip\-addresses. Use 0.0.0.0 and ::0 to bind to the wildcard interface. If an interface name is used instead of ip4 or ip6, the list of IP addresses associated with that interface is picked up and used at server start. Default is 127.0.0.1 and ::1. .TP .B metrics\-port:\fR The port number for the HTTP service. Default is 9100. .TP .B metrics\-path:\fR The HTTP path to expose the metrics at. Default is "/metrics". .SS "Remote Control" The .B remote\-control: clause is used to set options for using the \fInsd\-control\fR(8) tool to give commands to the running NSD server. It is disabled by default, and listens for localhost by default. It uses TLS over TCP where the server and client authenticate to each other with self\-signed certificates. The self\-signed certificates can be generated with the \fInsd\-control\-setup\fR tool. The key files are read by NSD before the chroot and before dropping user permissions, so they can be outside the chroot and readable by the superuser only. .TP .B control\-enable:\fR Enable remote control, default is no. .TP .B control\-interface:\fR NSD will bind to the listed addresses to service control requests (on TCP). Can be given multiple times to bind multiple ip\-addresses. Use 0.0.0.0 and ::0 to service the wildcard interface. If none are given NSD listens to the localhost 127.0.0.1 and ::1 interfaces for control, if control is enabled with control\-enable. If an interface name is used instead of ip4 or ip6, the list of IP addresses associated with that interface is picked up and used at server start. With an absolute path, a unix local named pipe is used for control. The file is created with user and group that is configured and access bits are set to allow members of the group access. Further access can be controlled by setting permissions on the directory containing the control socket file. The key and cert files are not used when control is via the named pipe, because access control is via file and directory permission. .TP .B control\-port:\fR The port number for remote control service. 8952 by default. .TP .B server\-key\-file:\fR Path to the server private key, by default .IR @configdir@/nsd_server.key . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by the nsd server, but not by \fInsd\-control\fR. .TP .B server\-cert\-file:\fR Path to the server self signed certificate, by default .IR @configdir@/nsd_server.pem . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by the nsd server, and also by \fInsd\-control\fR. .TP .B control\-key\-file:\fR Path to the control client private key, by default .IR @configdir@/nsd_control.key . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by \fInsd\-control\fR. .TP .B control\-cert\-file:\fR Path to the control client certificate, by default .IR @configdir@/nsd_control.pem . This certificate has to be signed with the server certificate. This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by \fInsd\-control\fR. .SS "Verifier options" The .B verify: clause is used to enable or disable zone verification, configure listen interfaces and control the global defaults. .TP .B enable:\fR Enable zone verification. Default is no. .TP .B port:\fR The port to answer verifier queries on. Default is 5347. .TP .B ip\-address:\fR Interfaces to bind for zone verification (default are the localhost interfaces, usually 127.0.0.1 and ::1). To bind to multiple IP addresses, list them one by one. Optionally, Socket options cannot be specified for verify ip-address .TP .B verify\-zones:\fR Verify zones by default. .TP .B verifier:\fR When an update is received for the zone (by IXFR or AXFR) this program will be run to assess the zone with the update. If the program exits with a status code of 0, the zone is considered good and will be served. Any other status code will designate the zone bad and the received update will be discarded. The zone will continue to be served but without the update. .sp The following environment variables are available to verifiers: .sp .B VERIFY_ZONE .br The domain name of the zone to be verified. .sp .B VERIFY_ZONE_ON_STDIN .br When the zone can be read from standard input (stdin), this variable is set to "yes", otherwise it is set to "no". .sp .B VERIFY_IP_ADDRESSES .br The first address on which the zones to be assessed will be served. If IPv6 is available an IPv6 address will be preferred over IPv4. .sp .B VERIFY_PORT .br The port number for \fBVERIFY_IP_ADDRESS\fR. .sp .B VERIFY_IPV6_ADDRESS .br The first IPv6 address on which the zones to be assessed will be served. .sp .B VERIFY_IPV6_PORT .br The port number for \fBVERIFY_IPV6_ADDRESS\fR. .sp .B VERIFY_IPV4_ADDRESS .br The first IPv4 address of which the zones to be assessed will be served. .sp .B VERIFY_IPV4_PORT .br The port number for \fBVERIFY_IPV4_ADDRESS\fR. .TP .B verifier\-count:\fR Maximum number of verifiers to run concurrently. Default is 1. .TP .B verifier\-feed\-zone:\fR Feed the updated zone to the verifier over standard input (stdin). .TP .B verifier\-timeout:\fR The maximum number of seconds a verifier is allowed to run for assessing one zone. If the verifier takes longer, it will be terminated and the zone update will be discarded. The default is 0 seconds which means the verifier may take as long as it needs. .SS "Pattern Options" The .B pattern: clause is used to denote a set of options to apply to some zones. The same zone options as for a zone are allowed. .TP .B name:\fR The name of the pattern. This is a (case sensitive) string. The pattern names that start with "_implicit_" are used internally for zones that have no pattern (they are defined in nsd.conf directly). .TP .B include\-pattern:\fR The options from the given pattern are included at this point in this pattern. The referenced pattern must be defined above this one. .TP .B :\fR The zone options such as .BR zonefile , .BR allow\-query , .BR allow\-notify , .BR request\-xfr , .BR allow\-axfr\-fallback , .BR notify , .BR notify\-retry , .BR provide\-xfr , .BR store\-ixfr , .BR ixfr\-number , .BR ixfr\-size , .BR create\-ixfr , .BR zonestats , .BR outgoing\-interface , .BR verify\-zone , .BR verifier , .BR verifier\-feed\-zone , .BR verifier\-timeout , .BR catalog , and .B catalog\-member\-pattern can be given. They are applied to the patterns and zones that include this pattern. .SS "Zone Options" .LP For every zone the options need to be specified in one .B zone: clause. The access control list elements can be given multiple times to add multiple servers. These elements need to be added explicitly. .LP For zones that are configured in the \fInsd.conf\fR config file their settings are hardcoded (in an implicit pattern for themselves only) and they cannot be deleted via delzone, but remove them from the config file and repattern. .TP .B name:\fR The name of the zone. This is the domain name of the apex of the zone. May end with a '.' (in FQDN notation). For example "example.com", "sub.example.net.". This attribute must be present in each zone. .TP .B zonefile:\fR The file containing the zone information. If this attribute is present it is used to read and write the zone contents. If the attribute is absent it prevents writing out of the zone. .sp The string is processed so that one string can be used (in a pattern) for a lot of different zones. If the label or character does not exist the percent-character is replaced with a period for output (i.e. for the third character in a two letter domain name). .sp .B %s\fR is replaced with the zone name. .sp .B %1\fR is replaced with the first character of the zone name. .sp .B %2\fR is replaced with the second character of the zone name. .sp .B %3\fR is replaced with the third character of the zone name. .sp .B %z\fR is replaced with the toplevel domain name of the zone. .sp .B %y\fR is replaced with the next label under the toplevel domain. .sp .B %x\fR is replaced with the next-next label under the toplevel domain. .TP .B allow\-query:\fR Access control list. When at least one \fBallow\-query\fR option is specified, then the specified addresses in the \fBallow\-query\fR options are allowed to query the server for the zone. Queries from unlisted or specifically BLOCKED addresses are discarded. If NOKEY is given no TSIG signature is required. BLOCKED supersedes other entries, other entries are scanned for a match in the order of the statements. Without \fBallow\-query\fR options, queries are allowed from any IP address without TSIG key (which is the default). .sp The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be a subnet of the form 1.2.3.4/24, or masked like 1.2.3.4&255.255.255.0 or a range of the form 1.2.3.4\-1.2.3.25. Note the ip\-spec ranges do not use spaces around the /, &, @ and \- symbols. .TP .B allow\-notify:\fR Access control list. The listed (primary) address is allowed to send notifies to this (secondary) server via UDP or TCP. Notifies from unlisted or specifically BLOCKED addresses are discarded. If NOKEY is given no TSIG signature is required. BLOCKED supersedes other entries, other entries are scanned for a match in the order of the statements. .sp The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be a subnet of the form 1.2.3.4/24, or masked like 1.2.3.4&255.255.255.0 or a range of the form 1.2.3.4\-1.2.3.25. A port number can be added using a suffix of @number, for example 1.2.3.4@5300 or 1.2.3.4/24@5300 for port 5300. Note the ip\-spec ranges do not use spaces around the /, &, @ and \- symbols. .RE .TP .B request\-xfr:\fR [AXFR|UDP] [tls\-auth\-name] Access control list. The listed address (the primary) is queried for AXFR/IXFR on update. A port number can be added using a suffix of @number, for example 1.2.3.4@5300. The specified key is used during AXFR/IXFR. If tls-auth-name is included, the specified tls-auth clause will be used to perform authenticated XFR-over-TLS. .sp If the AXFR option is given, the server will not be contacted with IXFR queries but only AXFR requests will be made to the server. This allows an NSD secondary to have a primary server that runs NSD. If the AXFR option is left out then both IXFR and AXFR requests are made to the primary server. .sp If the UDP option is given, the secondary will use UDP to transmit the IXFR requests. You should deploy TSIG when allowing UDP transport, to authenticate notifies and zone transfers. Otherwise, NSD is more vulnerable for Kaminsky\-style attacks. If the UDP option is left out then IXFR will be transmitted using TCP. .sp If a tls-auth-name is given then TLS (by default on port 853) will be used for all zone transfers for the zone. If authentication of the primary, based on the specified tls-auth authentication information, fails the XFR request will not be sent. Support for TLS 1.3 is required for XFR-over-TLS. .TP .B allow\-axfr\-fallback:\fR This option should be accompanied by request\-xfr. It (dis)allows NSD (as secondary) to fallback to AXFR if the primary name server does not support IXFR. Default is yes. .TP .B size\-limit\-xfr:\fR This option should be accompanied by request\-xfr. It specifies XFR temporary file size limit. It can be used to stop very large zone retrieval, that could otherwise use up a lot of memory and disk space. If this option is 0, unlimited. Default value is 0. .TP .B notify:\fR Access control list. The listed address (a secondary) is notified of updates to this zone via UDP. A port number can be added using a suffix of @number, for example 1.2.3.4@5300. The specified key is used to sign the notify. Only on secondary configurations will NSD be able to detect zone updates (as it gets notified itself, or refreshes after a time). .TP .B notify\-retry:\fR This option should be accompanied by notify. It sets the number of retries when sending notifies. .TP .B provide\-xfr:\fR [tls\-auth\-name] Access control list. The listed address (a secondary) is allowed to request XFR from this server. Zone data will be provided to the address. The specified key is used during XFR. For unlisted or BLOCKED addresses no data is provided and requests are discarded. BLOCKED supersedes other entries and other entries are scanned for a match in the order of the statements. .sp The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be a subnet of the form 1.2.3.4/24, or masked like 1.2.3.4&255.255.255.0 or a range of the form 1.2.3.4\-1.2.3.25. A port number can be added using a suffix of @number, for example 1.2.3.4@5300 or 1.2.3.4/24@5300 for port 5300. Note the ip\-spec ranges do not use spaces around the /, &, @ and \- symbols. .sp If a tls-auth-name is given then TLS authentication of the secondary will be performed for zone transfer requests for the zone. The remote end must connect to the .BR tls-auth-port and must present a certificate with a SAN (Subject Alternative Name) DNS entry or CN (Common Name) entry equal to .BR auth-domain-name of the defined .BR tls-auth . The certificate validify is also verified with .BR tls-cert-bundle . If authentication of the secondary, based on the specified tls-auth authentication information, fails the XFR zone transfer will be refused. If the connection is performed on the .BR tls-port then no authentication will be performed and the transfer will not be refused. To enforce only authenticated zone transfers, .BR tls-auth-xfr-only should also be enabled. Support for TLS 1.3 is required for XFR-over-TLS. .TP .B outgoing\-interface:\fR Access control list. The listed address is used to request AXFR|IXFR (in case of a secondary) or used to send notifies (in case of a primary). .sp The ip\-address is a plain IP address (IPv4 or IPv6). A port number can be added using a suffix of @number, for example 1.2.3.4@5300. .TP .B store\-ixfr:\fR If enabled, IXFR contents are stored and provided to the set of clients specified in the provide\-xfr statement. Default is no. IXFR content is a smaller set of changes that differ between zone versions, whereas an AXFR contains the full contents of the zone. .TP .B ixfr\-number:\fR The number of IXFR versions to store for this zone, at most. Default is 5. .TP .B ixfr\-size:\fR The max storage to use for IXFR versions for this zone, in bytes. Default is 1048576. A value of 0 means unlimited. If you want to turn off IXFR storage, set the store\-ixfr option to no. NSD does not elide IXFR contents from versions that add and remove the same data. It stores and transmits IXFRs as they were transmitted by the upstream server. .TP .B create\-ixfr:\fR If enabled, IXFR data is created when a zonefile is read by the server. This requires store\-ixfr to be set to yes, so that the IXFR contents are saved to disk. Default is off. If the server is not running, the nsd\-checkzone \-i option can be used to create an IXFR file. When an IXFR is created, the server spools a version of the zone to a temporary file, at the location where the ixfr files are stored. This creates IXFR data when the zone is read from file, but not when a zone is read by AXFR transfer from a server, because then the topmost server that originates the data is the one place where IXFR differences are computed and those differences are then transmitted verbatim to all the other servers. .TP .B max\-refresh\-time:\fR Limit refresh time for secondary zones. This is the timer which checks to see if the zone has to be refetched when it expires. Normally the value from the SOA record is used, but this option restricts that value. .TP .B min\-refresh\-time:\fR Limit refresh time for secondary zones. .TP .B max\-retry\-time:\fR Limit retry time for secondary zones. This is the timer which retries after a failed fetch attempt for the zone. Normally the value from the SOA record is used, followed by an exponential backoff, but this option restricts that value. .TP .B min\-retry\-time:\fR Limit retry time for secondary zones. .TP .B min\-expire\-time:\fR Limit expire time for secondary zones. The value can be expressed either by a number of seconds, or the string "refresh+retry+1". With the latter the expire time will be lower bound to the refresh plus the retry value from the SOA record, plus 1. The refresh and retry values will be subject to the bounds configured with max\-refresh\-time, min\-refresh\-time, max\-retry\-time and min\-retry\-time if given. .TP .B zonestats:\fR When compiled with \-\-enable\-zone\-stats NSD can collect statistics per zone. This name gives the group where statistics are added to. The groups are output from nsd\-control stats and stats_noreset. Default is "". You can use "%s" to use the name of the zone to track its statistics. If not compiled in, the option can be given but is ignored. .TP .B include\-pattern:\fR The options from the given pattern are included at this point. The referenced pattern must be defined above this zone. .\" rrlstart .TP .B rrl\-whitelist:\fR This option causes queries of this rrltype to be whitelisted, for this zone. They receive the whitelist\-ratelimit. You can give multiple lines, each enables a new rrltype to be whitelisted for the zone. Default has none whitelisted. The rrltype is the query classification that the NSD RRL employs to make different types not interfere with one another. The types are logged in the loglines when a subnet is blocked (in verbosity 2). The RRL classification types are: nxdomain, error, referral, any, rrsig, wildcard, nodata, dnskey, positive, all. .\" rrlend .TP .B multi\-primary\-check:\fR Default no. If enabled, checks all primaries for the last version. It uses the higher version of all the configured primaries. Useful if you have multiple primaries that have different version numbers served. .TP .B verify\-zone:\fR Enable or disable verification for this zone. Default is value\-zones configured in .B verify:\fR. .TP .B verifier:\fR Command to execute to assess this zone. Default is verifier configured in .B verify:\fR. .TP .B verifier-feed-zone:\fR Feed updated zone to verifier over standard input. Default is verifier\-feed\-zone configured in .B verify:\fR. .TP .B verifier\-timeout:\fR Number of seconds before verifier is forcefully terminated. Specify 0 (zero) to not use a specific timeout. Default is verifier\-timeout from .B verify:\fR. .TP .B catalog:\fR If set to \fIconsumer\fR, catalog zone processing is enabled for the zone. Only a single zone may be configured as a catalog consumer zone. When more than one catalog consumer zone is configured, none of them will be processed. Member zones of the catalog will use the pattern specified by the group property, or if a group property is missing or invalid, the pattern specified by the \fBcatalog\-member\-pattern\fR option is used. Group properties are valid if there is only a single value matching the name of a for member zones valid pattern. .sp A zone with the option set to \fIproducer\fR, can be used to produce a catalog zone. Member zones for catalog producer zones can be added with "\fInsd\-control addzone \fR", where has a \fBcatalog\-producer\-zone\fR option pointing to a catalog producer zone. Members will get a group property with the pattern name as value. Catalog producer zones must be primary zones and may not have a \fBrequest\-xfr\fR option. Catalog producer zones will \fInot\fR read content from zone files, but will reconstruct the zone on startup from the member zone entries in @zonelistfile@, specified with the \fBzonelistfile\fR option. .sp The status of both catalog consumer and producer zones can be verified with \fInsd\-control zonestatus\fR. It will show the number of member zones and, if the catalog zone is invalid, the reason for it to be invalid is shown. \fInsd\-control zonestatus\fR will also show the entry of a catalog member zone in the catalog (consumer or producer) zone as \fBcatalog-member-id:\fR. .sp A catalog zone can either be catalog consumer zone or a catalog producer zone but not both. Likewise, catalog member zones can be either a member of catalog consumer zone or a catalog producer zone but not both. .sp Catalog zones contain a list of zones that are served. Use \fBallow\-query: 0.0.0.0/0 BLOCKED\fR and \fBallow\-query: ::0/0 BLOCKED\fR in a catalog zone zone or pattern clause to prevent revealing the catalog. Also consider using transfers over TLS to further protect the catalog against eavesdroppers. .TP .B catalog\-member\-pattern:\fR If this option is provided for a catalog consumer zone, members of that catalog that have a missing or an invalid group property will be added using pattern . .TP .B catalog\-producer\-zone:\fR This option can only be used in a pattern. Adding a zone using "\fInsd\-control addzone \fR" with a containing this option, will cause a catalog member entry to be created in the catalog producer zone . must exist and must be a valid catalog producer zone. .SS "Key Declarations" The .B key: clause establishes a key for use in access control lists. It has the following attributes. .TP .B name:\fR The key name. Used to refer to this key in the access control list. The key name has to be correct for tsig to work. This is because the key name is output on the wire. .TP .B algorithm:\fR Authentication algorithm for this key. Such as hmac\-md5, hmac\-sha1, hmac\-sha224, hmac\-sha256, hmac\-sha384 and hmac\-sha512. Can also be abbreviated as 'sha1', 'sha256'. Default is sha256. Algorithms are only available when they were compiled in (available in the crypto library). .TP .B secret:\fR The base64 encoded shared secret. It is possible to put the .B secret: declaration (and base64 blob) into a different file, and then to .B include: that file. In this way the key secret and the rest of the configuration file, which may have different security policies, can be split apart. The content of the secret is the agreed base64 secret content. To make it up, enter a password (its length must be a multiple of 4 characters, A\-Za\-z0\-9), or use dev-random output through a base64 encode filter. .SS "TLS Auth Declarations" The .B tls-auth: clause establishes attributes to use when authenticating the far end of a TLS connection as well as to define credentials to authenticate to a remote server. It is used in access control lists for XFR-over-TLS. It has the following attributes. .TP .B name:\fR The tls-auth name. Used to refer to this TLS authentication information in the access control list. .TP .B auth\-domain\-name:\fR The authentication domain name as defined in RFC8310. Used to verify the certificate of the remote connecting server. When used by a primary server in .BR provide-xfr it verifies the secondary. When used by a secondary server in .BR request-xfr it verifies the primary. .TP .B client\-cert: If you want to use mutual TLS authentication, this is where the client certificates can be configured that NSD uses to connect to the upstream server to download the zone. The client public key pem cert file can be configured here. Also configure a private key with client\-key. .TP .B client\-key: If you want to use mutual TLS authentication, the private key file can be configured here for the client authentication. .TP .B client\-key\-pw: If the client\-key file uses a password to decrypt the key before it can be used, then the password can be specified here as a string. It is possible to include other config files with the include: option, and this can be used to move that sensitive data to another file, if you wish. .SS DNSTAP Logging Options DNSTAP support, when compiled in, is enabled in the \fBdnstap:\fR section. This starts a collector process that writes the log information to the destination. .TP .B dnstap-enable:\fR If dnstap is enabled. Default no. If yes, it connects to the dnstap server and if any of the dnstap-log-..-messages options is enabled it sends logs for those messages to the server. .TP .B dnstap-socket-path:\fR Sets the unix socket file name for connecting to the server that is listening on that socket. Default is "@dnstap_socket_path@". .TP .B dnstap-ip:\fR <"" or addr[@port]> If disabled with "", the socket path is used. With a value, like address or address@port, like "127.0.0.1@3333" TCP or TLS is used. Default is "". .TP .B dnstap-tls:\fR If enabled, TLS is used to the address specified in \fBdnstap-ip\fR. Otherwise, TCP is used. Default is yes. .TP .B dnstap-tls-server-name:\fR The name for authenticating the upstream server. With "" disabled. .TP .B dnstap-tls-client-key-file:\fR The key file for client authentication, or "" disabled. .TP .B dnstap-tls-client-cert-file:\fR The cert file for client authentication, or "" disabled. .TP .B dnstap-send-identity:\fR If enabled, the server identity is included in the log messages. Default is no. .TP .B dnstap-send-version:\fR If enabled, the server version if included in the log messages. Default is no. .TP .B dnstap-identity:\fR The identity to send with messages, if "" the hostname is used. Default is "". .TP .B dnstap-version:\fR The version to send with messages, if "" the package version is used. Default is "". .TP .B dnstap-log-auth-query-messages:\fR Enable to log auth query messages. Default is no. These are client queries to NSD. .TP .B dnstap-log-auth-response-messages:\fR Enable to log auth response messages. Default is no. These are responses from NSD to clients. .SH "NSD CONFIGURATION FOR BIND9 HACKERS" BIND9 is a name server implementation with its own configuration file format, named.conf(5). BIND9 types zones as 'Primary' or 'Secondary'. .SS "Secondary zones" For a secondary zone, the primary servers are listed. The primary servers are queried for zone data, and are listened to for update notifications. In NSD these two properties need to be configured separately, by listing the primary address in allow\-notify and request\-xfr statements. .sp In BIND9 you only need to provide allow\-notify elements for any extra sources of notifications (i.e. the operators), NSD needs to have allow\-notify for both primaries and operators. BIND9 allows additional transfer sources, in NSD you list those as request\-xfr. .sp Here is an example of a secondary zone in BIND9 syntax. .sp .nf # Config file for example.org options { dnssec\-enable yes; }; .sp key tsig.example.org. { algorithm hmac\-md5; secret "aaaaaabbbbbbccccccdddddd"; }; .sp server 162.0.4.49 { keys { tsig.example.org. ; }; }; .sp zone "example.org" { type secondary; file "secondary/example.org.signed"; primaries { 162.0.4.49; }; }; .fi For NSD, DNSSEC is enabled automatically for zones that are signed. The dnssec\-enable statement in the options clause is not needed. In NSD keys are associated with an IP address in the access control list statement, therefore the server{} statement is not needed. Below is the same example in an NSD config file. .sp .nf # Config file for example.org key: name: tsig.example.org. algorithm: hmac\-md5 secret: "aaaaaabbbbbbccccccdddddd" .sp zone: name: "example.org" zonefile: "secondary/example.org.signed" # the primary is allowed to notify and will provide zone data. allow\-notify: 162.0.4.49 NOKEY request\-xfr: 162.0.4.49 tsig.example.org. .fi .sp Notice that the primary is listed twice, once to allow it to send notifies to this secondary server and once to tell the secondary server where to look for updates zone data. More allow\-notify and request\-xfr lines can be added to specify more primaries. .sp It is possible to specify extra allow\-notify lines for addresses that are also allowed to send notifications to this secondary server. .SS "Primary zones" For a primary zone in BIND9, the secondary servers are listed. These secondary servers are sent notifications of updated and are allowed to request transfer of the zone data. In NSD these two properties need to be configured separately. .sp Here is an example of a primary zone in BIND9 syntax. .sp .nf zone "example.nl" { type primary; file "example.nl"; }; .fi .sp In NSD syntax this becomes: .sp .nf zone: name: "example.nl" zonefile: "example.nl" # allow anybody to request xfr. provide\-xfr: 0.0.0.0/0 NOKEY provide\-xfr: ::0/0 NOKEY .sp # to list a secondary server you would in general give # provide\-xfr: 1.2.3.4 tsig\-key.name. # notify: 1.2.3.4 NOKEY .fi .SS "Other" NSD is an authoritative only DNS server. This means that it is meant as a primary or secondary server for zones, providing DNS data to DNS resolvers and caches. BIND9 can function as an authoritative DNS server, the configuration options for that are compared with those for NSD in this section. However, BIND9 can also function as a resolver or cache. The configuration options that BIND9 has for the resolver or caching thus have no equivalents for NSD. .SH "FILES" .TP @nsdconfigfile@ default .B NSD configuration file .SH "SEE ALSO" \fInsd\fR(8), \fInsd\-checkconf\fR(8), \fInsd\-checkzone\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by a combined team from NLnet Labs and RIPE NCC. Please see the CREDITS file in the distribution for further details. .SH "BUGS" .B nsd.conf is parsed by a primitive parser. Error messages may not be to the point. nsd-4.12.0/nsd.c0000644000175000017500000013250315002373054012731 0ustar mozziemozzie/* * nsd.c -- nsd(8) * * Copyright (c) 2001-2024, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_GRP_H #include #endif /* HAVE_GRP_H */ #ifdef HAVE_SETUSERCONTEXT #ifdef HAVE_LOGIN_CAP_H #include #endif /* HAVE_LOGIN_CAP_H */ #endif /* HAVE_SETUSERCONTEXT */ #ifdef HAVE_OPENSSL_RAND_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_IFADDRS_H #include #endif #include "nsd.h" #include "options.h" #include "tsig.h" #include "remote.h" #include "xfrd-disk.h" #include "ipc.h" #ifdef USE_METRICS #include "metrics.h" #endif /* USE_METRICS */ #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif #include "util/proxy_protocol.h" /* The server handler... */ struct nsd nsd; static char hostname[MAXHOSTNAMELEN]; extern config_parser_state_type* cfg_parser; static void version(void) ATTR_NORETURN; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd [OPTION]...\n"); fprintf(stderr, "Name Server Daemon.\n\n"); fprintf(stderr, "Supported options:\n" " -4 Only listen to IPv4 connections.\n" " -6 Only listen to IPv6 connections.\n" " -a ip-address[@port] Listen to the specified incoming IP address (and port)\n" " May be specified multiple times).\n" " -c configfile Read specified configfile instead of %s.\n" " -d do not fork as a daemon process.\n" #ifndef NDEBUG " -F facilities Specify the debug facilities.\n" #endif /* NDEBUG */ " -h Print this help information.\n" , CONFIGFILE); fprintf(stderr, " -i identity Specify the identity when queried for id.server CHAOS TXT.\n" " -I nsid Specify the NSID. This must be a hex string.\n" #ifndef NDEBUG " -L level Specify the debug level.\n" #endif /* NDEBUG */ " -l filename Specify the log file.\n" " -N server-count The number of servers to start.\n" " -n tcp-count The maximum number of TCP connections per server.\n" " -P pidfile Specify the PID file to write.\n" " -p port Specify the port to listen to.\n" " -s seconds Dump statistics every SECONDS seconds.\n" " -t chrootdir Change root to specified directory on startup.\n" ); fprintf(stderr, " -u user Change effective uid to the specified user.\n" " -V level Specify verbosity level.\n" " -v Print version information.\n" ); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } /* * Print the version exit. * */ static void version(void) { fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); fprintf(stderr, "Written by NLnet Labs.\n\n"); fprintf(stderr, "Configure line: %s\n", CONFCMDLINE); #ifdef USE_MINI_EVENT fprintf(stderr, "Event loop: internal (uses select)\n"); #else # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) fprintf(stderr, "Event loop: %s %s (uses %s)\n", "libev", nsd_event_vs(), nsd_event_method()); # else fprintf(stderr, "Event loop: %s %s (uses %s)\n", "libevent", nsd_event_vs(), nsd_event_method()); # endif #endif #ifdef HAVE_SSL fprintf(stderr, "Linked with %s\n\n", # ifdef SSLEAY_VERSION SSLeay_version(SSLEAY_VERSION) # else OpenSSL_version(OPENSSL_VERSION) # endif ); #endif fprintf(stderr, "Copyright (C) 2001-2024 NLnet Labs. This is free software.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n" "FOR A PARTICULAR PURPOSE.\n"); exit(0); } static void setup_verifier_environment(void) { size_t i; int ret, ip4, ip6; char *buf, host[NI_MAXHOST], serv[NI_MAXSERV]; size_t size, cnt = 0; /* allocate large enough buffer to hold a list of all ip addresses. ((" " + INET6_ADDRSTRLEN + "@" + "65535") * n) + "\0" */ size = ((INET6_ADDRSTRLEN + 1 + 5 + 1) * nsd.verify_ifs) + 1; buf = xalloc(size); ip4 = ip6 = 0; for(i = 0; i < nsd.verify_ifs; i++) { ret = getnameinfo( (struct sockaddr *)&nsd.verify_udp[i].addr.ai_addr, nsd.verify_udp[i].addr.ai_addrlen, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); if(ret != 0) { log_msg(LOG_ERR, "error in getnameinfo: %s", gai_strerror(ret)); continue; } buf[cnt++] = ' '; cnt += strlcpy(&buf[cnt], host, size - cnt); assert(cnt < size); buf[cnt++] = '@'; cnt += strlcpy(&buf[cnt], serv, size - cnt); assert(cnt < size); #ifdef INET6 if (nsd.verify_udp[i].addr.ai_family == AF_INET6 && !ip6) { setenv("VERIFY_IPV6_ADDRESS", host, 1); setenv("VERIFY_IPV6_PORT", serv, 1); setenv("VERIFY_IP_ADDRESS", host, 1); setenv("VERIFY_PORT", serv, 1); ip6 = 1; } else #endif if (!ip4) { assert(nsd.verify_udp[i].addr.ai_family == AF_INET); setenv("VERIFY_IPV4_ADDRESS", host, 1); setenv("VERIFY_IPV4_PORT", serv, 1); if (!ip6) { setenv("VERIFY_IP_ADDRESS", host, 1); setenv("VERIFY_PORT", serv, 1); } ip4 = 1; } } setenv("VERIFY_IP_ADDRESSES", &buf[1], 1); free(buf); } static void copyaddrinfo(struct nsd_addrinfo *dest, struct addrinfo *src) { dest->ai_flags = src->ai_flags; dest->ai_family = src->ai_family; dest->ai_socktype = src->ai_socktype; dest->ai_addrlen = src->ai_addrlen; memcpy(&dest->ai_addr, src->ai_addr, src->ai_addrlen); } static void setup_socket( struct nsd_socket *sock, const char *node, const char *port, struct addrinfo *hints) { int ret; char *host; char host_buf[sizeof("65535") + INET6_ADDRSTRLEN + 1 /* '\0' */]; const char *service; struct addrinfo *addr = NULL; sock->fib = -1; if(node) { char *sep; if (strlcpy(host_buf, node, sizeof(host_buf)) >= sizeof(host_buf)) { error("cannot parse address '%s': %s", node, strerror(ENAMETOOLONG)); } host = host_buf; sep = strchr(host_buf, '@'); if(sep != NULL) { *sep = '\0'; service = sep + 1; } else { service = port; } } else { host = NULL; service = port; } if((ret = getaddrinfo(host, service, hints, &addr)) == 0) { copyaddrinfo(&sock->addr, addr); freeaddrinfo(addr); } else { error("cannot parse address '%s': getaddrinfo: %s %s", host ? host : "(null)", gai_strerror(ret), ret==EAI_SYSTEM ? strerror(errno) : ""); } } static void figure_socket_servers( struct nsd_socket *sock, struct ip_address_option *ip) { int i; struct range_option *server; sock->servers = xalloc_zero(nsd_bitset_size(nsd.child_count)); region_add_cleanup(nsd.region, free, sock->servers); nsd_bitset_init(sock->servers, nsd.child_count); if(!ip || !ip->servers) { /* every server must listen on this socket */ for(i = 0; i < (int)nsd.child_count; i++) { nsd_bitset_set(sock->servers, i); } return; } /* only specific servers must listen on this socket */ for(server = ip->servers; server; server = server->next) { if(server->first == server->last) { if(server->first <= 0) { error("server %d specified for ip-address %s " "is invalid; server ranges are 1-based", server->first, ip->address); } else if(server->last > (int)nsd.child_count) { error("server %d specified for ip-address %s " "exceeds number of servers configured " "in server-count", server->first, ip->address); } } else { /* parse_range must ensure range itself is valid */ assert(server->first < server->last); if(server->first <= 0) { error("server range %d-%d specified for " "ip-address %s is invalid; server " "ranges are 1-based", server->first, server->last, ip->address); } else if(server->last > (int)nsd.child_count) { error("server range %d-%d specified for " "ip-address %s exceeds number of servers " "configured in server-count", server->first, server->last, ip->address); } } for(i = server->first - 1; i < server->last; i++) { nsd_bitset_set(sock->servers, i); } } } static void figure_default_sockets( struct nsd_socket **udp, struct nsd_socket **tcp, size_t *ifs, const char *node, const char *udp_port, const char *tcp_port, const struct addrinfo *hints) { size_t i = 0, n = 1; struct addrinfo ai[2] = { *hints, *hints }; assert(udp != NULL); assert(tcp != NULL); assert(ifs != NULL); ai[0].ai_socktype = SOCK_DGRAM; ai[1].ai_socktype = SOCK_STREAM; #ifdef INET6 #ifdef IPV6_V6ONLY if (hints->ai_family == AF_UNSPEC) { ai[0].ai_family = AF_INET6; ai[1].ai_family = AF_INET6; n++; } #endif /* IPV6_V6ONLY */ #endif /* INET6 */ *udp = xalloc_zero((n + 1) * sizeof(struct nsd_socket)); *tcp = xalloc_zero((n + 1) * sizeof(struct nsd_socket)); region_add_cleanup(nsd.region, free, *udp); region_add_cleanup(nsd.region, free, *tcp); #ifdef INET6 if(hints->ai_family == AF_UNSPEC) { /* * With IPv6 we'd like to open two separate sockets, one for * IPv4 and one for IPv6, both listening to the wildcard * address (unless the -4 or -6 flags are specified). * * However, this is only supported on platforms where we can * turn the socket option IPV6_V6ONLY _on_. Otherwise we just * listen to a single IPv6 socket and any incoming IPv4 * connections will be automatically mapped to our IPv6 * socket. */ #ifdef IPV6_V6ONLY int r; struct addrinfo *addrs[2] = { NULL, NULL }; if((r = getaddrinfo(node, udp_port, &ai[0], &addrs[0])) == 0 && (r = getaddrinfo(node, tcp_port, &ai[1], &addrs[1])) == 0) { (*udp)[i].flags |= NSD_SOCKET_IS_OPTIONAL; (*udp)[i].fib = -1; copyaddrinfo(&(*udp)[i].addr, addrs[0]); figure_socket_servers(&(*udp)[i], NULL); (*tcp)[i].flags |= NSD_SOCKET_IS_OPTIONAL; (*tcp)[i].fib = -1; copyaddrinfo(&(*tcp)[i].addr, addrs[1]); figure_socket_servers(&(*tcp)[i], NULL); i++; } else { log_msg(LOG_WARNING, "No IPv6, fallback to IPv4. getaddrinfo: %s", r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r)); } if(addrs[0]) freeaddrinfo(addrs[0]); if(addrs[1]) freeaddrinfo(addrs[1]); ai[0].ai_family = AF_INET; ai[1].ai_family = AF_INET; #endif /* IPV6_V6ONLY */ } #endif /* INET6 */ *ifs = i + 1; setup_socket(&(*udp)[i], node, udp_port, &ai[0]); figure_socket_servers(&(*udp)[i], NULL); setup_socket(&(*tcp)[i], node, tcp_port, &ai[1]); figure_socket_servers(&(*tcp)[i], NULL); } #ifdef HAVE_GETIFADDRS static int find_device( struct nsd_socket *sock, const struct ifaddrs *ifa) { for(; ifa != NULL; ifa = ifa->ifa_next) { if((ifa->ifa_addr == NULL) || (ifa->ifa_addr->sa_family != sock->addr.ai_family) || ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0 || (ifa->ifa_flags & IFF_RUNNING) == 0)) { continue; } #ifdef INET6 if(ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *sa1, *sa2; size_t sz = sizeof(struct in6_addr); sa1 = (struct sockaddr_in6 *)ifa->ifa_addr; sa2 = (struct sockaddr_in6 *)&sock->addr.ai_addr; if(memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sz) == 0) { break; } } else #endif if(ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sa1, *sa2; sa1 = (struct sockaddr_in *)ifa->ifa_addr; sa2 = (struct sockaddr_in *)&sock->addr.ai_addr; if(sa1->sin_addr.s_addr == sa2->sin_addr.s_addr) { break; } } } if(ifa != NULL) { size_t len = strlcpy(sock->device, ifa->ifa_name, sizeof(sock->device)); if(len < sizeof(sock->device)) { char *colon = strchr(sock->device, ':'); if(colon != NULL) *colon = '\0'; return 1; } } return 0; } #endif /* HAVE_GETIFADDRS */ static void figure_sockets( struct nsd_socket **udp, struct nsd_socket **tcp, size_t *ifs, struct ip_address_option *ips, const char *node, const char *udp_port, const char *tcp_port, const struct addrinfo *hints) { size_t i = 0; struct addrinfo ai = *hints; struct ip_address_option *ip; #ifdef HAVE_GETIFADDRS struct ifaddrs *ifa = NULL; #endif int bind_device = 0; if(!ips) { figure_default_sockets( udp, tcp, ifs, node, udp_port, tcp_port, hints); return; } *ifs = 0; for(ip = ips; ip; ip = ip->next) { (*ifs)++; bind_device |= (ip->dev != 0); } #ifdef HAVE_GETIFADDRS if(bind_device && getifaddrs(&ifa) == -1) { error("getifaddrs failed: %s", strerror(errno)); } #endif *udp = xalloc_zero((*ifs + 1) * sizeof(struct nsd_socket)); *tcp = xalloc_zero((*ifs + 1) * sizeof(struct nsd_socket)); region_add_cleanup(nsd.region, free, *udp); region_add_cleanup(nsd.region, free, *tcp); ai.ai_flags |= AI_NUMERICHOST; for(ip = ips, i = 0; ip; ip = ip->next, i++) { ai.ai_socktype = SOCK_DGRAM; setup_socket(&(*udp)[i], ip->address, udp_port, &ai); figure_socket_servers(&(*udp)[i], ip); ai.ai_socktype = SOCK_STREAM; setup_socket(&(*tcp)[i], ip->address, tcp_port, &ai); figure_socket_servers(&(*tcp)[i], ip); if(ip->fib != -1) { (*udp)[i].fib = ip->fib; (*tcp)[i].fib = ip->fib; } #ifdef HAVE_GETIFADDRS if(ip->dev != 0) { (*udp)[i].flags |= NSD_BIND_DEVICE; (*tcp)[i].flags |= NSD_BIND_DEVICE; if(ifa != NULL && (find_device(&(*udp)[i], ifa) == 0 || find_device(&(*tcp)[i], ifa) == 0)) { error("cannot find device for ip-address %s", ip->address); } } #endif } assert(i == *ifs); #ifdef HAVE_GETIFADDRS if(ifa != NULL) { freeifaddrs(ifa); } #endif } /* print server affinity for given socket. "*" if socket has no affinity with any specific server, "x-y" if socket has affinity with more than two consecutively numbered servers, "x" if socket has affinity with a specific server number, which is not necessarily just one server. e.g. "1 3" is printed if socket has affinity with servers number one and three, but not server number two. */ static ssize_t print_socket_servers(struct nsd_socket *sock, char *buf, size_t bufsz) { int i, x, y, z, n = (int)(sock->servers->size); char *sep = ""; size_t off, tot; ssize_t cnt = 0; assert(bufsz != 0); off = tot = 0; x = y = z = -1; for (i = 0; i <= n; i++) { if (i == n || !nsd_bitset_isset(sock->servers, i)) { cnt = 0; if (i == n && x == -1) { assert(y == -1); assert(z == (n - 1)); cnt = snprintf(buf, bufsz, "-"); } else if (y > z) { assert(x > z); if (x == 0 && y == (n - 1)) { assert(z == -1); cnt = snprintf(buf+off, bufsz-off, "*"); } else if (x == y) { cnt = snprintf(buf+off, bufsz-off, "%s%d", sep, x+1); } else if (x == (y - 1)) { cnt = snprintf(buf+off, bufsz-off, "%s%d %d", sep, x+1, y+1); } else { assert(y > (x + 1)); cnt = snprintf(buf+off, bufsz-off, "%s%d-%d", sep, x+1, y+1); } } z = i; if (cnt > 0) { tot += (size_t)cnt; off = (tot < bufsz) ? tot : bufsz - 1; sep = " "; } else if (cnt < 0) { return -1; } } else if (x <= z) { x = y = i; } else { assert(x > z); y = i; } } return tot; } static void print_sockets( struct nsd_socket *udp, struct nsd_socket *tcp, size_t ifs) { char sockbuf[INET6_ADDRSTRLEN + 6 + 1]; char *serverbuf; size_t i, serverbufsz, servercnt; const char *fmt = "listen on ip-address %s (%s) with server(s): %s"; struct nsd_bitset *servers; if(ifs == 0) { return; } assert(udp != NULL); assert(tcp != NULL); servercnt = udp[0].servers->size; serverbufsz = (((servercnt / 10) * servercnt) + servercnt) + 1; serverbuf = xalloc(serverbufsz); /* warn user of unused servers */ servers = xalloc(nsd_bitset_size(servercnt)); nsd_bitset_init(servers, (size_t)servercnt); for(i = 0; i < ifs; i++) { assert(udp[i].servers->size == servercnt); addrport2str((void*)&udp[i].addr.ai_addr, sockbuf, sizeof(sockbuf)); print_socket_servers(&udp[i], serverbuf, serverbufsz); nsd_bitset_or(servers, servers, udp[i].servers); VERBOSITY(3, (LOG_NOTICE, fmt, sockbuf, "udp", serverbuf)); assert(tcp[i].servers->size == servercnt); addrport2str((void*)&tcp[i].addr.ai_addr, sockbuf, sizeof(sockbuf)); print_socket_servers(&tcp[i], serverbuf, serverbufsz); nsd_bitset_or(servers, servers, tcp[i].servers); VERBOSITY(3, (LOG_NOTICE, fmt, sockbuf, "tcp", serverbuf)); } /* warn user of unused servers */ for(i = 0; i < servercnt; i++) { if(!nsd_bitset_isset(servers, i)) { log_msg(LOG_WARNING, "server %zu will not listen on " "any specified ip-address", i+1); } } free(serverbuf); free(servers); } #ifdef HAVE_CPUSET_T static void free_cpuset(void *ptr) { cpuset_t *set = (cpuset_t *)ptr; cpuset_destroy(set); } #endif /* * Fetch the nsd parent process id from the nsd pidfile * */ pid_t readpid(const char *file) { int fd; pid_t pid; char pidbuf[16]; char *t; int l; if ((fd = open(file, O_RDONLY)) == -1) { return -1; } if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { int errno_bak = errno; close(fd); errno = errno_bak; return -1; } close(fd); /* Empty pidfile means no pidfile... */ if (l == 0) { errno = ENOENT; return -1; } pid = (pid_t) strtol(pidbuf, &t, 10); if (*t && *t != '\n') { return -1; } return pid; } /* * Store the nsd parent process id in the nsd pidfile * */ int writepid(struct nsd *nsd) { int fd; char pidbuf[32]; size_t count = 0; if(!nsd->pidfile || !nsd->pidfile[0]) return 0; snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) nsd->pid); if((fd = open(nsd->pidfile, O_WRONLY | O_CREAT | O_TRUNC #ifdef O_NOFOLLOW | O_NOFOLLOW #endif , 0644)) == -1) { log_msg(LOG_ERR, "cannot open pidfile %s: %s", nsd->pidfile, strerror(errno)); return -1; } while(count < strlen(pidbuf)) { ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count); if(r == -1) { if(errno == EAGAIN || errno == EINTR) continue; log_msg(LOG_ERR, "cannot write pidfile %s: %s", nsd->pidfile, strerror(errno)); close(fd); return -1; } else if(r == 0) { log_msg(LOG_ERR, "cannot write any bytes to " "pidfile %s: write returns 0 bytes written", nsd->pidfile); close(fd); return -1; } count += r; } close(fd); return 0; } void unlinkpid(const char* file, const char* username) { int fd = -1; if (file && file[0]) { /* truncate pidfile */ fd = open(file, O_WRONLY | O_TRUNC #ifdef O_NOFOLLOW | O_NOFOLLOW #endif , 0644); if (fd == -1) { /* Truncate the pid file. */ /* If there is a username configured, we assume that * due to privilege drops, NSD cannot truncate or * unlink the pid file. NSD does not chown the file * because that creates a privilege escape. */ if(username && username[0]) { VERBOSITY(5, (LOG_INFO, "can not truncate the pid file %s: %s", file, strerror(errno))); } else { log_msg(LOG_ERR, "can not truncate the pid file %s: %s", file, strerror(errno)); } } else { close(fd); } /* unlink pidfile */ if (unlink(file) == -1) { /* this unlink may not work if the pidfile is located * outside of the chroot/workdir or we no longer * have permissions */ if(username && username[0]) { VERBOSITY(5, (LOG_INFO, "failed to unlink pidfile %s: %s", file, strerror(errno))); } else { VERBOSITY(3, (LOG_WARNING, "failed to unlink pidfile %s: %s", file, strerror(errno))); } } } } /* * Incoming signals, set appropriate actions. * */ void sig_handler(int sig) { /* To avoid race cond. We really don't want to use log_msg() in this handler */ /* Are we a child server? */ if (nsd.server_kind != NSD_SERVER_MAIN) { switch (sig) { case SIGCHLD: nsd.signal_hint_child = 1; break; case SIGALRM: break; case SIGINT: case SIGTERM: nsd.signal_hint_quit = 1; break; case SIGILL: case SIGUSR1: /* Dump stats on SIGUSR1. */ nsd.signal_hint_statsusr = 1; break; default: break; } return; } /* We are the main process */ switch (sig) { case SIGCHLD: nsd.signal_hint_child = 1; return; case SIGHUP: nsd.signal_hint_reload_hup = 1; return; case SIGALRM: nsd.signal_hint_stats = 1; break; case SIGILL: /* * For backwards compatibility with BIND 8 and older * versions of NSD. */ nsd.signal_hint_statsusr = 1; break; case SIGUSR1: /* Dump statistics. */ nsd.signal_hint_statsusr = 1; break; case SIGINT: case SIGTERM: default: nsd.signal_hint_shutdown = 1; break; } } /* * Statistic output... * */ #ifdef BIND8_STATS void bind8_stats (struct nsd *nsd) { char buf[MAXSYSLOGMSGLEN]; char *msg, *t; int i, len; struct nsdst st; /* Current time... */ time_t now; if(!nsd->st_period) return; time(&now); memcpy(&st, nsd->st, sizeof(st)); stats_subtract(&st, &nsd->stat_proc); /* NSTATS */ t = msg = buf + snprintf(buf, MAXSYSLOGMSGLEN, "NSTATS %lld %lu", (long long) now, (unsigned long) st.boot); for (i = 0; i <= 255; i++) { /* How much space left? */ if ((len = buf + MAXSYSLOGMSGLEN - t) < 32) { log_msg(LOG_INFO, "%s", buf); t = msg; len = buf + MAXSYSLOGMSGLEN - t; } if (st.qtype[i] != 0) { t += snprintf(t, len, " %s=%lu", rrtype_to_string(i), st.qtype[i]); } } if (t > msg) log_msg(LOG_INFO, "%s", buf); /* XSTATS */ /* Only print it if we're in the main daemon or have anything to report... */ if (nsd->server_kind == NSD_SERVER_MAIN || st.dropped || st.raxfr || st.rixfr || (st.qudp + st.qudp6 - st.dropped) || st.txerr || st.opcode[OPCODE_QUERY] || st.opcode[OPCODE_IQUERY] || st.wrongzone || st.ctcp + st.ctcp6 || st.rcode[RCODE_SERVFAIL] || st.rcode[RCODE_FORMAT] || st.nona || st.rcode[RCODE_NXDOMAIN] || st.opcode[OPCODE_UPDATE]) { log_msg(LOG_INFO, "XSTATS %lld %lu" " RR=%lu RNXD=%lu RFwdR=%lu RDupR=%lu RFail=%lu RFErr=%lu RErr=%lu RAXFR=%lu RIXFR=%lu" " RLame=%lu ROpts=%lu SSysQ=%lu SAns=%lu SFwdQ=%lu SDupQ=%lu SErr=%lu RQ=%lu" " RIQ=%lu RFwdQ=%lu RDupQ=%lu RTCP=%lu SFwdR=%lu SFail=%lu SFErr=%lu SNaAns=%lu" " SNXD=%lu RUQ=%lu RURQ=%lu RUXFR=%lu RUUpd=%lu", (long long) now, (unsigned long) st.boot, st.dropped, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, st.raxfr, st.rixfr, (unsigned long)0, (unsigned long)0, (unsigned long)0, st.qudp + st.qudp6 - st.dropped, (unsigned long)0, (unsigned long)0, st.txerr, st.opcode[OPCODE_QUERY], st.opcode[OPCODE_IQUERY], st.wrongzone, (unsigned long)0, st.ctcp + st.ctcp6, (unsigned long)0, st.rcode[RCODE_SERVFAIL], st.rcode[RCODE_FORMAT], st.nona, st.rcode[RCODE_NXDOMAIN], (unsigned long)0, (unsigned long)0, (unsigned long)0, st.opcode[OPCODE_UPDATE]); } } #endif /* BIND8_STATS */ extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; pid_t oldpid; size_t i; struct sigaction action; #ifdef HAVE_GETPWNAM struct passwd *pwd = NULL; #endif /* HAVE_GETPWNAM */ struct ip_address_option *ip; struct addrinfo hints; const char *udp_port = 0; const char *tcp_port = 0; const char *verify_port = 0; const char *configfile = CONFIGFILE; char* argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0]; log_init(argv0); /* Initialize the server handler... */ memset(&nsd, 0, sizeof(struct nsd)); nsd.region = region_create(xalloc, free); nsd.pidfile = 0; nsd.server_kind = NSD_SERVER_MAIN; memset(&hints, 0, sizeof(hints)); hints.ai_family = DEFAULT_AI_FAMILY; hints.ai_flags = AI_PASSIVE; nsd.identity = 0; nsd.version = VERSION; nsd.username = 0; nsd.chrootdir = 0; nsd.nsid = NULL; nsd.nsid_len = 0; nsd.do_answer_cookie = 0; nsd.cookie_count = 0; nsd.cookie_secrets_source = COOKIE_SECRETS_NONE; nsd.cookie_secrets_filename = NULL; nsd.child_count = 0; nsd.maximum_tcp_count = 0; nsd.current_tcp_count = 0; nsd.file_rotation_ok = 0; /* Set up our default identity to gethostname(2) */ if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { nsd.identity = hostname; } else { log_msg(LOG_ERR, "failed to get the host name: %s - using default identity", strerror(errno)); nsd.identity = IDENTITY; } /* Create region where options will be stored and set defaults */ nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); /* 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 /* only when configured with --enable-checking */ "F:L:" #endif /* NDEBUG */ )) != -1) { switch (c) { case '4': hints.ai_family = AF_INET; break; case '6': #ifdef INET6 hints.ai_family = AF_INET6; #else /* !INET6 */ error("IPv6 support not enabled."); #endif /* INET6 */ break; case 'a': ip = region_alloc_zero( nsd.options->region, sizeof(*ip)); ip->address = region_strdup( nsd.options->region, optarg); ip->next = nsd.options->ip_addresses; nsd.options->ip_addresses = ip; break; case 'c': configfile = optarg; break; case 'd': nsd.debug = 1; break; case 'f': break; case 'h': usage(); exit(0); case 'i': nsd.identity = optarg; break; case 'I': if (nsd.nsid_len != 0) { /* can only be given once */ break; } if (strncasecmp(optarg, "ascii_", 6) == 0) { nsd.nsid = xalloc(strlen(optarg+6)); nsd.nsid_len = strlen(optarg+6); memmove(nsd.nsid, optarg+6, nsd.nsid_len); } else { if (strlen(optarg) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(optarg) / 2); nsd.nsid_len = strlen(optarg) / 2; if (hex_pton(optarg, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", optarg); } } break; case 'l': nsd.log_filename = optarg; break; case 'N': i = atoi(optarg); if (i <= 0) { error("number of child servers must be greater than zero."); } else { nsd.child_count = i; } break; case 'n': i = atoi(optarg); if (i <= 0) { error("number of concurrent TCP connections must greater than zero."); } else { nsd.maximum_tcp_count = i; } break; case 'P': nsd.pidfile = optarg; break; case 'p': if (atoi(optarg) == 0) { error("port argument must be numeric."); } tcp_port = optarg; udp_port = optarg; break; case 's': #ifdef BIND8_STATS nsd.st_period = atoi(optarg); #else /* !BIND8_STATS */ error("BIND 8 statistics not enabled."); #endif /* BIND8_STATS */ break; case 't': #ifdef HAVE_CHROOT nsd.chrootdir = optarg; #else /* !HAVE_CHROOT */ error("chroot not supported on this platform."); #endif /* HAVE_CHROOT */ break; case 'u': nsd.username = optarg; break; case 'V': verbosity = atoi(optarg); break; case 'v': version(); /* version exits */ break; #ifndef NDEBUG case 'F': sscanf(optarg, "%x", &nsd_debug_facilities); break; case 'L': sscanf(optarg, "%d", &nsd_debug_level); break; #endif /* NDEBUG */ case '?': default: usage(); exit(1); } } argc -= optind; /* argv += optind; */ /* Commandline parse error */ if (argc != 0) { usage(); exit(1); } if (strlen(nsd.identity) > UCHAR_MAX) { error("server identity too long (%u characters)", (unsigned) strlen(nsd.identity)); } if(!tsig_init(nsd.region)) error("init tsig failed"); pp_init(&write_uint16, &write_uint32); /* Read options */ if(!parse_options_file(nsd.options, configfile, NULL, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { error("could not read zonelist file %s\n", nsd.options->zonelistfile); } if(nsd.options->do_ip4 && !nsd.options->do_ip6) { hints.ai_family = AF_INET; } #ifdef INET6 if(nsd.options->do_ip6 && !nsd.options->do_ip4) { hints.ai_family = AF_INET6; } #endif /* INET6 */ if (verbosity == 0) verbosity = nsd.options->verbosity; #ifndef NDEBUG if (nsd_debug_level > 0 && verbosity == 0) verbosity = nsd_debug_level; #endif /* NDEBUG */ if(nsd.options->debug_mode) nsd.debug=1; if(!nsd.pidfile) { if(nsd.options->pidfile) nsd.pidfile = nsd.options->pidfile; else nsd.pidfile = PIDFILE; } if(strcmp(nsd.identity, hostname)==0 || strcmp(nsd.identity,IDENTITY)==0) { if(nsd.options->identity) nsd.identity = nsd.options->identity; } if(nsd.options->version) { nsd.version = nsd.options->version; } if (nsd.options->logfile && !nsd.log_filename) { nsd.log_filename = nsd.options->logfile; } 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; } nsd.tcp_timeout = nsd.options->tcp_timeout; nsd.tcp_query_count = nsd.options->tcp_query_count; nsd.tcp_mss = nsd.options->tcp_mss; nsd.outgoing_tcp_mss = nsd.options->outgoing_tcp_mss; nsd.ipv4_edns_size = nsd.options->ipv4_edns_size; nsd.ipv6_edns_size = nsd.options->ipv6_edns_size; #ifdef HAVE_SSL nsd.tls_ctx = NULL; nsd.tls_auth_ctx = NULL; #endif if(udp_port == 0) { if(nsd.options->port != 0) { udp_port = nsd.options->port; tcp_port = nsd.options->port; } else { udp_port = UDP_PORT; tcp_port = TCP_PORT; } } if(nsd.options->verify_port != 0) { verify_port = nsd.options->verify_port; } else { verify_port = VERIFY_PORT; } #ifdef BIND8_STATS if(nsd.st_period == 0) { nsd.st_period = nsd.options->statistics; } #endif /* BIND8_STATS */ #ifdef HAVE_CHROOT if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; #ifdef CHROOTDIR /* if still no chrootdir, fallback to default */ if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; #endif /* CHROOTDIR */ #endif /* HAVE_CHROOT */ if(nsd.username == 0) { if(nsd.options->username) nsd.username = nsd.options->username; else nsd.username = USER; } if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("cannot chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } /* EDNS0 */ edns_init_data(&nsd.edns_ipv4, nsd.options->ipv4_edns_size); #if defined(INET6) #if defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); #else /* no way to set IPV6 MTU, send no bigger than that. */ if (nsd.options->ipv6_edns_size < IPV6_MIN_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); else edns_init_data(&nsd.edns_ipv6, IPV6_MIN_MTU); #endif /* IPV6 MTU) */ #endif /* defined(INET6) */ reconfig_cookies(&nsd, nsd.options); if (nsd.nsid_len == 0 && nsd.options->nsid) { if (strlen(nsd.options->nsid) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(nsd.options->nsid) / 2); nsd.nsid_len = strlen(nsd.options->nsid) / 2; if (hex_pton(nsd.options->nsid, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", nsd.options->nsid); } } edns_init_nsid(&nsd.edns_ipv4, nsd.nsid_len); #if defined(INET6) edns_init_nsid(&nsd.edns_ipv6, nsd.nsid_len); #endif /* defined(INET6) */ #ifdef HAVE_CPUSET_T nsd.use_cpu_affinity = (nsd.options->cpu_affinity != NULL); if(nsd.use_cpu_affinity) { int ncpus; struct cpu_option* opt = nsd.options->cpu_affinity; if((ncpus = number_of_cpus()) == -1) { error("cannot retrieve number of cpus: %s", strerror(errno)); } nsd.cpuset = cpuset_create(); region_add_cleanup(nsd.region, free_cpuset, nsd.cpuset); for(; opt; opt = opt->next) { assert(opt->cpu >= 0); if(opt->cpu >= ncpus) { error("invalid cpu %d specified in " "cpu-affinity", opt->cpu); } cpuset_set((cpuid_t)opt->cpu, nsd.cpuset); } } if(nsd.use_cpu_affinity) { int cpu; struct cpu_map_option *opt = nsd.options->service_cpu_affinity; cpu = -1; for(; opt && cpu == -1; opt = opt->next) { if(opt->service == -1) { cpu = opt->cpu; assert(cpu >= 0); } } nsd.xfrd_cpuset = cpuset_create(); region_add_cleanup(nsd.region, free_cpuset, nsd.xfrd_cpuset); if(cpu == -1) { cpuset_or(nsd.xfrd_cpuset, nsd.cpuset); } else { if(!cpuset_isset(cpu, nsd.cpuset)) { error("cpu %d specified in xfrd-cpu-affinity " "is not specified in cpu-affinity", cpu); } cpuset_set((cpuid_t)cpu, nsd.xfrd_cpuset); } } #endif /* HAVE_CPUSET_T */ /* Number of child servers to fork. */ nsd.children = (struct nsd_child *) region_alloc_array( nsd.region, nsd.child_count, sizeof(struct nsd_child)); for (i = 0; i < nsd.child_count; ++i) { nsd.children[i].kind = NSD_SERVER_BOTH; nsd.children[i].pid = -1; nsd.children[i].child_fd = -1; nsd.children[i].parent_fd = -1; nsd.children[i].handler = NULL; nsd.children[i].need_to_send_STATS = 0; nsd.children[i].need_to_send_QUIT = 0; nsd.children[i].need_to_exit = 0; nsd.children[i].has_exited = 0; #ifdef BIND8_STATS nsd.children[i].query_count = 0; #endif #ifdef HAVE_CPUSET_T if(nsd.use_cpu_affinity) { int cpu, server; struct cpu_map_option *opt = nsd.options->service_cpu_affinity; cpu = -1; server = i+1; for(; opt && cpu == -1; opt = opt->next) { if(opt->service == server) { cpu = opt->cpu; assert(cpu >= 0); } } nsd.children[i].cpuset = cpuset_create(); region_add_cleanup(nsd.region, free_cpuset, nsd.children[i].cpuset); if(cpu == -1) { cpuset_or(nsd.children[i].cpuset, nsd.cpuset); } else { if(!cpuset_isset((cpuid_t)cpu, nsd.cpuset)) { error("cpu %d specified in " "server-%d-cpu-affinity is not " "specified in cpu-affinity", cpu, server); } cpuset_set( (cpuid_t)cpu, nsd.children[i].cpuset); } } #endif /* HAVE_CPUSET_T */ } nsd.this_child = NULL; resolve_interface_names(nsd.options); figure_sockets(&nsd.udp, &nsd.tcp, &nsd.ifs, nsd.options->ip_addresses, NULL, udp_port, tcp_port, &hints); if(nsd.options->verify_enable) { figure_sockets(&nsd.verify_udp, &nsd.verify_tcp, &nsd.verify_ifs, nsd.options->verify_ip_addresses, "localhost", verify_port, verify_port, &hints); setup_verifier_environment(); } /* Parse the username into uid and gid */ nsd.gid = getgid(); nsd.uid = getuid(); #ifdef HAVE_GETPWNAM /* Parse the username into uid and gid */ if (*nsd.username) { if (isdigit((unsigned char)*nsd.username)) { char *t; nsd.uid = strtol(nsd.username, &t, 10); if (*t != 0) { if (*t != '.' || !isdigit((unsigned char)*++t)) { error("-u user or -u uid or -u uid.gid"); } nsd.gid = strtol(t, &t, 10); } else { /* Lookup the group id in /etc/passwd */ if ((pwd = getpwuid(nsd.uid)) == NULL) { error("user id %u does not exist.", (unsigned) nsd.uid); } else { nsd.gid = pwd->pw_gid; } } } else { /* Lookup the user id in /etc/passwd */ if ((pwd = getpwnam(nsd.username)) == NULL) { error("user '%s' does not exist.", nsd.username); } else { nsd.uid = pwd->pw_uid; nsd.gid = pwd->pw_gid; } } } /* endpwent(); */ #endif /* HAVE_GETPWNAM */ #if defined(HAVE_SSL) key_options_tsig_add(nsd.options); #endif append_trailing_slash(&nsd.options->xfrdir, nsd.options->region); /* Check relativity of pathnames to chroot */ if (nsd.chrootdir && nsd.chrootdir[0]) { /* existing chrootdir: append trailing slash for strncmp checking */ append_trailing_slash(&nsd.chrootdir, nsd.region); append_trailing_slash(&nsd.options->zonesdir, nsd.options->region); /* zonesdir must be absolute and within chroot, * all other pathnames may be relative to zonesdir */ if (strncmp(nsd.options->zonesdir, nsd.chrootdir, strlen(nsd.chrootdir)) != 0) { error("zonesdir %s has to be an absolute path that starts with the chroot path %s", nsd.options->zonesdir, nsd.chrootdir); } else if (!file_inside_chroot(nsd.pidfile, nsd.chrootdir)) { error("pidfile %s is not relative to %s: chroot not possible", nsd.pidfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdfile, nsd.chrootdir)) { error("xfrdfile %s is not relative to %s: chroot not possible", nsd.options->xfrdfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->zonelistfile, nsd.chrootdir)) { error("zonelistfile %s is not relative to %s: chroot not possible", nsd.options->zonelistfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdir, nsd.chrootdir)) { error("xfrdir %s is not relative to %s: chroot not possible", nsd.options->xfrdir, nsd.chrootdir); } } /* Set up the logging */ log_open(LOG_PID, FACILITY, nsd.log_filename); if(nsd.options->log_only_syslog) log_set_log_function(log_only_syslog); else if (!nsd.log_filename) log_set_log_function(log_syslog); else if (nsd.uid && nsd.gid) { if(chown(nsd.log_filename, nsd.uid, nsd.gid) != 0) VERBOSITY(2, (LOG_WARNING, "chown %s failed: %s", nsd.log_filename, strerror(errno))); } log_msg(LOG_NOTICE, "%s starting (%s)", argv0, PACKAGE_STRING); /* Do we have a running nsd? */ /* When there is a username configured, we assume that due to * privilege drops, the pidfile could not be removed by NSD and * as such could be lingering around. We could not remove it, * and also not chown it as that creates privilege escape problems. * The init system could remove the pidfile after use for us, but * it is not sure if it is configured to do so. */ if(nsd.pidfile && nsd.pidfile[0] && !(nsd.username && nsd.username[0])) { if ((oldpid = readpid(nsd.pidfile)) == -1) { if (errno != ENOENT) { log_msg(LOG_ERR, "can't read pidfile %s: %s", nsd.pidfile, strerror(errno)); } } else { if (kill(oldpid, 0) == 0 || errno == EPERM) { log_msg(LOG_WARNING, "%s is already running as %u, continuing", argv0, (unsigned) oldpid); } else { log_msg(LOG_ERR, "...stale pid file from process %u", (unsigned) oldpid); } } } #ifdef HAVE_SETPROCTITLE setproctitle("main"); #endif #ifdef HAVE_CPUSET_T if(nsd.use_cpu_affinity) { set_cpu_affinity(nsd.cpuset); } #endif print_sockets(nsd.udp, nsd.tcp, nsd.ifs); /* Setup the signal handling... */ action.sa_handler = sig_handler; sigfillset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGTERM, &action, NULL); sigaction(SIGHUP, &action, NULL); sigaction(SIGINT, &action, NULL); sigaction(SIGILL, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGALRM, &action, NULL); sigaction(SIGCHLD, &action, NULL); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); /* Initialize... */ nsd.mode = NSD_RUN; nsd.signal_hint_child = 0; nsd.signal_hint_reload = 0; nsd.signal_hint_reload_hup = 0; nsd.signal_hint_quit = 0; nsd.signal_hint_shutdown = 0; nsd.signal_hint_stats = 0; nsd.signal_hint_statsusr = 0; nsd.quit_sync_done = 0; /* Initialize the server... */ if (server_init(&nsd) != 0) { error("server initialization failed, %s could " "not be started", argv0); } #if defined(HAVE_SSL) if(nsd.options->control_enable || (nsd.options->tls_service_key && nsd.options->tls_service_key[0])) { perform_openssl_init(); } #endif /* HAVE_SSL */ if(nsd.options->control_enable) { /* read ssl keys while superuser and outside chroot */ if(!(nsd.rc = daemon_remote_create(nsd.options))) error("could not perform remote control setup"); } #ifdef USE_METRICS if(nsd.options->metrics_enable) { if(!(nsd.metrics = daemon_metrics_create(nsd.options))) error("could not perform metrics server setup"); } #endif /* USE_METRICS */ #if defined(HAVE_SSL) if(nsd.options->tls_service_key && nsd.options->tls_service_key[0] && nsd.options->tls_service_pem && nsd.options->tls_service_pem[0]) { /* normal tls port with no client authentication */ if(!(nsd.tls_ctx = server_tls_ctx_create(&nsd, NULL, nsd.options->tls_service_ocsp))) error("could not set up tls SSL_CTX"); /* tls-auth port with required client authentication */ if(nsd.options->tls_auth_port) { if(!(nsd.tls_auth_ctx = server_tls_ctx_create(&nsd, (char*)nsd.options->tls_cert_bundle, nsd.options->tls_service_ocsp))) error("could not set up tls SSL_CTX"); } } #endif /* HAVE_SSL */ /* Unless we're debugging, fork... */ if (!nsd.debug) { int fd; /* Take off... */ switch (fork()) { case 0: /* Child */ break; case -1: error("fork() failed: %s", strerror(errno)); break; default: /* Parent is done */ server_close_all_sockets(nsd.udp, nsd.ifs); server_close_all_sockets(nsd.tcp, nsd.ifs); exit(0); } /* Detach ourselves... */ if (setsid() == -1) { error("setsid() failed: %s", strerror(errno)); } if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > 2) (void)close(fd); } } /* Get our process id */ nsd.pid = getpid(); /* Set user context */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_SETUSERCONTEXT /* setusercontext does initgroups, setuid, setgid, and * also resource limits from login config, but we * still call setresuid, setresgid to be sure to set all uid */ if (setusercontext(NULL, pwd, nsd.uid, LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) log_msg(LOG_WARNING, "unable to setusercontext %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_SETUSERCONTEXT */ } #endif /* HAVE_GETPWNAM */ /* Chroot */ #ifdef HAVE_CHROOT if (nsd.chrootdir && nsd.chrootdir[0]) { int l = strlen(nsd.chrootdir)-1; /* ends in trailing slash */ if (file_inside_chroot(nsd.log_filename, nsd.chrootdir)) nsd.file_rotation_ok = 1; /* strip chroot from pathnames if they're absolute */ nsd.options->zonesdir += l; if (nsd.log_filename){ if (nsd.log_filename[0] == '/') nsd.log_filename += l; } if (nsd.pidfile && nsd.pidfile[0] == '/') nsd.pidfile += l; if (nsd.options->xfrdfile[0] == '/') nsd.options->xfrdfile += l; if (nsd.options->zonelistfile[0] == '/') nsd.options->zonelistfile += l; if (nsd.options->xfrdir[0] == '/') nsd.options->xfrdir += l; /* strip chroot from pathnames of "include:" statements * on subsequent repattern commands */ cfg_parser->chroot = nsd.chrootdir; #ifdef HAVE_TZSET /* set timezone whilst not yet in chroot */ tzset(); #endif if (chroot(nsd.chrootdir)) { error("unable to chroot: %s", strerror(errno)); } if (chdir("/")) { error("unable to chdir to chroot: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", nsd.chrootdir)); /* chdir to zonesdir again after chroot */ if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("unable to chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } } else #endif /* HAVE_CHROOT */ nsd.file_rotation_ok = 1; DEBUG(DEBUG_IPC,1, (LOG_INFO, "file rotation on %s %sabled", nsd.log_filename, nsd.file_rotation_ok?"en":"dis")); /* Write pidfile */ if (writepid(&nsd) == -1) { log_msg(LOG_ERR, "cannot overwrite the pidfile %s: %s", nsd.pidfile, strerror(errno)); } /* Drop the permissions */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_INITGROUPS if(initgroups(nsd.username, nsd.gid) != 0) log_msg(LOG_WARNING, "unable to initgroups %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_INITGROUPS */ endpwent(); #ifdef HAVE_SETRESGID if(setresgid(nsd.gid,nsd.gid,nsd.gid) != 0) #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) if(setregid(nsd.gid,nsd.gid) != 0) #else /* use setgid */ if(setgid(nsd.gid) != 0) #endif /* HAVE_SETRESGID */ error("unable to set group id of %s: %s", nsd.username, strerror(errno)); #ifdef HAVE_SETRESUID if(setresuid(nsd.uid,nsd.uid,nsd.uid) != 0) #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) if(setreuid(nsd.uid,nsd.uid) != 0) #else /* use setuid */ if(setuid(nsd.uid) != 0) #endif /* HAVE_SETRESUID */ error("unable to set user id of %s: %s", nsd.username, strerror(errno)); DEBUG(DEBUG_IPC,1, (LOG_INFO, "dropped user privileges, run as %s", nsd.username)); } #endif /* HAVE_GETPWNAM */ xfrd_make_tempdir(&nsd); #ifdef USE_ZONE_STATS options_zonestatnames_create(nsd.options); server_zonestat_alloc(&nsd); #endif /* USE_ZONE_STATS */ #ifdef BIND8_STATS server_stat_alloc(&nsd); #endif /* BIND8_STATS */ if(nsd.server_kind == NSD_SERVER_MAIN) { server_prepare_xfrd(&nsd); /* xfrd forks this before reading database, so it does not get * the memory size of the database */ server_start_xfrd(&nsd, 0, 0); /* close zonelistfile in non-xfrd processes */ zone_list_close(nsd.options); #ifdef USE_DNSTAP if(nsd.options->dnstap_enable) { nsd.dt_collector = dt_collector_create(&nsd); dt_collector_start(nsd.dt_collector, &nsd); } #endif /* USE_DNSTAP */ } if (server_prepare(&nsd) != 0) { unlinkpid(nsd.pidfile, nsd.username); error("server preparation failed, %s could " "not be started", argv0); } if(nsd.server_kind == NSD_SERVER_MAIN) { server_send_soa_xfrd(&nsd, 0); } /* Really take off */ log_msg(LOG_NOTICE, "%s started (%s), pid %d", argv0, PACKAGE_STRING, (int) nsd.pid); if (nsd.server_kind == NSD_SERVER_MAIN) { server_main(&nsd); } else { server_child(&nsd); } /* NOTREACH */ exit(0); } nsd-4.12.0/nsd.8.in0000644000175000017500000001210215002373060013250 0ustar mozziemozzie.TH "NSD" "8" "Apr 24, 2025" "NLnet Labs" "NSD 4.12.0" .\" Copyright (c) 2001\-2024, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd \- Name Server Daemon (NSD) version 4.12.0. .SH "SYNOPSIS" .B nsd .RB [ \-4 ] .RB [ \-6 ] .RB [ \-a .IR ip\-address[@port] ] .RB [ \-c .IR configfile ] .RB [ \-d ] .RB [ \-h ] .RB [ \-i .IR identity ] .RB [ \-I .IR nsid ] .RB [ \-l .IR logfile ] .RB [ \-N .IR server\-count ] .RB [ \-n .IR noncurrent\-tcp\-count ] .RB [ \-P .IR pidfile ] .RB [ \-p .IR port ] .RB [ \-s .IR seconds ] .RB [ \-t .IR chrootdir ] .RB [ \-u .IR username ] .RB [ \-V .IR level ] .RB [ \-v ] .SH "DESCRIPTION" .B NSD is a complete implementation of an authoritative DNS nameserver. Upon startup, .B NSD will read the configuration file and put itself into the background and answers queries on port 53 or a different port specified with .B \-p .I port option. By default, .B NSD will bind to all local interfaces available. Use the .B \-a .I ip\-address[@port] option to specify a single particular interface address to be bound. If this option is given more than once, .B NSD will bind its UDP and TCP sockets to all the specified ip\-addresses separately. If IPv6 is enabled when .B NSD is compiled an IPv6 address can also be specified. .SH "OPTIONS" All the options can be specified in the configfile ( .B \-c argument), except for the .B \-v and .B \-h options. If options are specified on the commandline, the options on the commandline take precedence over the options in the configfile. .P Normally .B 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. .TP .B \-6 Only listen to IPv6 connections. .TP .B \-a\fI ip\-address[@port] Listen to the specified .IR ip\-address . The .I ip\-address must be specified in numeric format (using the standard IPv4 or IPv6 notation). Optionally, a port number can be given. This flag can be specified multiple times to listen to multiple IP addresses. If this flag is not specified, .B NSD listens to the wildcard interface. .TP .B \-c\fI configfile Read specified .I configfile instead of the default .IR @nsdconfigfile@ . For format description see nsd.conf(5). .TP .B \-d Do not fork, stay in the foreground. .TP .B \-h Print help information and exit. .TP .B \-i\fI identity Return the specified .I identity when asked for .I CH TXT ID.SERVER (This option is used to determine which server is answering the queries when they are anycast). The default is the name returned by gethostname(3). .TP .B \-I\fI nsid Add the specified .I nsid to the EDNS section of the answer when queried with an NSID EDNS enabled packet. As a sequence of hex characters or with ascii_ prefix and then an ascii string. .TP .B \-l\fI logfile Log messages to the specified .IR logfile . The default is to log to stderr and syslog. If a .B zonesdir: is specified in the config file this path can be relative to that directory. .TP .B \-N\fI count Start .I count .B NSD servers. The default is 1. Starting more than a single server is only useful on machines with multiple CPUs and/or network adapters. .TP .B \-n\fI number The maximum .I number of concurrent TCP connection that can be handled by each server. The default is 100. .TP .B \-P\fI pidfile Use the specified .I pidfile instead of the platform specific default, which is mostly .IR @pidfile@ . If a .B zonesdir: is specified in the config file, this path can be relative to that directory. .TP .B \-p\fI port Answer the queries on the specified .IR port . Normally this is port 53. .TP .B \-s\fI seconds Produce statistics dump every .I seconds seconds. This is equal to sending .I SIGUSR1 to the daemon periodically. .TP .B \-t\fI chroot Specifies a directory to .I chroot 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 .I username after binding the socket. The .I username must be one of: username, id, or id.gid. For example: nsd, 80, or 80.80. .TP .B \-V\fI level This value specifies the verbosity level for (non\-debug) logging. Default is 0. .TP .B \-v Print the version number of .B NSD to standard error and exit. .LP .B NSD reacts to the following signals: .TP SIGTERM .br Stop answering queries, shutdown, and exit normally. .TP SIGHUP .br Reopen logfile (assists rotation) and optionally update TSIG keys and zones. .TP SIGUSR1 .br Dump BIND8\-style statistics into the log. Ignored otherwise. .SH "FILES" .TP @pidfile@ the process id of the name server. .TP @nsdconfigfile@ default .B NSD configuration file .SH "DIAGNOSTICS" .B NSD will log all the problems via the standard syslog(8) .I daemon facility, unless the .B \-d option is specified. .SH "SEE ALSO" \fInsd.conf\fR(5), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. nsd-4.12.0/nsd-mem.c0000644000175000017500000001615015002373054013504 0ustar mozziemozzie/* * nsd-mem.c -- nsd-mem(8) * * Copyright (c) 2013, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "nsd.h" #include "tsig.h" #include "options.h" #include "namedb.h" #include "difffile.h" #include "util.h" #include "ixfr.h" struct nsd nsd; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd-mem [-c configfile]\n"); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } /* zone memory structure */ struct zone_mem { /* size of data (allocated in db.region) */ size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; /* count of number of domains */ size_t domaincount; }; /* total memory structure */ struct tot_mem { /* size of data (allocated in db.region) */ size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; /* count of number of domains */ size_t domaincount; /* options data */ size_t opt_data; /* unused in options region */ size_t opt_unused; /* dname compression table */ size_t compresstable; #ifdef RATELIMIT /* size of rrl tables */ size_t rrl; #endif /* total ram usage */ size_t ram; }; static void account_zone(struct namedb* db, struct zone_mem* zmem) { zmem->data = region_get_mem(db->region); zmem->data_unused = region_get_mem_unused(db->region); zmem->domaincount = domain_table_count(db->domains); } static void pretty_mem(size_t x, const char* s) { char buf[32]; memset(buf, 0, sizeof(buf)); if(snprintf(buf, sizeof(buf), "%12lld", (long long)x) > 12) { printf("%12lld %s\n", (long long)x, s); return; } printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %s\n", buf[0], buf[1], buf[2], (buf[2]==' '?' ':'.'), buf[3], buf[4], buf[5], (buf[5]==' '?' ':'.'), buf[6], buf[7], buf[8], (buf[8]==' '?' ':'.'), buf[9], buf[10], buf[11], s); } static void print_zone_mem(struct zone_mem* z) { pretty_mem(z->data, "zone data"); pretty_mem(z->data_unused, "zone unused space (due to alignment)"); } static void account_total(struct nsd_options* opt, struct tot_mem* t) { t->opt_data = region_get_mem(opt->region); t->opt_unused = region_get_mem_unused(opt->region); t->compresstable = sizeof(uint16_t) * (t->domaincount + 1 + EXTRA_DOMAIN_NUMBERS); t->compresstable *= opt->server_count; #ifdef RATELIMIT #define SIZE_RRL_BUCKET (8 + 4 + 4 + 4 + 4 + 2) t->rrl = opt->rrl_size * SIZE_RRL_BUCKET; t->rrl *= opt->server_count; #endif t->ram = t->data + t->data_unused + t->opt_data + t->opt_unused + t->compresstable; #ifdef RATELIMIT t->ram += t->rrl; #endif } static void print_tot_mem(struct tot_mem* t) { printf("\ntotal\n"); pretty_mem(t->data, "data"); pretty_mem(t->data_unused, "unused space (due to alignment)"); pretty_mem(t->opt_data, "options"); pretty_mem(t->opt_unused, "options unused space (due to alignment)"); pretty_mem(t->compresstable, "name table (depends on servercount)"); #ifdef RATELIMIT pretty_mem(t->rrl, "RRL table (depends on servercount)"); #endif printf("\nsummary\n"); pretty_mem(t->ram, "ram usage (excl space for buffers)"); } static void add_mem(struct tot_mem* t, struct zone_mem* z) { t->data += z->data; t->data_unused += z->data_unused; t->domaincount += z->domaincount; } static void check_zone_mem(const char* tf, struct zone_options* zo, struct nsd_options* opt, struct tot_mem* totmem) { struct nsd nsd; struct namedb* db; const dname_type* dname = (const dname_type*)zo->node.key; zone_type* zone; struct udb_base* taskudb; udb_ptr last_task; struct zone_mem zmem; printf("zone %s\n", zo->name); /* init*/ memset(&zmem, 0, sizeof(zmem)); memset(&nsd, 0, sizeof(nsd)); nsd.region = region_create(xalloc, free); nsd.db = db = namedb_open(opt); if(!db) error("cannot open namedb"); zone = namedb_zone_create(db, dname, zo); taskudb = task_file_create(tf); udb_ptr_init(&last_task, taskudb); /* read the zone */ namedb_read_zonefile(&nsd, zone, taskudb, &last_task); /* account the memory for this zone */ account_zone(db, &zmem); /* pretty print the memory for this zone */ print_zone_mem(&zmem); /* delete the zone from memory */ zone_ixfr_free(zone->ixfr); namedb_close(db); udb_base_free(taskudb); unlink(tf); region_destroy(nsd.region); /* add up totals */ add_mem(totmem, &zmem); } static void check_mem(struct nsd_options* opt) { struct tot_mem totmem; struct zone_options* zo; char tf[512]; memset(&totmem, 0, sizeof(totmem)); snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid()); /* read all zones and account memory */ RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { check_zone_mem(tf, zo, opt, &totmem); } /* calculate more total statistics */ account_total(opt, &totmem); /* print statistics */ print_tot_mem(&totmem); nsd_options_destroy(opt); } /* dummy functions to link */ struct nsd; int writepid(struct nsd * ATTR_UNUSED(nsd)) { return 0; } void unlinkpid(const char * ATTR_UNUSED(file), const char* ATTR_UNUSED(username)) { } void bind8_stats(struct nsd * ATTR_UNUSED(nsd)) { } void sig_handler(int ATTR_UNUSED(sig)) { } extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; struct nsd nsd; const char *configfile = CONFIGFILE; memset(&nsd, 0, sizeof(nsd)); log_init("nsd-mem"); /* Parse the command line... */ while ((c = getopt(argc, argv, "c:h" )) != -1) { switch (c) { case 'c': configfile = optarg; break; case 'h': usage(); exit(0); case '?': default: usage(); exit(1); } } argc -= optind; /* argv += optind; move along argv for positional arguments */ /* Commandline parse error */ if (argc != 0) { usage(); exit(1); } /* Read options */ nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); tsig_init(nsd.options->region); if(!parse_options_file(nsd.options, configfile, NULL, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { error("could not read zonelist file %s\n", nsd.options->zonelistfile); } if (verbosity == 0) verbosity = nsd.options->verbosity; #ifdef HAVE_CHROOT if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; #ifdef CHROOTDIR /* if still no chrootdir, fallback to default */ if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; #endif /* CHROOTDIR */ #endif /* HAVE_CHROOT */ if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("cannot chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } /* Chroot */ #ifdef HAVE_CHROOT if (nsd.chrootdir && strlen(nsd.chrootdir)) { if(chdir(nsd.chrootdir)) { error("unable to chdir to chroot: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", nsd.chrootdir)); } #endif /* HAVE_CHROOT */ check_mem(nsd.options); exit(0); } nsd-4.12.0/nsd-control.c0000644000175000017500000004352015002373054014407 0ustar mozziemozzie/* * nsd-control.c - remote control utility for nsd. * * Copyright (c) 2011, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * The remote control utility contacts the nsd server over ssl and * sends the command, receives the answer, and displays the result * from the commandline. */ #include "config.h" #include #include struct region; struct domain_table; struct zone; struct domain; int zonec_parse_string(struct region* ATTR_UNUSED(region), struct domain_table* ATTR_UNUSED(domains), struct zone* ATTR_UNUSED(zone), char* ATTR_UNUSED(str), struct domain** ATTR_UNUSED(parsed), int* ATTR_UNUSED(num_rrs)) { return 0; } #include #include #include #include #ifdef HAVE_SSL #ifdef HAVE_OPENSSL_SSL_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #endif /* HAVE_SSL */ #ifdef HAVE_SYS_UN_H #include #endif #include #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif #include "util.h" #include "tsig.h" #include "options.h" #include "zonec.h" static void usage(void) ATTR_NORETURN; #ifdef HAVE_SSL static void ssl_err(const char* s) ATTR_NORETURN; static void ssl_path_err(const char* s, const char *path) ATTR_NORETURN; #else /* define SSL to use as a boolean to turn it off in function calls. */ #define SSL int #endif /** timeout to wait for connection over stream, in msec */ #define NSD_CONTROL_CONNECT_TIMEOUT 5000 /** Give nsd-control usage, and exit (1). */ static void usage() { printf("Usage: nsd-control [options] command\n"); printf(" Remote control utility for nsd server.\n"); printf("Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); printf("Options:\n"); printf(" -c file config file, default is %s\n", CONFIGFILE); printf(" -s ip[@port] server address, if omitted config is used.\n"); printf(" -h show this usage help.\n"); printf("Commands:\n"); printf(" start start server; runs nsd(8)\n"); printf(" stop stops the server\n"); printf(" reload [] reload modified zonefiles from disk\n"); printf(" reconfig reload the config file\n"); printf(" repattern the same as reconfig\n"); printf(" log_reopen reopen logfile (for log rotate)\n"); printf(" status display status of server\n"); printf(" stats print statistics\n"); printf(" stats_noreset peek at statistics\n"); printf(" addzone add a new zone\n"); printf(" delzone remove a zone\n"); printf(" changezone change zone to use pattern\n"); printf(" addzones add zone list on stdin {name space pattern newline}\n"); printf(" delzones remove zone list on stdin {name newline}\n"); printf(" write [] write changed zonefiles to disk\n"); printf(" notify [] send NOTIFY messages to secondary servers\n"); printf(" transfer [] try to update secondary zones to newer serial\n"); printf(" force_transfer [] update secondary zones with AXFR, no serial check\n"); printf(" zonestatus [] print state, serial, activity\n"); printf(" serverpid get pid of server process\n"); printf(" verbosity change logging detail\n"); printf(" print_tsig [] print tsig with the secret and algo\n"); printf(" update_tsig change existing tsig with to a new \n"); printf(" add_tsig [algo] add new key with the given parameters\n"); printf(" assoc_tsig associate with given tsig name\n"); printf(" del_tsig delete tsig from configuration\n"); printf(" add_cookie_secret add (or replace) a new cookie secret \n"); printf(" drop_cookie_secret drop a staging cookie secret\n"); printf(" activate_cookie_secret make a staging cookie secret active\n"); printf(" print_cookie_secrets show all cookie secrets with their status\n"); exit(1); } #ifdef HAVE_SSL /** exit with ssl error */ static void ssl_err(const char* s) { fprintf(stderr, "error: %s\n", s); ERR_print_errors_fp(stderr); exit(1); } /** exit with ssl error related to a file path */ static void ssl_path_err(const char* s, const char *path) { unsigned long err; err = ERR_peek_error(); if (ERR_GET_LIB(err) == ERR_LIB_SYS) { fprintf(stderr, "error: %s\n%s: %s\n", s, path, ERR_reason_error_string(err)); exit(1); } else { ssl_err(s); } } /** setup SSL context */ static SSL_CTX* setup_ctx(struct nsd_options* cfg) { char* s_cert, *c_key, *c_cert; SSL_CTX* ctx; if(!options_remote_is_address(cfg)) return NULL; s_cert = cfg->server_cert_file; c_key = cfg->control_key_file; c_cert = cfg->control_cert_file; /* filenames may be relative to zonesdir */ if (cfg->zonesdir && cfg->zonesdir[0] && (s_cert[0] != '/' || c_key[0] != '/' || c_cert[0] != '/')) { if(chdir(cfg->zonesdir)) error("could not chdir to zonesdir: %s %s", cfg->zonesdir, strerror(errno)); } ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); #if SSL_OP_NO_SSLv2 != 0 if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) ssl_err("could not set SSL_OP_NO_SSLv2"); #endif if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); #if defined(SSL_OP_NO_RENEGOTIATION) /* disable client renegotiation */ if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) & SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) ssl_err("could not set SSL_OP_NO_RENEGOTIATION"); #endif if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client cert", c_cert); if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client key", c_key); if(!SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_path_err("Error setting up SSL_CTX verify, server cert", s_cert); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); return ctx; } #endif /* HAVE_SSL */ /** check connect error */ static void checkconnecterr(int err, const char* svr, int port, int statuscmd) { if(!port) fprintf(stderr, "error: connect (%s): %s\n", svr, strerror(err)); else fprintf(stderr, "error: connect (%s@%d): %s\n", svr, port, strerror(err)); if(err == ECONNREFUSED && statuscmd) { printf("nsd is stopped\n"); exit(3); } exit(1); } /** contact the server with TCP connect */ static int contact_server(const char* svr, struct nsd_options* cfg, int statuscmd) { #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; int fd; int port = cfg->control_port; int addrfamily = 0; /* use svr or a config entry */ if(!svr) { if(cfg->control_interface) { svr = cfg->control_interface->address; } else if(cfg->do_ip4) { svr = "127.0.0.1"; } else { svr = "::1"; } /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; else if(strcmp(svr, "::0") == 0 || strcmp(svr, "0::0") == 0 || strcmp(svr, "0::") == 0 || strcmp(svr, "::") == 0) svr = "::1"; } if(strchr(svr, '@')) { char* ps = strchr(svr, '@'); *ps++ = 0; port = atoi(ps); if(!port) { fprintf(stderr, "could not parse port %s\n", ps); exit(1); } } if(svr[0] == '/') { #ifdef HAVE_SYS_UN_H struct sockaddr_un* usock = (struct sockaddr_un *) &addr; usock->sun_family = AF_LOCAL; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN usock->sun_len = (unsigned)sizeof(usock); #endif (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); addrlen = (socklen_t)sizeof(struct sockaddr_un); addrfamily = AF_LOCAL; port = 0; #endif #ifdef INET6 } else if(strchr(svr, ':')) { struct sockaddr_in6 sa; addrlen = (socklen_t)sizeof(struct sockaddr_in6); memset(&sa, 0, addrlen); sa.sin6_family = AF_INET6; sa.sin6_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin6_family, svr, &sa.sin6_addr) <= 0) { fprintf(stderr, "could not parse IP: %s\n", svr); exit(1); } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET6; #endif } else { /* ip4 */ struct sockaddr_in sa; addrlen = (socklen_t)sizeof(struct sockaddr_in); memset(&sa, 0, addrlen); sa.sin_family = AF_INET; sa.sin_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin_family, svr, &sa.sin_addr) <= 0) { fprintf(stderr, "could not parse IP: %s\n", svr); exit(1); } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET; } fd = socket(addrfamily, SOCK_STREAM, 0); if(fd == -1) { fprintf(stderr, "socket: %s\n", strerror(errno)); exit(1); } if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { fprintf(stderr, "error: set nonblocking: fcntl: %s", strerror(errno)); } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { if(errno != EINPROGRESS) { checkconnecterr(errno, svr, port, statuscmd); } } while(1) { fd_set rset, wset, eset; struct timeval tv; FD_ZERO(&rset); FD_SET(fd, &rset); FD_ZERO(&wset); FD_SET(fd, &wset); FD_ZERO(&eset); FD_SET(fd, &eset); tv.tv_sec = NSD_CONTROL_CONNECT_TIMEOUT/1000; tv.tv_usec= (NSD_CONTROL_CONNECT_TIMEOUT%1000)*1000; if(select(fd+1, &rset, &wset, &eset, &tv) == -1) { fprintf(stderr, "select: %s\n", strerror(errno)); exit(1); } if(!FD_ISSET(fd, &rset) && !FD_ISSET(fd, &wset) && !FD_ISSET(fd, &eset)) { fprintf(stderr, "timeout: could not connect to server\n"); exit(1); } else { /* check nonblocking connect error */ int error = 0; socklen_t len = (socklen_t)sizeof(error); if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len) < 0) { error = errno; /* on solaris errno is error */ } if(error != 0) { if(error == EINPROGRESS || error == EWOULDBLOCK) continue; /* try again later */ checkconnecterr(error, svr, port, statuscmd); } } break; } if(fcntl(fd, F_SETFL, 0) == -1) { fprintf(stderr, "error: set blocking: fcntl: %s", strerror(errno)); } return fd; } #ifdef HAVE_SSL /** setup SSL on the connection */ static SSL* setup_ssl(SSL_CTX* ctx, int fd) { SSL* ssl; X509* x; int r; if(!ctx) return NULL; ssl = SSL_new(ctx); if(!ssl) ssl_err("could not SSL_new"); SSL_set_connect_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) ssl_err("could not SSL_set_fd"); while(1) { ERR_clear_error(); if( (r=SSL_do_handshake(ssl)) == 1) break; r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) ssl_err("SSL handshake failed"); /* wants to be called again */ } /* check authenticity of server */ if(SSL_get_verify_result(ssl) != X509_V_OK) ssl_err("SSL verification failed"); #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE x = SSL_get1_peer_certificate(ssl); #else x = SSL_get_peer_certificate(ssl); #endif if(!x) ssl_err("Server presented no peer certificate"); X509_free(x); return ssl; } #endif /* HAVE_SSL */ /** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ static int remote_read(SSL* ssl, int fd, char* buf, size_t len) { if(ssl) { #ifdef HAVE_SSL int r; ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ return 0; } ssl_err("could not SSL_read"); } buf[r] = 0; #endif /* HAVE_SSL */ } else { ssize_t rr = read(fd, buf, len-1); if(rr <= 0) { if(rr == 0) { /* EOF */ return 0; } fprintf(stderr, "could not read: %s\n", strerror(errno)); exit(1); } buf[rr] = 0; } return 1; } /** write to ssl or fd, fatalexit on error */ static void remote_write(SSL* ssl, int fd, const char* buf, size_t len) { if(ssl) { #ifdef HAVE_SSL if(SSL_write(ssl, buf, (int)len) <= 0) ssl_err("could not SSL_write"); #endif /* HAVE_SSL */ } else { if(write(fd, buf, len) < (ssize_t)len) { fprintf(stderr, "could not write: %s\n", strerror(errno)); exit(1); } } } /** send stdin to server */ static void send_file(SSL* ssl, int fd, FILE* in, char* buf, size_t sz) { char e[] = {0x04, 0x0a}; while(fgets(buf, (int)sz, in)) { remote_write(ssl, fd, buf, strlen(buf)); } /* send end-of-file marker */ remote_write(ssl, fd, e, sizeof(e)); } /** send command and display result */ static int go_cmd(SSL* ssl, int fd, int argc, char* argv[]) { char pre[10]; const char* space=" "; const char* newline="\n"; int was_error = 0, first_line = 1; int i; char buf[1024]; snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION); remote_write(ssl, fd, pre, strlen(pre)); for(i=0; iregion); if(!parse_options_file(opt, cfgfile, NULL, NULL, NULL)) { fprintf(stderr, "could not read config file\n"); exit(1); } if(!opt->control_enable) fprintf(stderr, "warning: control-enable is 'no' in the config file.\n"); resolve_interface_names(opt); #ifdef HAVE_SSL ctx = setup_ctx(opt); #else if(options_remote_is_address(opt)) { fprintf(stderr, "error: NSD was compiled without SSL.\n"); exit(1); } #endif /* HAVE_SSL */ /* contact server */ fd = contact_server(svr, opt, argc>0&&strcmp(argv[0],"status")==0); #ifdef HAVE_SSL ssl = setup_ssl(ctx, fd); #endif /* send command */ ret = go_cmd(ssl, fd, argc, argv); #ifdef HAVE_SSL if(ssl) SSL_free(ssl); #endif close(fd); #ifdef HAVE_SSL if(ctx) SSL_CTX_free(ctx); #endif region_destroy(opt->region); return ret; } /** getopt global, in case header files fail to declare it. */ extern int optind; /** getopt global, in case header files fail to declare it. */ extern char* optarg; /** Main routine for nsd-control */ int main(int argc, char* argv[]) { int c; const char* cfgfile = CONFIGFILE; char* svr = NULL; log_init("nsd-control"); #ifdef HAVE_SSL #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); #endif #if defined(HAVE_ERR_LOAD_SSL_STRINGS) && !defined(DEPRECATED_ERR_LOAD_SSL_STRINGS) ERR_load_SSL_strings(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else OPENSSL_init_ssl(0, NULL); #endif if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); size_t i; v = seed; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); fprintf(stderr, "warning: no entropy, seeding openssl PRNG with time\n"); } #endif /* HAVE_SSL */ /* parse the options */ while( (c=getopt(argc, argv, "c:s:h")) != -1) { switch(c) { case 'c': cfgfile = optarg; break; case 's': svr = optarg; break; case '?': case 'h': default: usage(); } } argc -= optind; argv += optind; if(argc == 0) usage(); if(argc >= 1 && strcmp(argv[0], "start")==0) { const char *path; if((path = getenv("NSD_PATH")) == NULL) { path = NSD_START_PATH; } if(execl(path, "nsd", "-c", cfgfile, (char*)NULL) < 0) { fprintf(stderr, "could not exec %s: %s\n", NSD_START_PATH, strerror(errno)); exit(1); } } return go(cfgfile, svr, argc, argv); } nsd-4.12.0/nsd-control.8.in0000644000175000017500000003240215002373060014733 0ustar mozziemozzie.TH "nsd\-control" "8" "Apr 24, 2025" "NLnet Labs" "nsd 4.12.0" .\" Copyright (c) 2011-2024, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-control, .B nsd\-control\-setup \- NSD remote server control utility. .SH "SYNOPSIS" .B nsd\-control .RB [ \-c .IR cfgfile ] .RB [ \-s .IR server ] .IR command .SH "DESCRIPTION" .B nsd\-control performs remote administration on the \fInsd\fR(8) DNS server. It reads the configuration file, contacts the nsd server over SSL, sends the command and displays the result. Commands that require a reload are queued and the result indicates the command was accepted. .P The available options are: .TP .B \-h Show the version and commandline option help. .TP .B \-c \fIcfgfile The config file to read with settings. If not given the default config file @nsdconfigfile@ is used. .TP .B \-s \fIserver[@port] IPv4 or IPv6 address of the server to contact. If not given, the address is read from the config file. .SH "COMMANDS" There are several commands that the server understands. .TP .B start Start the server. Simply execs \fInsd\fR(8). The nsd executable is not searched for in the \fBPATH\fR set in the environment. Instead the default location relative to the installation prefix specified at compile-time. The executable location can be overridden by setting \fINSD_PATH\fR in the environment. It is started with the config file specified using \fI\-c\fR or the default config file. .TP .B stop Stop the server. The server daemon exits. .TP .B reload [] Reload zonefiles and reopen logfile. Without argument reads changed zonefiles. With argument reads the zonefile for the given zone and loads it. .TP .B reconfig Reload nsd.conf and apply changes to TSIG keys and configuration patterns, and apply the changes to add and remove zones that are mentioned in the config. Other changes are not applied, such as listening ip address and port and chroot, also per-zone statistics are not applied. The pattern updates means that the configuration options for zones (request\-xfr, zonefile, notify, ...) are updated. Also new patterns are available for use with the addzone command. .TP .B repattern Same as the reconfig option. .TP .B log_reopen Reopen the logfile, for log rotate that wants to move the logfile away and create a new logfile. The log can also be reopened with kill \-HUP (which also reloads all zonefiles). .TP .B status Display server status. Exit code 3 if not running (the connection to the port is refused), 1 on error, 0 if running. .TP .B stats Output a sequence of name=value lines with statistics information, requires NSD to be compiled with this option enabled. .TP .B stats_noreset Same as stats, but does not zero the counters. .TP .B addzone Add a new zone to the running server. The zone is added to the zonelist file on disk, so it stays after a restart. The pattern name determines the options for the new zone. For secondary zones a zone transfer is immediately attempted. For zones with a zonefile, the zone file is attempted to be read in. .TP .B delzone Remove the zone from the running server. The zone is removed from the zonelist file on disk, from the nsd.db file and from the memory. If it had a zonefile, this remains (but may be outdated). Zones configured inside nsd.conf itself cannot be removed this way because the daemon does not write to the nsd.conf file, you need to add such zones to the zonelist file to be able to delete them with the delzone command. .TP .B changezone Change a zone to use the pattern for options. The zone is deleted and added in one operation, changing it to use the new pattern for the zone options. Zones configured in nsd.conf cannot be changed like this, instead edit the nsd.conf (or the included file in nsd.conf) and reconfig. .TP .B addzones Add zones read from stdin of nsd\-control. Input is read per line, with name space patternname on a line. For bulk additions. .TP .B delzones Remove zones read from stdin of nsd\-control. Input is one name per line. For bulk removals. .TP .B write [] Write zonefiles to disk, or the given zonefile to disk. Zones that have changed (via AXFR or IXFR) are written, or if the zonefile has not been created yet then it is created. Directory components of the zonefile path are created if necessary. With argument that zone is written if it was modified, without argument, all modified zones are written. .TP .B notify [] Send NOTIFY messages to secondary servers. Sends to the IP addresses configured in the 'notify:' lists for the primary zones hosted on this server. Usually NSD sends NOTIFY messages right away when a primary zone serial is updated. If a zone is given, notifies are sent for that zone. These secondary servers are supposed to initiate a zone transfer request later (to this server or another primary), this can be allowed via the 'provide\-xfr:' acl list configuration. With argument that zone is processed, without argument, all zones are processed. .TP .B transfer [] Attempt to update secondary zones that are hosted on this server by contacting the primaries. The primaries are configured via 'request\-xfr:' lists. If a zone is given, that zone is updated. Usually NSD receives a NOTIFY from the primaries (configured via 'allow\-notify:' acl list) that a new zone serial has to be transferred. For zones with no content, NSD may have backed off from asking often because the primaries did not respond, but this command will reset the backoff to its initial timeout, for frequent retries. With argument that zone is transferred, without argument, all zones are transferred. .TP .B force_transfer [] Force update secondary zones that are hosted on this server. Even if the primary hosts the same serial number of the zone, a full AXFR is performed to fetch it. If you want to use IXFR and check that the serial number increases, use the 'transfer' command. With argument that zone is transferred, without argument, all zones are transferred. .TP .B zonestatus [] Print state of the zone, the serial numbers and since when they have been acquired. Also prints the notify action (to which server), and zone transfer (and from which primary) if there is activity right now. The state of the zone is printed as: 'primary' (primary zones), 'ok' (secondary zone is up\-to\-date), 'expired' (secondary zone has expired), 'refreshing' (secondary zone has transfers active). The serial numbers printed are the 'served\-serial' (currently active), the 'commit\-serial' (is in reload), the 'notified\-serial' (got notify, busy fetching the data). The serial numbers are only printed if such a serial number is available. With argument that zone is printed, without argument, all zones are printed. .TP .B serverpid Prints the PID of the server process. This is used for statistics (and only works when NSD is compiled with statistics enabled). This pid is not for sending unix signals, use the pid from nsd.pid for that, that pid is also stable. .TP .B verbosity Change logging verbosity. .TP .B print_tsig [] print the secret and algorithm for the TSIG key with that name. Or list all the tsig keys with their name, secret and algorithm. .TP .B update_tsig Change existing TSIG key with name to the new secret. The secret is a base64 encoded string. The changes are only in-memory and are gone next restart, for lasting changes edit the nsd.conf file or a file included from it. .TP .B add_tsig [algo] Add a new TSIG key with the given name, secret and algorithm. Without algorithm a default (hmac-sha256) algorithm is used. The secret is a base64 encoded string. The changes are only in-memory and are gone next restart, for lasting changes edit the nsd.conf file or a file included from it. .TP .B assoc_tsig Associate the zone with the given tsig. The access control lists for notify, allow-notify, provide-xfr and request-xfr are adjusted to use the given key. .TP .B del_tsig Delete the TSIG key with the given name. Prints error if the key is still in use by some zone. The changes are only in-memory and are gone next restart, for lasting changes edit the nsd.conf file or a file included from it. .TP .B add_cookie_secret Add or replace a cookie secret persistently. needs to be an 128 bit hex string. .sp Cookie secrets can be either \fIactive\fR or \fIstaging\fR. \fIActive\fR cookie secrets are used to create DNS Cookies, but verification of a DNS Cookie succeeds with any of the \fIactive\fR or \fIstaging\fR cookie secrets. The state of the current cookie secrets can be printed with the \fBprint_cookie_secrets\fR command. .sp When there are no cookie secrets configured yet, the is added as \fIactive\fR. If there is already an \fIactive\fR cookie secret, the is added as \fIstaging\fR or replacing an existing \fIstaging\fR secret. .sp To "roll" a cookie secret used in an anycast set. The new secret has to be added as staging secret to \fBall\fR nodes in the anycast set. When \fBall\fR nodes can verify DNS Cookies with the new secret, the new secret can be activated with the \fBactivate_cookie_secret\fR command. After \fBall\fR nodes have the new secret \fIactive\fR for at least one hour, the previous secret can be dropped with the \fBdrop_cookie_secret\fR command. .sp Persistence is accomplished by writing to a file which if configured with the \fBcookie\-secret\-file\fR option in the server section of the config file. The default value for that is: @cookiesecretsfile@ . .TP .B drop_cookie_secret Drop the \fIstaging\fR cookie secret. .TP .B activate_cookie_secret Make the current \fIstaging\fR cookie secret \fIactive\fR, and the current \fIactive\fR cookie secret \fIstaging\fR. .TP .B print_cookie_secrets Show the current configured cookie secrets with their status. .SH "EXIT CODE" The nsd\-control program exits with status code 1 on error, 0 on success. .SH "SET UP" The setup requires a self\-signed certificate and private keys for both the server and client. The script \fInsd\-control\-setup\fR generates these in the default run directory, or with \-d in another directory. If you change the access control permissions on the key files you can decide who can use nsd\-control, by default owner and group but not all users. The script preserves private keys present in the directory. After running the script as root, turn on \fBcontrol\-enable\fR in \fInsd.conf\fR. .SH "STATISTIC COUNTERS" The \fIstats\fR command shows a number of statistic counters. .TP .I num.queries number of queries received (the tls, tcp and udp queries added up). .TP .I serverX.queries number of queries handled by the server process. The number of server processes is set with the config statement \fBserver\-count\fR. .TP .I time.boot uptime in seconds since the server was started. With fractional seconds. .TP .I time.elapsed time since the last stats report, in seconds. With fractional seconds. Can be zero if polled quickly and the previous stats command resets the counters, so that the next gets a fully zero, and zero elapsed time, report. .TP .I size.db.disk size of nsd.db on disk, in bytes. .TP .I size.db.mem size of the DNS database in memory, in bytes. .TP .I size.xfrd.mem size of memory for zone transfers and notifies in xfrd process, excludes TSIG data, in bytes. .TP .I size.config.disk size of zonelist file on disk, excludes the nsd.conf size, in bytes. .TP .I size.config.mem size of config data in memory, kept twice in server and xfrd process, in bytes. .TP .I num.type.X number of queries with this query type. .TP .I num.opcode.X number of queries with this opcode. .TP .I num.class.X number of queries with this query class. .TP .I num.rcode.X number of answers that carried this return code. .TP .I num.edns number of queries with EDNS OPT. .TP .I num.ednserr number of queries which failed EDNS parse. .TP .I num.udp number of queries over UDP ip4. .TP .I num.udp6 number of queries over UDP ip6. .TP .I num.tcp number of connections over TCP ip4. .TP .I num.tcp6 number of connections over TCP ip6. .TP .I num.tls number of connections over TLS ip4. TLS queries are not part of num.tcp. .TP .I num.tls6 number of connections over TLS ip6. TLS queries are not part of num.tcp6. .TP .I num.answer_wo_aa number of answers with NOERROR rcode and without AA flag, this includes the referrals. .TP .I num.rxerr number of queries for which the receive failed. .TP .I num.txerr number of answers for which the transmit failed. .TP .I num.raxfr number of AXFR requests from clients (that got served with reply). .TP .I num.rixfr number of IXFR requests from clients (that got served with reply). .TP .I num.truncated number of answers with TC flag set. .TP .I num.dropped number of queries that were dropped because they failed sanity check. .TP .I zone.primary number of primary zones served. These are zones with no 'request\-xfr:' entries. Also output as 'zone.master' for backwards compatibility. .TP .I zone.secondary number of secondary zones served. These are zones with 'request\-xfr' entries. Also output as 'zone.slave' for backwards compatibility. .SH "FILES" .TP .I @nsdconfigfile@ nsd configuration file. .TP .I @configdir@ directory with private keys (nsd_server.key and nsd_control.key) and self\-signed certificates (nsd_server.pem and nsd_control.pem). .SH "SEE ALSO" \fInsd.conf\fR(5), \fInsd\fR(8), \fInsd\-checkconf\fR(8) nsd-4.12.0/nsd-control-setup.sh.in0000755000175000017500000001350115002373054016341 0ustar mozziemozzie#!/bin/sh # # nsd-control-setup.sh - set up SSL certificates for nsd-control # # Copyright (c) 2011, NLnet Labs. All rights reserved. # # This software is open source. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of the NLNET LABS nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # settings: # directory for files DESTDIR=@configdir@ # issuer and subject name for certificates SERVERNAME=nsd CLIENTNAME=nsd-control # validity period for certificates DAYS=7200 # size of keys in bits BITS=3072 # hash algorithm HASH=sha256 # base name for nsd server keys SVR_BASE=nsd_server # base name for nsd-control keys CTL_BASE=nsd_control # flag to recreate generated certificates RECREATE=0 # we want -rw-r--- access (say you run this as root: grp=yes (server), all=no). umask 0026 # end of options set -eu cleanup() { echo "removing artifacts" rm -rf \ server.cnf \ client.cnf \ "${SVR_BASE}_trust.pem" \ "${CTL_BASE}_trust.pem" \ "${SVR_BASE}_trust.srl" } fatal() { printf "fatal error: $*\n" >/dev/stderr exit 1 } usage() { cat < used directory to store keys and certificates (default: $DESTDIR) -h show help notice -r recreate certificates EOF } OPTIND=1 while getopts 'd:hr' arg; do case "$arg" in d) DESTDIR="$OPTARG" ;; h) usage; exit 1 ;; r) RECREATE=1 ;; ?) fatal "'$arg' unknown option" ;; esac done shift $((OPTIND - 1)) echo "setup in directory $DESTDIR" cd "$DESTDIR" trap cleanup INT # === # Generate server certificate # === # generate private key; do no recreate it if they already exist. if [ ! -f "$SVR_BASE.key" ]; then openssl genrsa -out "$SVR_BASE.key" "$BITS" fi cat >server.cnf <client.cnf < #include #include #include #include #include #include #include "nsd.h" #include "options.h" #include "util.h" #include "zonec.h" #include "ixfr.h" #include "ixfrcreate.h" #include "difffile.h" struct nsd nsd; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd-checkzone [-p] \n"); fprintf(stderr, "\t-p\tprint the zone if the zone is ok\n"); fprintf(stderr, "\t-i \tcreate an IXFR from the differences between the\n\t\told zone file and the new zone file. Writes to \n\t\t.ixfr and renames other .ixfr files to\n\t\t.ixfr.num+1.\n"); fprintf(stderr, "\t-n \tnumber of IXFR versions to store, at most.\n\t\tdefault %d.\n", (int)IXFR_NUMBER_DEFAULT); fprintf(stderr, "\t-s \tsize of IXFR to store, at most. default %d.\n", (int)IXFR_SIZE_DEFAULT); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } static void check_zone(struct nsd* nsd, const char* name, const char* fname, FILE *out, const char* oldzone, uint32_t ixfr_number, uint64_t ixfr_size) { const dname_type* dname; zone_options_type* zo; zone_type* zone; unsigned errors; struct ixfr_create* ixfrcr = NULL; /* init*/ nsd->db = namedb_open(nsd->options); dname = dname_parse(nsd->options->region, name); if(!dname) { /* parse failure */ error("cannot parse zone name '%s'", name); } zo = zone_options_create(nsd->options->region); memset(zo, 0, sizeof(*zo)); zo->node.key = dname; zo->name = name; zone = namedb_zone_create(nsd->db, dname, zo); if(oldzone) { errors = zonec_read(nsd->db, nsd->db->domains, name, oldzone, zone); if(errors > 0) { printf("zone %s file %s has %u errors\n", name, oldzone, errors); exit(1); } ixfrcr = ixfr_create_start(zone, fname, ixfr_size, 1); if(!ixfrcr) { error("out of memory"); } delete_zone_rrs(nsd->db, zone); } /* read the zone */ errors = zonec_read(nsd->db, nsd->db->domains, name, fname, zone); if(errors > 0) { printf("zone %s file %s has %u errors\n", name, fname, errors); ixfr_create_cancel(ixfrcr); #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */ namedb_close(nsd->db); region_destroy(nsd->options->region); #endif exit(1); } if(ixfrcr) { if(!ixfr_create_perform(ixfrcr, zone, 0, nsd, fname, ixfr_number)) { #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */ namedb_close(nsd->db); region_destroy(nsd->options->region); ixfr_create_free(ixfrcr); #endif error("could not create IXFR"); } printf("zone %s created IXFR %s.ixfr\n", name, fname); ixfr_create_free(ixfrcr); } if (out) { print_rrs(out, zone); printf("; "); } printf("zone %s is ok\n", name); namedb_close(nsd->db); } /* dummy functions to link */ int writepid(struct nsd * ATTR_UNUSED(nsd)) { return 0; } void unlinkpid(const char * ATTR_UNUSED(file), const char* ATTR_UNUSED(username)) { } void bind8_stats(struct nsd * ATTR_UNUSED(nsd)) { } void sig_handler(int ATTR_UNUSED(sig)) { } extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; int print_zone = 0; uint32_t ixfr_number = IXFR_NUMBER_DEFAULT; uint64_t ixfr_size = IXFR_SIZE_DEFAULT; char* oldzone = NULL; struct nsd nsd; memset(&nsd, 0, sizeof(nsd)); log_init("nsd-checkzone"); /* Parse the command line... */ while ((c = getopt(argc, argv, "hi:n:ps:")) != -1) { switch (c) { case 'h': usage(); exit(0); case 'i': oldzone = optarg; break; case 'n': ixfr_number = (uint32_t)atoi(optarg); break; case 'p': print_zone = 1; break; case 's': ixfr_size = (uint64_t)atoi(optarg); break; case '?': default: usage(); exit(1); } } argc -= optind; argv += optind; /* Commandline parse error */ if (argc != 2) { fprintf(stderr, "wrong number of arguments.\n"); usage(); exit(1); } nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); if (verbosity == 0) verbosity = nsd.options->verbosity; check_zone(&nsd, argv[0], argv[1], print_zone ? stdout : NULL, oldzone, ixfr_number, ixfr_size); region_destroy(nsd.options->region); /* yylex_destroy(); but, not available in all versions of flex */ exit(0); } nsd-4.12.0/nsd-checkzone.8.in0000644000175000017500000000472015002373060015226 0ustar mozziemozzie.TH "nsd\-checkzone" "8" "Apr 24, 2025" "NLnet Labs" "nsd 4.12.0" .\" Copyright (c) 2014-2024, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-checkzone \- NSD zone file syntax checker. .SH "SYNOPSIS" .B nsd\-checkzone .RB [ \-h ] .I zonename .I zonefile .SH "DESCRIPTION" .B nsd\-checkzone reads a DNS zone file and checks it for errors. It prints errors to stderr. On failure it exits with nonzero exit status. .P This is used to check files before feeding them to the nsd(8) daemon. .SH "OPTIONS" .TP .B \-h Print usage help information and exit. .TP .I zonename The name of the zone to check, eg. "example.com". .TP .I zonefile The file to read, eg. "zones/example.com.zone.signed". Use "-" to read from stdin. .TP .B \-p Print the zone contents to stdout if the zone is ok. This prints the contents as it has been parsed, not literally a copy of the input, but as printed by the formatting routines in NSD, much like the nsd-control command write does. .TP .B \-i \fI Create an IXFR from the differences between the old zone file and the new zone file. The argument to the \-i option is the old zone file, the other zonefile argument passed is the new zonefile. .sp The difference is computed between the two zonefiles by keeping one version of the zone in memory, and another version in a temporary file. The temporary file is located at the zonefile directory. This is also where the result is written, to a file with the zonefile name, ending with '.ixfr'. This is also where NSD reads it when IXFRs are configured for the zone. .sp The other existing ixfr files are renamed to become older IXFR contents for the zone, if any such files exist. If the output file already exists with the correct contents, no new file is created. The contents of the header of the output file are checked for that, if it already exists. .TP .B \-n \fI The number of IXFR versions to store, at most. Default 5. This is the number of files that is created with ixfr contents for the zone. Older stored IXFR versions are deleted when the number is exceeded. .TP .B \-s \fI The number of bytes of storage to use for IXFRs. Default is 1048576. If an IXFR is bigger it is not created, and if the sum of IXFR storage exceeds it, older IXFRs versions are deleted. .SH "SEE ALSO" \fInsd\fR(8), \fInsd-checkconf\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. nsd-4.12.0/nsd-checkconf.c0000644000175000017500000007655015002373054014663 0ustar mozziemozzie/* * checkconf - Read and repeat configuration file to output. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include "tsig.h" #include "options.h" #include "util.h" #include "dname.h" #include "rrl.h" extern char *optarg; extern int optind; static void usage(void) ATTR_NORETURN; int zonec_parse_string(region_type* ATTR_UNUSED(region), domain_table_type* ATTR_UNUSED(domains), zone_type* ATTR_UNUSED(zone), char* ATTR_UNUSED(str), domain_type** ATTR_UNUSED(parsed), int* ATTR_UNUSED(num_rrs)) { return 0; } #define ZONE_GET_ACL(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote_acl(PATTERN->NAME); \ return; \ } #define ZONE_GET_OUTGOING(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ acl_options_type* acl; \ for(acl=PATTERN->NAME; acl; acl=acl->next) \ quote(acl->ip_address_spec); \ return; \ } #define ZONE_GET_STR(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote(PATTERN->NAME); \ return; \ } #define ZONE_GET_PATH(FINAL, NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quotepath(opt, FINAL, PATTERN->NAME); \ return; \ } #define ZONE_GET_BIN(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%s\n", (PATTERN->NAME)?"yes":"no"); \ return; \ } #define ZONE_GET_RRL(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ zone_print_rrl_whitelist("", PATTERN->NAME); \ return; \ } #define ZONE_GET_INT(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%d\n", (int) PATTERN->NAME); \ return; \ } #define SERV_GET_BIN(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%s\n", opt->NAME?"yes":"no"); \ return; \ } #define SERV_GET_STR(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote(opt->NAME); \ return; \ } #define SERV_GET_PATH(FINAL, NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quotepath(opt, FINAL, opt->NAME); \ return; \ } #define SERV_GET_INT(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%d\n", (int) opt->NAME); \ return; \ } #define SERV_GET_IP(NAME, MEMBER, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ for(ip = opt->MEMBER; ip; ip=ip->next) \ { \ quote(ip->address); \ } \ return; \ } #ifdef RATELIMIT static void zone_print_rrl_whitelist(const char* s, uint16_t w) { int i; if(w==rrl_type_all) { printf("%sall\n", s); return; } for(i=0x01; i <= 0x80; i<<=1) { if( (w&i) ) printf("%s%s\n", s, rrltype2str(i)); } } #endif /* RATELIMIT */ static char buf[BUFSIZ]; static char * underscore(const char *s) { const char *j = s; size_t i = 0; while(j && *j) { if (*j == '-') { buf[i++] = '_'; } else { buf[i++] = *j; } j++; if (i >= BUFSIZ) { return NULL; } } buf[i] = '\0'; return buf; } static void usage(void) { fprintf(stderr, "usage: nsd-checkconf [-v|-h] [-o option] [-z zonename]\n"); fprintf(stderr, " [-s keyname] [-t tlsauthname] \n"); fprintf(stderr, " Checks NSD configuration file for errors.\n"); fprintf(stderr, " Version %s. Report bugs to <%s>.\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); fprintf(stderr, "Use with a configfile as argument to check syntax.\n"); fprintf(stderr, "Use with -o, -z, -t or -s options to query the configuration.\n\n"); fprintf(stderr, "-v Verbose, echo settings that take effect to std output.\n"); fprintf(stderr, "-h Print this help information.\n"); fprintf(stderr, "-f Use with -o to print final pathnames, ie. with chroot.\n"); fprintf(stderr, "-o option Print value of the option specified to stdout.\n"); fprintf(stderr, "-p pattern Print option value for the pattern given.\n"); fprintf(stderr, "-z zonename Print option value for the zone given.\n"); fprintf(stderr, "-a keyname Print algorithm name for the TSIG key.\n"); fprintf(stderr, "-s keyname Print base64 secret blob for the TSIG key.\n"); fprintf(stderr, "-t tls-auth-name Print auth domain name for the tls-auth clause.\n"); exit(1); } static void print_string_var(const char* varname, const char* value) { if (!value) { printf("\t#%s\n", varname); } else { printf("\t%s \"%s\"\n", varname, value); } } static void quote(const char *v) { if(v==NULL) printf("\n"); else printf("%s\n", v); } static void quotepath(nsd_options_type* opt, int final, const char *f) { const char* chr = opt->chroot; #ifdef CHROOTDIR if(chr == 0) chr = CHROOTDIR; #endif if(f == 0 || f[0] == '/' || !final || !chr || chr[0]==0) { quote(f); return; } /* chroot has had trailing slash applied in check part of checkconf */ printf("%s%s\n", chr, f); } static void quote_acl(acl_options_type* acl) { while(acl) { if (acl->tls_auth_name) printf("%s %s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)")), acl->tls_auth_name?acl->tls_auth_name:""); else printf("%s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)"))); acl=acl->next; } } static void print_acl(const char* varname, acl_options_type* acl) { while(acl) { printf("\t%s ", varname); if(acl->use_axfr_only) printf("AXFR "); if(acl->allow_udp) printf("UDP "); if (acl->tls_auth_name) printf("%s %s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)")), acl->tls_auth_name?acl->tls_auth_name:""); else printf("%s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)"))); if(verbosity>1) { printf("\t# %s", acl->is_ipv6?"ip6":"ip4"); if(acl->port == 0) printf(" noport"); else printf(" port=%d", acl->port); if(acl->rangetype == acl_range_single) printf(" single"); if(acl->rangetype == acl_range_mask) printf(" masked"); if(acl->rangetype == acl_range_subnet) printf(" subnet"); if(acl->rangetype == acl_range_minmax) printf(" minmax"); if(acl->is_ipv6) { #ifdef INET6 char dest[128]; inet_ntop(AF_INET6, &acl->addr.addr6, dest, sizeof(dest)); printf(" addr=%s", dest); if(acl->rangetype != acl_range_single) { inet_ntop(AF_INET6, &acl->range_mask.addr6, dest, sizeof(dest)); printf(" rangemask=%s", dest); } #else printf(" ip6addr-noip6defined"); #endif } else { char dest[128]; inet_ntop(AF_INET, &acl->addr.addr, dest, sizeof(dest)); printf(" addr=%s", dest); if(acl->rangetype != acl_range_single) { inet_ntop(AF_INET, &acl->range_mask.addr, dest, sizeof(dest)); printf(" rangemask=%s", dest); } } printf("\n"); } acl=acl->next; } } static void print_acl_ips(const char* varname, acl_options_type* acl) { while(acl) { printf("\t%s %s\n", varname, acl->ip_address_spec); acl=acl->next; } } void config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, const char *z, const char* pat, const char* tls, int final) { ip_address_option_type* ip; if (k) { /* find key */ key_options_type* key = key_options_find(opt, k); if(key) { if (s) { quote(key->secret); } else { quote(key->algorithm); } return; } printf("Could not find key %s\n", k); return; } if (tls) { /* find tlsauth */ tls_auth_options_type* tlsauth = tls_auth_options_find(opt, tls); if(tlsauth) { quote(tlsauth->auth_domain_name); return; } printf("Could not find tls-auth %s\n", tls); return; } if (!o) { return; } if (z) { zone_options_type* zone; const dname_type *dname = dname_parse(opt->region, z); if(!dname) { printf("Could not parse zone name %s\n", z); exit(1); } zone = zone_options_find(opt, dname); if(!zone) { printf("Zone does not exist: %s\n", z); exit(1); } ZONE_GET_STR(name, o, zone); if(strcasecmp("pattern", o)==0) { quote(zone->pattern->pname); return; } ZONE_GET_BIN(part_of_config, o, zone); ZONE_GET_PATH(final, zonefile, o, zone->pattern); ZONE_GET_ACL(allow_query, o, zone->pattern); ZONE_GET_ACL(request_xfr, o, zone->pattern); ZONE_GET_ACL(provide_xfr, o, zone->pattern); ZONE_GET_ACL(allow_notify, o, zone->pattern); ZONE_GET_ACL(notify, o, zone->pattern); ZONE_GET_BIN(notify_retry, o, zone->pattern); ZONE_GET_STR(zonestats, o, zone->pattern); ZONE_GET_OUTGOING(outgoing_interface, o, zone->pattern); ZONE_GET_BIN(allow_axfr_fallback, o, zone->pattern); ZONE_GET_INT(max_refresh_time, o, zone->pattern); ZONE_GET_INT(min_refresh_time, o, zone->pattern); ZONE_GET_INT(max_retry_time, o, zone->pattern); ZONE_GET_INT(min_retry_time, o, zone->pattern); ZONE_GET_INT(min_expire_time, o, zone->pattern); ZONE_GET_INT(size_limit_xfr, o, zone->pattern); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, zone->pattern); #endif ZONE_GET_BIN(multi_primary_check, o, zone->pattern); ZONE_GET_BIN(store_ixfr, o, zone->pattern); ZONE_GET_INT(ixfr_size, o, zone->pattern); ZONE_GET_INT(ixfr_number, o, zone->pattern); ZONE_GET_BIN(create_ixfr, o, zone->pattern); printf("Zone option not handled: %s %s\n", z, o); exit(1); } else if(pat) { pattern_options_type* p = pattern_options_find(opt, pat); if(!p) { printf("Pattern does not exist: %s\n", pat); exit(1); } if(strcasecmp("name", o)==0) { quote(p->pname); return; } ZONE_GET_STR(zonefile, o, p); ZONE_GET_PATH(final, zonefile, o, p); ZONE_GET_ACL(allow_query, o, p); ZONE_GET_ACL(request_xfr, o, p); ZONE_GET_ACL(provide_xfr, o, p); ZONE_GET_ACL(allow_notify, o, p); ZONE_GET_ACL(notify, o, p); ZONE_GET_BIN(notify_retry, o, p); ZONE_GET_STR(zonestats, o, p); ZONE_GET_OUTGOING(outgoing_interface, o, p); ZONE_GET_BIN(allow_axfr_fallback, o, p); ZONE_GET_INT(max_refresh_time, o, p); ZONE_GET_INT(min_refresh_time, o, p); ZONE_GET_INT(max_retry_time, o, p); ZONE_GET_INT(min_retry_time, o, p); ZONE_GET_INT(min_expire_time, o, p); ZONE_GET_INT(size_limit_xfr, o, p); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, p); #endif ZONE_GET_BIN(multi_primary_check, o, p); ZONE_GET_BIN(store_ixfr, o, p); ZONE_GET_INT(ixfr_size, o, p); ZONE_GET_INT(ixfr_number, o, p); ZONE_GET_BIN(create_ixfr, o, p); printf("Pattern option not handled: %s %s\n", pat, o); exit(1); } else { /* look in the server section */ SERV_GET_IP(ip_address, ip_addresses, o); /* bin */ SERV_GET_BIN(ip_transparent, o); SERV_GET_BIN(ip_freebind, o); 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(hide_identity, o); SERV_GET_BIN(drop_updates, o); SERV_GET_BIN(reload_config, o); SERV_GET_BIN(zonefiles_check, o); SERV_GET_BIN(log_time_ascii, o); SERV_GET_BIN(log_time_iso, o); SERV_GET_BIN(round_robin, o); SERV_GET_BIN(minimal_responses, o); SERV_GET_BIN(confine_to_zone, o); SERV_GET_BIN(refuse_any, o); SERV_GET_BIN(tcp_reject_overflow, o); SERV_GET_BIN(log_only_syslog, o); /* str */ SERV_GET_STR(identity, o); SERV_GET_STR(version, o); SERV_GET_STR(nsid, o); SERV_GET_PATH(final, logfile, o); SERV_GET_PATH(final, pidfile, o); SERV_GET_STR(chroot, o); SERV_GET_STR(username, o); SERV_GET_PATH(final, zonesdir, o); SERV_GET_PATH(final, xfrdfile, o); SERV_GET_PATH(final, xfrdir, o); SERV_GET_PATH(final, zonelistfile, o); SERV_GET_STR(port, o); SERV_GET_STR(tls_service_key, o); SERV_GET_STR(tls_service_ocsp, o); SERV_GET_STR(tls_service_pem, o); SERV_GET_STR(tls_port, o); SERV_GET_STR(tls_cert_bundle, o); SERV_GET_STR(cookie_secret, o); SERV_GET_STR(cookie_staging_secret, o); SERV_GET_STR(cookie_secret_file, o); SERV_GET_BIN(answer_cookie, o); /* int */ SERV_GET_INT(server_count, o); SERV_GET_INT(tcp_count, o); SERV_GET_INT(tcp_query_count, o); SERV_GET_INT(tcp_timeout, o); SERV_GET_INT(tcp_mss, o); SERV_GET_INT(outgoing_tcp_mss, o); SERV_GET_INT(xfrd_tcp_max, o); SERV_GET_INT(xfrd_tcp_pipeline, o); SERV_GET_INT(ipv4_edns_size, o); SERV_GET_INT(ipv6_edns_size, o); SERV_GET_INT(statistics, o); SERV_GET_INT(xfrd_reload_timeout, o); SERV_GET_INT(verbosity, o); SERV_GET_INT(send_buffer_size, o); SERV_GET_INT(receive_buffer_size, o); #ifdef RATELIMIT SERV_GET_INT(rrl_size, o); SERV_GET_INT(rrl_ratelimit, o); SERV_GET_INT(rrl_slip, o); SERV_GET_INT(rrl_ipv4_prefix_length, o); SERV_GET_INT(rrl_ipv6_prefix_length, o); SERV_GET_INT(rrl_whitelist_ratelimit, o); #endif #ifdef USE_METRICS SERV_GET_BIN(metrics_enable, o); SERV_GET_IP(metrics_interface, metrics_interface, o); SERV_GET_INT(metrics_port, o); SERV_GET_STR(metrics_path, o); #endif /* USE_METRICS */ #ifdef USE_DNSTAP SERV_GET_BIN(dnstap_enable, o); SERV_GET_STR(dnstap_socket_path, o); SERV_GET_STR(dnstap_ip, o); SERV_GET_BIN(dnstap_tls, o); SERV_GET_STR(dnstap_tls_server_name, o); SERV_GET_STR(dnstap_tls_cert_bundle, o); SERV_GET_STR(dnstap_tls_client_key_file, o); SERV_GET_STR(dnstap_tls_client_cert_file, o); SERV_GET_BIN(dnstap_send_identity, o); SERV_GET_BIN(dnstap_send_version, o); SERV_GET_STR(dnstap_identity, o); SERV_GET_STR(dnstap_version, o); SERV_GET_BIN(dnstap_log_auth_query_messages, o); SERV_GET_BIN(dnstap_log_auth_response_messages, o); #endif SERV_GET_INT(zonefiles_write, o); /* remote control */ SERV_GET_BIN(control_enable, o); SERV_GET_IP(control_interface, control_interface, o); SERV_GET_INT(control_port, o); SERV_GET_STR(server_key_file, o); SERV_GET_STR(server_cert_file, o); SERV_GET_STR(control_key_file, o); SERV_GET_STR(control_cert_file, o); if(strcasecmp(o, "zones") == 0) { zone_options_type* zone; RBTREE_FOR(zone, zone_options_type*, opt->zone_options) quote(zone->name); return; } if(strcasecmp(o, "patterns") == 0) { pattern_options_type* p; RBTREE_FOR(p, pattern_options_type*, opt->patterns) quote(p->pname); return; } if(strcasecmp(o, "proxy_protocol_port") == 0) { struct proxy_protocol_port_list* p; for(p = opt->proxy_protocol_port; p; p = p->next) printf("%d\n", p->port); return; } printf("Server option not handled: %s\n", o); exit(1); } } /* print zone content items */ static void print_zone_content_elems(pattern_options_type* pat) { if(pat->zonefile) print_string_var("zonefile:", pat->zonefile); #ifdef RATELIMIT zone_print_rrl_whitelist("\trrl-whitelist: ", pat->rrl_whitelist); #endif print_acl("allow_query:", pat->allow_query); print_acl("allow-notify:", pat->allow_notify); print_acl("request-xfr:", pat->request_xfr); if(pat->multi_primary_check) printf("\tmulti-primary-check: %s\n", pat->multi_primary_check?"yes":"no"); if(!pat->notify_retry_is_default) printf("\tnotify-retry: %d\n", pat->notify_retry); print_acl("notify:", pat->notify); print_acl("provide-xfr:", pat->provide_xfr); if(pat->zonestats) print_string_var("zonestats:", pat->zonestats); print_acl_ips("outgoing-interface:", pat->outgoing_interface); if(!pat->allow_axfr_fallback_is_default) printf("\tallow-axfr-fallback: %s\n", pat->allow_axfr_fallback?"yes":"no"); if(!pat->max_refresh_time_is_default) printf("\tmax-refresh-time: %d\n", pat->max_refresh_time); if(!pat->min_refresh_time_is_default) printf("\tmin-refresh-time: %d\n", pat->min_refresh_time); if(!pat->max_retry_time_is_default) printf("\tmax-retry-time: %d\n", pat->max_retry_time); if(!pat->min_retry_time_is_default) printf("\tmin-retry-time: %d\n", pat->min_retry_time); if(pat->min_expire_time_expr == REFRESHPLUSRETRYPLUS1) printf("\tmin-expire-time: " REFRESHPLUSRETRYPLUS1_STR "\n"); else if(pat->min_expire_time_expr == EXPIRE_TIME_HAS_VALUE) printf("\tmin-expire-time: %d\n", pat->min_expire_time); if(pat->size_limit_xfr != 0) printf("\tsize-limit-xfr: %llu\n", (long long unsigned)pat->size_limit_xfr); if(!pat->store_ixfr_is_default) printf("\tstore-ixfr: %s\n", pat->store_ixfr?"yes":"no"); if(!pat->ixfr_number_is_default) printf("\tixfr-number: %u\n", (unsigned)pat->ixfr_number); if(!pat->ixfr_size_is_default) printf("\tixfr-size: %u\n", (unsigned)pat->ixfr_size); if(!pat->create_ixfr_is_default) printf("\tcreate-ixfr: %s\n", pat->create_ixfr?"yes":"no"); if(pat->verify_zone != VERIFY_ZONE_INHERIT) { printf("\tverify-zone: "); if(pat->verify_zone) { printf("yes\n"); } else { printf("no\n"); } } if(pat->verifier) { printf("\tverifier:"); for(char *const *s = pat->verifier; *s; s++) { printf(" \"%s\"", *s); } printf("\n"); } if(pat->verifier_feed_zone != VERIFIER_FEED_ZONE_INHERIT) { printf("\tverifier-feed-zone: "); if(pat->verifier_feed_zone) { printf("yes\n"); } else { printf("no\n"); } } if(pat->verifier_timeout != VERIFIER_TIMEOUT_INHERIT) { printf("\tverifier-timeout: %d\n", pat->verifier_timeout); } if(!pat->catalog_role_is_default) switch(pat->catalog_role) { case CATALOG_ROLE_CONSUMER: printf("\tcatalog: consumer\n"); break; case CATALOG_ROLE_PRODUCER: printf("\tcatalog: producer\n"); break; default : break; } if(pat->catalog_member_pattern) print_string_var("catalog-member-pattern:", pat->catalog_member_pattern); if(pat->catalog_producer_zone) print_string_var("catalog-producer-zone:", pat->catalog_producer_zone); } void config_test_print_server(nsd_options_type* opt) { ip_address_option_type* ip; key_options_type* key; tls_auth_options_type* tlsauth; zone_options_type* zone; pattern_options_type* pat; printf("# Config settings.\n"); printf("server:\n"); printf("\tdebug-mode: %s\n", opt->debug_mode?"yes":"no"); printf("\tip-transparent: %s\n", opt->ip_transparent?"yes":"no"); printf("\tip-freebind: %s\n", opt->ip_freebind?"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("\tsend-buffer-size: %d\n", opt->send_buffer_size); printf("\treceive-buffer-size: %d\n", opt->receive_buffer_size); printf("\thide-version: %s\n", opt->hide_version?"yes":"no"); printf("\thide-identity: %s\n", opt->hide_identity?"yes":"no"); printf("\tdrop-updates: %s\n", opt->drop_updates?"yes":"no"); printf("\ttcp-reject-overflow: %s\n", opt->tcp_reject_overflow ? "yes" : "no"); print_string_var("identity:", opt->identity); print_string_var("version:", opt->version); print_string_var("nsid:", opt->nsid); print_string_var("logfile:", opt->logfile); printf("\tlog-only-syslog: %s\n", opt->log_only_syslog?"yes":"no"); printf("\tserver-count: %d\n", opt->server_count); if(opt->cpu_affinity) { cpu_option_type *n; printf("\tcpu-affinity:"); for(n = opt->cpu_affinity; n; n = n->next) { printf(" %d", n->cpu); } printf("\n"); } if(opt->cpu_affinity && opt->service_cpu_affinity) { cpu_map_option_type *n; for(n = opt->service_cpu_affinity; n; n = n->next) { if(n->service > 0) { printf("\tserver-%d-cpu-affinity: %d\n", n->service, n->cpu); } else if(n->service == -1) { printf("\txfrd-cpu-affinity: %d\n", n->cpu); } } } printf("\ttcp-count: %d\n", opt->tcp_count); printf("\ttcp-query-count: %d\n", opt->tcp_query_count); printf("\ttcp-timeout: %d\n", opt->tcp_timeout); printf("\ttcp-mss: %d\n", opt->tcp_mss); printf("\toutgoing-tcp-mss: %d\n", opt->outgoing_tcp_mss); printf("\txfrd-tcp-max: %d\n", opt->xfrd_tcp_max); printf("\txfrd-tcp-pipeline: %d\n", opt->xfrd_tcp_pipeline); printf("\tipv4-edns-size: %d\n", (int) opt->ipv4_edns_size); printf("\tipv6-edns-size: %d\n", (int) opt->ipv6_edns_size); print_string_var("pidfile:", opt->pidfile); print_string_var("port:", opt->port); printf("\tstatistics: %d\n", opt->statistics); print_string_var("chroot:", opt->chroot); print_string_var("username:", opt->username); print_string_var("zonesdir:", opt->zonesdir); print_string_var("xfrdfile:", opt->xfrdfile); print_string_var("zonelistfile:", opt->zonelistfile); print_string_var("xfrdir:", opt->xfrdir); printf("\txfrd-reload-timeout: %d\n", opt->xfrd_reload_timeout); printf("\tlog-time-ascii: %s\n", opt->log_time_ascii?"yes":"no"); printf("\tlog-time-iso: %s\n", opt->log_time_iso?"yes":"no"); printf("\tround-robin: %s\n", opt->round_robin?"yes":"no"); printf("\tminimal-responses: %s\n", opt->minimal_responses?"yes":"no"); printf("\tconfine-to-zone: %s\n", opt->confine_to_zone ? "yes" : "no"); printf("\trefuse-any: %s\n", opt->refuse_any?"yes":"no"); printf("\tverbosity: %d\n", opt->verbosity); for(ip = opt->ip_addresses; ip; ip=ip->next) { printf("\tip-address: %s", ip->address); if(ip->servers) { const char *sep; struct range_option *n; printf(" servers=\""); for(n=ip->servers, sep=""; n; n = n->next, sep=" ") { if(n->first == n->last) { printf("%s%d", sep, n->first); } else { printf("%s%d-%d", sep, n->first, n->last); } } printf("\""); } if(ip->fib != -1) { printf(" setfib=%d", ip->fib); } printf("\n"); } #ifdef RATELIMIT printf("\trrl-size: %d\n", (int)opt->rrl_size); printf("\trrl-ratelimit: %d\n", (int)opt->rrl_ratelimit); printf("\trrl-slip: %d\n", (int)opt->rrl_slip); printf("\trrl-ipv4-prefix-length: %d\n", (int)opt->rrl_ipv4_prefix_length); printf("\trrl-ipv6-prefix-length: %d\n", (int)opt->rrl_ipv6_prefix_length); printf("\trrl-whitelist-ratelimit: %d\n", (int)opt->rrl_whitelist_ratelimit); #endif printf("\treload-config: %s\n", opt->reload_config?"yes":"no"); printf("\tzonefiles-check: %s\n", opt->zonefiles_check?"yes":"no"); printf("\tzonefiles-write: %d\n", opt->zonefiles_write); print_string_var("tls-service-key:", opt->tls_service_key); print_string_var("tls-service-pem:", opt->tls_service_pem); print_string_var("tls-service-ocsp:", opt->tls_service_ocsp); print_string_var("tls-port:", opt->tls_port); print_string_var("tls-cert-bundle:", opt->tls_cert_bundle); printf("\tanswer-cookie: %s\n", opt->answer_cookie?"yes":"no"); print_string_var("cookie-secret:", opt->cookie_secret); print_string_var("cookie-staging-secret:", opt->cookie_staging_secret); if(opt->cookie_secret_file_is_default) { print_string_var("#cookie-secret-file:", opt->cookie_secret_file); } else if(opt->cookie_secret_file) { print_string_var("cookie-secret-file:", opt->cookie_secret_file); } else { print_string_var("cookie-secret-file:", ""); } if(opt->proxy_protocol_port) { struct proxy_protocol_port_list* p; for(p = opt->proxy_protocol_port; p; p = p->next) printf("\tproxy-protocol-port: %d\n", p->port); } #ifdef USE_METRICS printf("\tmetrics-enable: %s\n", opt->metrics_enable?"yes":"no"); for(ip = opt->metrics_interface; ip; ip=ip->next) print_string_var("metrics-interface:", ip->address); printf("\tmetrics-port: %d\n", opt->metrics_port); print_string_var("metrics-path:", opt->metrics_path); #endif /* USE_METRICS */ #ifdef USE_DNSTAP printf("\ndnstap:\n"); printf("\tdnstap-enable: %s\n", opt->dnstap_enable?"yes":"no"); print_string_var("dnstap-socket-path:", opt->dnstap_socket_path); print_string_var("dnstap-ip:", opt->dnstap_ip); printf("\tdnstap-tls: %s\n", opt->dnstap_tls?"yes":"no"); print_string_var("dnstap-tls-server-name:", opt->dnstap_tls_server_name); print_string_var("dnstap-tls-cert-bundle:", opt->dnstap_tls_cert_bundle); print_string_var("dnstap-tls-client-key-file:", opt->dnstap_tls_client_key_file); print_string_var("dnstap-tls-client-cert-file:", opt->dnstap_tls_client_cert_file); printf("\tdnstap-send-identity: %s\n", opt->dnstap_send_identity?"yes":"no"); printf("\tdnstap-send-version: %s\n", opt->dnstap_send_version?"yes":"no"); print_string_var("dnstap-identity:", opt->dnstap_identity); print_string_var("dnstap-version:", opt->dnstap_version); printf("\tdnstap-log-auth-query-messages: %s\n", opt->dnstap_log_auth_query_messages?"yes":"no"); printf("\tdnstap-log-auth-response-messages: %s\n", opt->dnstap_log_auth_response_messages?"yes":"no"); #endif printf("\nremote-control:\n"); printf("\tcontrol-enable: %s\n", opt->control_enable?"yes":"no"); for(ip = opt->control_interface; ip; ip=ip->next) print_string_var("control-interface:", ip->address); printf("\tcontrol-port: %d\n", opt->control_port); print_string_var("server-key-file:", opt->server_key_file); print_string_var("server-cert-file:", opt->server_cert_file); print_string_var("control-key-file:", opt->control_key_file); print_string_var("control-cert-file:", opt->control_cert_file); printf("\nverify:\n"); printf("\tenable: %s\n", opt->verify_enable?"yes":"no"); for(ip = opt->verify_ip_addresses; ip; ip=ip->next) { print_string_var("ip-address:", ip->address); } printf("\tport: %s\n", opt->verify_port); printf("\tverify-zones: %s\n", opt->verify_zones?"yes":"no"); if(opt->verifier) { printf("\tverifier:"); for(char **s = opt->verifier; *s; s++) { printf(" \"%s\"", *s); } printf("\n"); } printf("\tverifier-count: %d\n", opt->verifier_count); printf("\tverifier-feed-zone: %s\n", opt->verifier_feed_zone?"yes":"no"); printf("\tverifier-timeout: %d\n", opt->verifier_timeout); RBTREE_FOR(key, key_options_type*, opt->keys) { printf("\nkey:\n"); print_string_var("name:", key->name); print_string_var("algorithm:", key->algorithm); print_string_var("secret:", key->secret); } RBTREE_FOR(tlsauth, tls_auth_options_type*, opt->tls_auths) { printf("\ntls-auth:\n"); print_string_var("name:", tlsauth->name); print_string_var("auth-domain-name:", tlsauth->auth_domain_name); } RBTREE_FOR(pat, pattern_options_type*, opt->patterns) { if(pat->implicit) continue; printf("\npattern:\n"); print_string_var("name:", pat->pname); print_zone_content_elems(pat); } RBTREE_FOR(zone, zone_options_type*, opt->zone_options) { if(!zone->part_of_config) continue; printf("\nzone:\n"); print_string_var("name:", zone->name); print_zone_content_elems(zone->pattern); } } static int additional_checks(nsd_options_type* opt, const char* filename) { zone_options_type* zone; int errors = 0; RBTREE_FOR(zone, zone_options_type*, opt->zone_options) { const dname_type* dname = dname_parse(opt->region, zone->name); /* memory leak. */ if(!dname) { fprintf(stderr, "%s: cannot parse zone name syntax for zone %s.\n", filename, zone->name); errors ++; continue; } if(zone->pattern->allow_notify && !zone->pattern->request_xfr) { 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_is_catalog_producer(zone) && (!zone->pattern->zonefile || zone->pattern->zonefile[0] == 0)) { fprintf(stderr, "%s: zone %s is a primary zone but has " "no zonefile. Where can the data come from?\n", filename, zone->name); errors ++; } } #ifndef BIND8_STATS if(opt->statistics > 0) { fprintf(stderr, "%s: 'statistics: %d' but BIND 8 statistics feature not enabled.\n", filename, opt->statistics); errors ++; } #endif #ifndef HAVE_CHROOT if(opt->chroot != 0) { fprintf(stderr, "%s: chroot %s given. chroot not supported on this platform.\n", filename, opt->chroot); errors ++; } #endif if (opt->identity && strlen(opt->identity) > UCHAR_MAX) { fprintf(stderr, "%s: server identity too long (%u characters)\n", filename, (unsigned) strlen(opt->identity)); errors ++; } if (opt->version && strlen(opt->version) > UCHAR_MAX) { fprintf(stderr, "%s: server version too long (%u characters)\n", filename, (unsigned) strlen(opt->version)); errors ++; } /* not done here: parsing of ip-address. parsing of username. */ if (opt->chroot && opt->chroot[0]) { /* append trailing slash for strncmp checking */ append_trailing_slash(&opt->chroot, opt->region); append_trailing_slash(&opt->xfrdir, opt->region); append_trailing_slash(&opt->zonesdir, opt->region); /* zonesdir must be absolute and within chroot, * all other pathnames may be relative to zonesdir */ if (strncmp(opt->zonesdir, opt->chroot, strlen(opt->chroot)) != 0) { fprintf(stderr, "%s: zonesdir %s has to be an absolute path that starts with the chroot path %s\n", filename, opt->zonesdir, opt->chroot); errors ++; } if (!file_inside_chroot(opt->pidfile, opt->chroot)) { fprintf(stderr, "%s: pidfile %s is not relative to chroot %s.\n", filename, opt->pidfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->xfrdfile, opt->chroot)) { fprintf(stderr, "%s: xfrdfile %s is not relative to chroot %s.\n", filename, opt->xfrdfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->zonelistfile, opt->chroot)) { fprintf(stderr, "%s: zonelistfile %s is not relative to chroot %s.\n", filename, opt->zonelistfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->xfrdir, opt->chroot)) { fprintf(stderr, "%s: xfrdir %s is not relative to chroot %s.\n", filename, opt->xfrdir, opt->chroot); errors ++; } } if (atoi(opt->port) <= 0) { fprintf(stderr, "%s: port number '%s' is not a positive number.\n", filename, opt->port); errors ++; } if(errors != 0) { fprintf(stderr, "%s: %d semantic errors in %d zones, %d keys, %d tls-auth.\n", filename, errors, (int)nsd_options_num_zones(opt), (int)opt->keys->count, (int)opt->tls_auths->count); } return (errors == 0); } int main(int argc, char* argv[]) { int c; int verbose = 0; int key_sec = 0; int final = 0; const char * conf_opt = NULL; /* what option do you want? Can be NULL -> print all */ const char * conf_zone = NULL; /* what zone are we talking about */ const char * conf_key = NULL; /* what key is needed */ const char * conf_tlsauth = NULL; /* what tls-auth is needed */ const char * conf_pat = NULL; /* what pattern is talked about */ const char* configfile; nsd_options_type *options; log_init("nsd-checkconf"); /* Parse the command line... */ while ((c = getopt(argc, argv, "vfho:a:p:s:z:t:")) != -1) { switch (c) { case 'v': verbose = 1; verbosity++; break; case 'o': conf_opt = optarg; break; case 'f': final = 1; break; case 'p': conf_pat = optarg; break; case 'a': if (conf_key) { fprintf(stderr, "Error: cannot combine -a with -s or other -a.\n"); exit(1); } conf_key = optarg; break; case 's': if (conf_key) { fprintf(stderr, "Error: cannot combine -s with -a or other -s.\n"); exit(1); } conf_key = optarg; key_sec = 1; break; case 't': conf_tlsauth = optarg; break; case 'z': conf_zone = optarg; break; case 'h': default: usage(); }; } argc -= optind; argv += optind; if (argc == 0 || argc>=2) { usage(); } configfile = argv[0]; /* read config file */ options = nsd_options_create(region_create(xalloc, free)); tsig_init(options->region); if (!parse_options_file(options, configfile, NULL, NULL, NULL) || !additional_checks(options, configfile)) { exit(2); } if (conf_opt || conf_key || conf_tlsauth) { config_print_zone(options, conf_key, key_sec, underscore(conf_opt), conf_zone, conf_pat, conf_tlsauth, final); } else { if (verbose) { printf("# Read file %s: %d patterns, %d fixed-zones, " "%d keys, %d tls-auth.\n", configfile, (int)options->patterns->count, (int)nsd_options_num_zones(options), (int)options->keys->count, (int)options->tls_auths->count); config_test_print_server(options); } } return 0; } nsd-4.12.0/nsd-checkconf.8.in0000644000175000017500000000507515002373060015204 0ustar mozziemozzie.TH "nsd\-checkconf" "8" "Apr 24, 2025" "NLnet Labs" "nsd 4.12.0" .\" Copyright (c) 2001\-2024, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-checkconf \- NSD configuration file checker. .SH "SYNOPSIS" .B nsd\-checkconf .RB [ \-v ] .RB [ \-f ] .RB [ \-h ] .RB [ \-o .IR option ] .RB [ \-z .IR zonename ] .RB [ \-p .IR pattern ] .RB [ \-s .IR keyname ] .RB [ \-t .IR tlsauthname ] .I configfile .SH "DESCRIPTION" .B nsd\-checkconf reads a configuration file. It prints parse errors to standard error, and performs additional checks on the contents. The configfile format is described in nsd.conf(5). .P The utility of this program is to check a config file for errors before using it in nsd(8). This program can also be used for shell scripts to access the nsd config file, using the \-o and \-z options. .P .SH "OPTIONS" .TP .B \-v After reading print the options to standard output in configfile format. Without this option, only success or parse errors are reported. .TP .B \-f Print full pathname when used with files, like with \-o pidfile. This includes the chroot in the way it is applied to the pidfile. .TP .B \-h Print usage help information and exit. .TP .B \-o\fI option Return only this option from the config file. This option can be used in conjunction with the .B \-z and the .B \-p option, or without them to query the server: section. The special value .I zones prints out a list of configured zones. The special value .I patterns prints out a list of configured patterns. .sp This option can be used to parse the config file from the shell. If the .B \-z option is given, but the .B \-o option is not given, nothing is printed. .TP .B \-s\fI keyname Prints the key secret (base64 blob) configured for this key in the config file. Used to help shell scripts parse the config file. .TP .B \-t\fI tls-auth Prints the authentication domain name configured for this tls-auth clause in the config file. Used to help shell scripts parse the config file. .TP .B \-p\fI pattern Return the option specified with .B \-o for the given pattern name. .TP .B \-z\fI zonename Return the option specified with .B \-o for zone 'zonename'. .sp If this option is not given, the server section of the config file is used. .sp The \-o, \-s and \-z option print configfile options to standard output. .SH "FILES" .TP @nsdconfigfile@ default .B NSD configuration file .SH "SEE ALSO" \fInsd\fR(8), \fInsd.conf\fR(5), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. nsd-4.12.0/netio.h0000644000175000017500000001165115002373054013270 0ustar mozziemozzie/* * netio.h -- network I/O support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The netio module implements event based I/O handling using * pselect(2). Multiple event handlers can wait for a certain event * to occur simultaneously. Each event handler is called when an * event occurs that the event handler has indicated that it is * willing to handle. * * There are four types of events that can be handled: * * NETIO_EVENT_READ: reading will not block. * NETIO_EVENT_WRITE: writing will not block. * NETIO_EVENT_TIMEOUT: the timeout expired. * * A file descriptor must be specified if the handler is interested in * the first three event types. A timeout must be specified if the * event handler is interested in timeouts. These event types can be * OR'ed together if the handler is willing to handle multiple types * of events. * * The special event type NETIO_EVENT_NONE is available if you wish to * temporarily disable the event handler without removing and adding * the handler to the netio structure. * * The event callbacks are free to modify the netio_handler_type * structure to change the file descriptor, timeout, event types, user * data, or handler functions. * * The main loop of the program must call netio_dispatch to check for * events and dispatch them to the handlers. An additional timeout * can be specified as well as the signal mask to install while * blocked in pselect(2). */ #ifndef NETIO_H #define NETIO_H #ifdef HAVE_SYS_SELECT_H #include #endif #include #include "region-allocator.h" /* * The type of events a handler is interested in. These can be OR'ed * together to specify multiple event types. */ enum netio_event_types { NETIO_EVENT_NONE = 0, NETIO_EVENT_READ = 1, NETIO_EVENT_WRITE = 2, NETIO_EVENT_TIMEOUT = 4, }; typedef enum netio_event_types netio_event_types_type; typedef struct netio netio_type; typedef struct netio_handler netio_handler_type; typedef struct netio_handler_list netio_handler_list_type; struct netio { region_type *region; netio_handler_list_type *handlers; netio_handler_list_type *deallocated; /* * Cached value of the current time. The cached value is * cleared at the start of netio_dispatch to calculate the * relative timeouts of the event handlers and after calling * pselect(2) so handlers can use it to calculate a new * absolute timeout. * * Use netio_current_time() to read the current time. */ int have_current_time; struct timespec cached_current_time; /* * Next handler in the dispatch. Only valid during callbacks. * To make sure that deletes respect the state of the iterator. */ netio_handler_list_type *dispatch_next; }; typedef void (*netio_event_handler_type)(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); struct netio_handler { /* * The file descriptor that should be checked for events. If * the file descriptor is negative only timeout events are * checked for. */ int fd; /** index of the pollfd array for this handler */ int pfd; /* * The time when no events should be checked for and the * handler should be called with the NETIO_EVENT_TIMEOUT * event type. Unlike most timeout parameters the time should * be absolute, not relative! */ struct timespec *timeout; /* * Additional user data. */ void *user_data; /* * The type of events that should be checked for. These types * can be OR'ed together to wait for multiple types of events. */ netio_event_types_type event_types; /* * The event handler. The event_types parameter contains the * OR'ed set of event types that actually triggered. The * event handler is allowed to modify this handler object. * The event handler SHOULD NOT block. */ netio_event_handler_type event_handler; }; struct netio_handler_list { netio_handler_list_type *next; netio_handler_type *handler; }; /* * Create a new netio instance using the specified REGION. The netio * instance is cleaned up when the REGION is deallocated. */ netio_type *netio_create(region_type *region); /* * Add a new HANDLER to NETIO. */ void netio_add_handler(netio_type *netio, netio_handler_type *handler); /* * Remove the HANDLER from NETIO. */ void netio_remove_handler(netio_type *netio, netio_handler_type *handler); /* * Retrieve the current time (using gettimeofday(2). */ const struct timespec *netio_current_time(netio_type *netio); /* * Check for events and dispatch them to the handlers. If TIMEOUT is * specified it specifies the maximum time to wait for an event to * arrive. SIGMASK is passed to the underlying pselect(2) call. * Returns the number of non-timeout events dispatched, 0 on timeout, * and -1 on error (with errno set appropriately). */ int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask); #endif /* NETIO_H */ nsd-4.12.0/netio.c0000644000175000017500000001462615002373054013270 0ustar mozziemozzie/* * netio.c -- network I/O support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "netio.h" #include "util.h" #define MAX_NETIO_FDS 1024 netio_type * netio_create(region_type *region) { netio_type *result; assert(region); result = (netio_type *) region_alloc(region, sizeof(netio_type)); result->region = region; result->handlers = NULL; result->deallocated = NULL; result->dispatch_next = NULL; return result; } void netio_add_handler(netio_type *netio, netio_handler_type *handler) { netio_handler_list_type *elt; assert(netio); assert(handler); if (netio->deallocated) { /* * If we have deallocated handler list elements, reuse * the first one. */ elt = netio->deallocated; netio->deallocated = elt->next; } else { /* * Allocate a new one. */ elt = (netio_handler_list_type *) region_alloc( netio->region, sizeof(netio_handler_list_type)); } elt->next = netio->handlers; elt->handler = handler; elt->handler->pfd = -1; netio->handlers = elt; } void netio_remove_handler(netio_type *netio, netio_handler_type *handler) { netio_handler_list_type **elt_ptr; assert(netio); assert(handler); for (elt_ptr = &netio->handlers; *elt_ptr; elt_ptr = &(*elt_ptr)->next) { if ((*elt_ptr)->handler == handler) { netio_handler_list_type *next = (*elt_ptr)->next; if ((*elt_ptr) == netio->dispatch_next) netio->dispatch_next = next; (*elt_ptr)->handler = NULL; (*elt_ptr)->next = netio->deallocated; netio->deallocated = *elt_ptr; *elt_ptr = next; break; } } } const struct timespec * netio_current_time(netio_type *netio) { assert(netio); if (!netio->have_current_time) { struct timeval current_timeval; if (gettimeofday(¤t_timeval, NULL) == -1) { log_msg(LOG_ERR, "gettimeofday: %s, aborting.", strerror(errno)); abort(); } timeval_to_timespec(&netio->cached_current_time, ¤t_timeval); netio->have_current_time = 1; } return &netio->cached_current_time; } int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask) { /* static arrays to avoid allocation */ static struct pollfd fds[MAX_NETIO_FDS]; int numfd; int have_timeout = 0; struct timespec minimum_timeout; netio_handler_type *timeout_handler = NULL; netio_handler_list_type *elt; int rc; int result = 0; #ifndef HAVE_PPOLL sigset_t origmask; #endif assert(netio); /* * Clear the cached current time. */ netio->have_current_time = 0; /* * Initialize the minimum timeout with the timeout parameter. */ if (timeout) { have_timeout = 1; memcpy(&minimum_timeout, timeout, sizeof(struct timespec)); } /* * Initialize the fd_sets and timeout based on the handler * information. */ numfd = 0; for (elt = netio->handlers; elt; elt = elt->next) { netio_handler_type *handler = elt->handler; if (handler->fd != -1 && numfd < MAX_NETIO_FDS) { fds[numfd].fd = handler->fd; fds[numfd].events = 0; fds[numfd].revents = 0; handler->pfd = numfd; if (handler->event_types & NETIO_EVENT_READ) { fds[numfd].events |= POLLIN; } if (handler->event_types & NETIO_EVENT_WRITE) { fds[numfd].events |= POLLOUT; } numfd++; } else { handler->pfd = -1; } if (handler->timeout && (handler->event_types & NETIO_EVENT_TIMEOUT)) { struct timespec relative; relative.tv_sec = handler->timeout->tv_sec; relative.tv_nsec = handler->timeout->tv_nsec; timespec_subtract(&relative, netio_current_time(netio)); if (!have_timeout || timespec_compare(&relative, &minimum_timeout) < 0) { have_timeout = 1; minimum_timeout.tv_sec = relative.tv_sec; minimum_timeout.tv_nsec = relative.tv_nsec; timeout_handler = handler; } } } if (have_timeout && minimum_timeout.tv_sec < 0) { /* * On negative timeout for a handler, immediately * dispatch the timeout event without checking for * other events. */ if (timeout_handler && (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) { timeout_handler->event_handler(netio, timeout_handler, NETIO_EVENT_TIMEOUT); } return result; } /* Check for events. */ #ifdef HAVE_PPOLL rc = ppoll(fds, numfd, (have_timeout?&minimum_timeout:NULL), sigmask); #else sigprocmask(SIG_SETMASK, sigmask, &origmask); rc = poll(fds, numfd, (have_timeout?minimum_timeout.tv_sec*1000+ minimum_timeout.tv_nsec/1000000:-1)); sigprocmask(SIG_SETMASK, &origmask, NULL); #endif /* HAVE_PPOLL */ if (rc == -1) { if(errno == EINVAL || errno == EACCES || errno == EBADF) { log_msg(LOG_ERR, "fatal error poll: %s.", strerror(errno)); exit(1); } return -1; } /* * Clear the cached current_time (pselect(2) may block for * some time so the cached value is likely to be old). */ netio->have_current_time = 0; if (rc == 0) { /* * No events before the minimum timeout expired. * Dispatch to handler if interested. */ if (timeout_handler && (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) { timeout_handler->event_handler(netio, timeout_handler, NETIO_EVENT_TIMEOUT); } } else { /* * Dispatch all the events to interested handlers * based on the fd_sets. Note that a handler might * deinstall itself, so store the next handler before * calling the current handler! */ assert(netio->dispatch_next == NULL); for (elt = netio->handlers; elt && rc; ) { netio_handler_type *handler = elt->handler; netio->dispatch_next = elt->next; if (handler->fd != -1 && handler->pfd != -1) { netio_event_types_type event_types = NETIO_EVENT_NONE; if ((fds[handler->pfd].revents & POLLIN)) { event_types |= NETIO_EVENT_READ; } if ((fds[handler->pfd].revents & POLLOUT)) { event_types |= NETIO_EVENT_WRITE; } if ((fds[handler->pfd].revents & (POLLNVAL|POLLHUP|POLLERR))) { /* closed/error: give a read event, * or otherwise, a write event */ if((handler->event_types&NETIO_EVENT_READ)) event_types |= NETIO_EVENT_READ; else if((handler->event_types&NETIO_EVENT_WRITE)) event_types |= NETIO_EVENT_WRITE; } if (event_types & handler->event_types) { handler->event_handler(netio, handler, event_types & handler->event_types); ++result; } } elt = netio->dispatch_next; } netio->dispatch_next = NULL; } return result; } nsd-4.12.0/namedb.h0000644000175000017500000003455015002373054013403 0ustar mozziemozzie/* * namedb.h -- nsd(8) internal namespace database definitions * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef NAMEDB_H #define NAMEDB_H #include #include "dname.h" #include "dns.h" #include "radtree.h" #include "rbtree.h" struct zone_options; struct nsd_options; struct udb_base; struct udb_ptr; struct nsd; struct zone_ixfr; typedef union rdata_atom rdata_atom_type; typedef struct rrset rrset_type; typedef struct rr rr_type; /* * A domain name table supporting fast insert and search operations. */ typedef struct domain_table domain_table_type; typedef struct domain domain_type; typedef struct zone zone_type; typedef struct namedb namedb_type; struct domain_table { region_type* region; #ifdef USE_RADIX_TREE struct radtree *nametree; #else rbtree_type *names_to_domains; #endif domain_type* root; /* ptr to biggest domain.number and last in list. * the root is the lowest and first in the list. */ domain_type *numlist_last; #ifdef NSEC3 /* the prehash list, start of the list */ domain_type* prehash_list; #endif /* NSEC3 */ }; #ifdef NSEC3 typedef struct nsec3_hash_node nsec3_hash_node_type; struct nsec3_hash_node { /* hash value */ uint8_t hash[NSEC3_HASH_LEN]; /* entry in the hashtree */ rbnode_type node; } ATTR_PACKED; typedef struct nsec3_hash_wc_node nsec3_hash_wc_node_type; struct nsec3_hash_wc_node { nsec3_hash_node_type hash; nsec3_hash_node_type wc; }; struct nsec3_domain_data { /* (if nsec3 chain complete) always the covering nsec3 record */ domain_type* nsec3_cover; /* the nsec3 that covers the wildcard child of this domain. */ domain_type* nsec3_wcard_child_cover; /* for the DS case we must answer on the parent side of zone cut */ domain_type* nsec3_ds_parent_cover; /* NSEC3 domains to prehash, prev and next on the list or cleared */ domain_type* prehash_prev, *prehash_next; /* entry in the nsec3tree (for NSEC3s in the chain in use) */ rbnode_type nsec3_node; /* node for the precompiled domain and the precompiled wildcard */ nsec3_hash_wc_node_type* hash_wc; /* node for the precompiled parent ds */ nsec3_hash_node_type* ds_parent_hash; /* if the domain has an NSEC3 for it, use cover ptr to get it. */ unsigned nsec3_is_exact : 1; /* same but on parent side */ unsigned nsec3_ds_parent_is_exact : 1; } ATTR_PACKED; #endif /* NSEC3 */ struct domain { #ifdef USE_RADIX_TREE struct radnode* rnode; const dname_type* dname; #else rbnode_type node; #endif domain_type* parent; domain_type* wildcard_child_closest_match; rrset_type* rrsets; #ifdef NSEC3 struct nsec3_domain_data* nsec3; #endif /* double-linked list sorted by domain.number */ domain_type* numlist_prev, *numlist_next; uint32_t number; /* Unique domain name number. */ uint32_t usage; /* number of ptrs to this from RRs(in rdata) and from zone-apex pointers, also the root has one more to make sure it cannot be deleted. */ /* * This domain name exists (see wildcard clarification draft). */ unsigned is_existing : 1; unsigned is_apex : 1; } ATTR_PACKED; struct zone { struct radnode *node; /* this entry in zonetree */ domain_type* apex; rrset_type* soa_rrset; rrset_type* soa_nx_rrset; /* see bug #103 */ rrset_type* ns_rrset; #ifdef NSEC3 rr_type* nsec3_param; /* NSEC3PARAM RR of chain in use or NULL */ domain_type* nsec3_last; /* last domain with nsec3, wraps */ /* in these trees, the root contains an elem ptr to the radtree* */ rbtree_type* nsec3tree; /* tree with relevant NSEC3 domains */ rbtree_type* hashtree; /* tree, hashed NSEC3precompiled domains */ rbtree_type* wchashtree; /* tree, wildcard hashed domains */ rbtree_type* dshashtree; /* tree, ds-parent-hash domains */ #endif struct zone_options* opts; struct zone_ixfr* ixfr; char *filename; /* set if read from file, which files */ /* list of include files to monitor for changes */ struct { size_t count; char **paths; } includes; char* logstr; /* set for zone xfer, the log string */ struct timespec mtime; /* time of last modification */ unsigned zonestatid; /* array index for zone stats */ unsigned is_secure : 1; /* zone uses DNSSEC */ unsigned is_ok : 1; /* zone has not expired */ unsigned is_changed : 1; /* zone changes must be written to disk */ unsigned is_updated : 1; /* zone was changed by XFR */ unsigned is_skipped : 1; /* subsequent zone updates are skipped */ unsigned is_checked : 1; /* zone already verified */ unsigned is_bad : 1; /* zone failed verification */ } ATTR_PACKED; /* a RR in DNS */ struct rr { domain_type* owner; rdata_atom_type* rdatas; uint32_t ttl; uint16_t type; uint16_t klass; uint16_t rdata_count; } ATTR_PACKED; /* * An RRset consists of at least one RR. All RRs are from the same * zone. */ struct rrset { rrset_type* next; zone_type* zone; rr_type* rrs; uint16_t rr_count; } ATTR_PACKED; /* * The field used is based on the wireformat the atom is stored in. * The allowed wireformats are defined by the rdata_wireformat_type * enumeration. */ union rdata_atom { /* RDATA_WF_COMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME */ domain_type* domain; /* Default. */ uint16_t* data; }; /* * Create a new domain_table containing only the root domain. */ domain_table_type *domain_table_create(region_type *region); /* * Search the domain table for a match and the closest encloser. */ int domain_table_search(domain_table_type* table, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser); /* * The number of domains stored in the table (minimum is one for the * root domain). */ static inline uint32_t domain_table_count(domain_table_type* table) { #ifdef USE_RADIX_TREE return table->nametree->count; #else return table->names_to_domains->count; #endif } /* * Find the specified dname in the domain_table. NULL is returned if * there is no exact match. */ domain_type* domain_table_find(domain_table_type* table, const dname_type* dname); /* * Insert a domain name in the domain table. If the domain name is * not yet present in the table it is copied and a new dname_info node * is created (as well as for the missing parent domain names, if * any). Otherwise the domain_type that is already in the * domain_table is returned. */ domain_type *domain_table_insert(domain_table_type *table, const dname_type *dname); /* put domain into nsec3 hash space tree */ void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree, int (*cmpf)(const void*, const void*), domain_type* domain, rbnode_type* node); void zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node); void hash_tree_delete(region_type* region, rbtree_type* tree); void prehash_clear(domain_table_type* table); void prehash_add(domain_table_type* table, domain_type* domain); void prehash_del(domain_table_type* table, domain_type* domain); int domain_is_prehash(domain_table_type* table, domain_type* domain); /* * Add an RRset to the specified domain. Updates the is_existing flag * as required. */ void domain_add_rrset(domain_type* domain, rrset_type* rrset); rrset_type* domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type); rrset_type* domain_find_any_rrset(domain_type* domain, zone_type* zone); zone_type* domain_find_zone(namedb_type* db, domain_type* domain); zone_type* domain_find_parent_zone(namedb_type* db, zone_type* zone); domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns); /* find DNAME rrset in domain->parent or higher and return that domain */ domain_type * find_dname_above(domain_type* domain, zone_type* zone); int domain_is_glue(domain_type* domain, zone_type* zone); rrset_type* domain_find_non_cname_rrset(domain_type* domain, zone_type* zone); domain_type* domain_wildcard_child(domain_type* domain); domain_type *domain_previous_existing_child(domain_type* domain); int zone_is_secure(zone_type* zone); static inline dname_type * domain_dname(domain_type* domain) { #ifdef USE_RADIX_TREE return (dname_type *) domain->dname; #else return (dname_type *) domain->node.key; #endif } static inline const dname_type * domain_dname_const(const domain_type* domain) { #ifdef USE_RADIX_TREE return domain->dname; #else return (const dname_type *) domain->node.key; #endif } static inline domain_type * domain_previous(domain_type* domain) { #ifdef USE_RADIX_TREE struct radnode* prev = radix_prev(domain->rnode); return prev == NULL ? NULL : (domain_type*)prev->elem; #else rbnode_type *prev = rbtree_previous((rbnode_type *) domain); return prev == RBTREE_NULL ? NULL : (domain_type *) prev; #endif } static inline domain_type * domain_next(domain_type* domain) { #ifdef USE_RADIX_TREE struct radnode* next = radix_next(domain->rnode); return next == NULL ? NULL : (domain_type*)next->elem; #else rbnode_type *next = rbtree_next((rbnode_type *) domain); return next == RBTREE_NULL ? NULL : (domain_type *) next; #endif } /* easy comparison for subdomain, true if d1 is subdomain of d2. */ static inline int domain_is_subdomain(domain_type* d1, domain_type* d2) { return dname_is_subdomain(domain_dname(d1), domain_dname(d2)); } /* easy printout, to static buffer of dname_to_string, fqdn. */ static inline const char* domain_to_string(domain_type* domain) { return dname_to_string(domain_dname(domain), NULL); } /* easy printout, to given buffer of dname_to_string, fqdn. */ static inline const char* domain_to_string_buf(domain_type* domain, char *buf) { return dname_to_string_buf(domain_dname(domain), NULL, buf); } /* * The type covered by the signature in the specified RRSIG RR. */ uint16_t rr_rrsig_type_covered(rr_type* rr); struct namedb { region_type* region; domain_table_type* domains; struct radtree* zonetree; /* the timestamp on the ixfr.db file */ struct timeval diff_timestamp; /* if diff_skip=1, diff_pos contains the nsd.diff place to continue */ uint8_t diff_skip; off_t diff_pos; }; static inline int rdata_atom_is_domain(uint16_t type, size_t index); static inline int rdata_atom_is_literal_domain(uint16_t type, size_t index); static inline domain_type * rdata_atom_domain(rdata_atom_type atom) { return atom.domain; } static inline uint16_t rdata_atom_size(rdata_atom_type atom) { return *atom.data; } static inline uint8_t * rdata_atom_data(rdata_atom_type atom) { return (uint8_t *) (atom.data + 1); } /* Find the zone for the specified dname in DB. */ zone_type *namedb_find_zone(namedb_type *db, const dname_type *dname); /* * Delete a domain name from the domain table. Removes dname_info node. * Only deletes if usage is 0, has no rrsets and no children. Checks parents * for deletion as well. Adjusts numberlist(domain.number), and * wcard_child closest match. */ void domain_table_deldomain(namedb_type* db, domain_type* domain); /** dbcreate.c */ int print_rrs(FILE* out, struct zone* zone); /** marshal rdata into buffer, must be MAX_RDLENGTH in size */ size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz); /* dbaccess.c */ int namedb_lookup (struct namedb* db, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser); /* pass number of children (to alloc in dirty array */ struct namedb *namedb_open(struct nsd_options* opt); void namedb_close(struct namedb* db); /* free ixfr data stored for zones */ void namedb_free_ixfr(struct namedb* db); void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, struct udb_base* taskudb, struct udb_ptr* last_task); void namedb_check_zonefile(struct nsd* nsd, struct udb_base* taskudb, struct udb_ptr* last_task, struct zone_options* zo); /** zone one zonefile into memory and revert on parse error, write to udb */ void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, struct udb_base* taskudb, struct udb_ptr* last_task); zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zopt); static inline zone_type* namedb_find_or_create_zone(namedb_type *db, const dname_type *dname, struct zone_options* zopt) { zone_type* zone = namedb_find_zone(db, dname); return zone ? zone : namedb_zone_create(db, dname, zopt); } void namedb_zone_free_filenames(namedb_type* db, zone_type* zone); void namedb_zone_delete(namedb_type* db, zone_type* zone); void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt); void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options); int create_dirs(const char* path); int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist); void allocate_domain_nsec3(domain_table_type *table, domain_type *result); static inline int rdata_atom_is_domain(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); return (index < descriptor->maximum && (descriptor->wireformat[index] == RDATA_WF_COMPRESSED_DNAME || descriptor->wireformat[index] == RDATA_WF_UNCOMPRESSED_DNAME)); } static inline int rdata_atom_is_literal_domain(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); return (index < descriptor->maximum && (descriptor->wireformat[index] == RDATA_WF_LITERAL_DNAME)); } static inline rdata_wireformat_type rdata_atom_wireformat_type(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); assert(index < descriptor->maximum); return (rdata_wireformat_type) descriptor->wireformat[index]; } static inline uint16_t rrset_rrtype(rrset_type* rrset) { assert(rrset); assert(rrset->rr_count > 0); return rrset->rrs[0].type; } static inline uint16_t rrset_rrclass(rrset_type* rrset) { assert(rrset); assert(rrset->rr_count > 0); return rrset->rrs[0].klass; } /* * zone_rr_iter can be used to iterate over all RRs in a given zone. the * SOA RRSET is guaranteed to be returned first. */ typedef struct zone_rr_iter zone_rr_iter_type; struct zone_rr_iter { zone_type *zone; domain_type *domain; rrset_type *rrset; ssize_t index; }; void zone_rr_iter_init(zone_rr_iter_type *iter, zone_type *zone); rr_type *zone_rr_iter_next(zone_rr_iter_type *iter); /** make the domain last in the numlist, changes numbers of domains */ void numlist_make_last(domain_table_type* table, domain_type* domain); /** pop the biggest domain off the numlist */ domain_type* numlist_pop_last(domain_table_type* table); #endif /* NAMEDB_H */ nsd-4.12.0/namedb.c0000644000175000017500000004606115002373054013376 0ustar mozziemozzie/* * namedb.c -- common namedb operations. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "namedb.h" #include "nsec3.h" static domain_type * allocate_domain_info(domain_table_type* table, const dname_type* dname, domain_type* parent) { domain_type *result; assert(table); assert(dname); assert(parent); result = (domain_type *) region_alloc(table->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE result->dname #else result->node.key #endif = dname_partial_copy( table->region, dname, domain_dname(parent)->label_count + 1); result->parent = parent; result->wildcard_child_closest_match = result; result->rrsets = NULL; result->usage = 0; #ifdef NSEC3 result->nsec3 = NULL; #endif result->is_existing = 0; result->is_apex = 0; assert(table->numlist_last); /* it exists because root exists */ /* push this domain at the end of the numlist */ result->number = table->numlist_last->number+1; result->numlist_next = NULL; result->numlist_prev = table->numlist_last; table->numlist_last->numlist_next = result; table->numlist_last = result; return result; } #ifdef NSEC3 void allocate_domain_nsec3(domain_table_type* table, domain_type* result) { if(result->nsec3) return; result->nsec3 = (struct nsec3_domain_data*) region_alloc(table->region, sizeof(struct nsec3_domain_data)); result->nsec3->nsec3_cover = NULL; result->nsec3->nsec3_wcard_child_cover = NULL; result->nsec3->nsec3_ds_parent_cover = NULL; result->nsec3->nsec3_is_exact = 0; result->nsec3->nsec3_ds_parent_is_exact = 0; result->nsec3->hash_wc = NULL; result->nsec3->ds_parent_hash = NULL; result->nsec3->prehash_prev = NULL; result->nsec3->prehash_next = NULL; result->nsec3->nsec3_node.key = NULL; } #endif /* NSEC3 */ void numlist_make_last(domain_table_type* table, domain_type* domain) { uint32_t sw; domain_type* last = table->numlist_last; if(domain == last) return; /* swap numbers with the last element */ sw = domain->number; domain->number = last->number; last->number = sw; /* swap list position with the last element */ assert(domain->numlist_next); assert(last->numlist_prev); if(domain->numlist_next != last) { /* case 1: there are nodes between domain .. last */ domain_type* span_start = domain->numlist_next; domain_type* span_end = last->numlist_prev; /* these assignments walk the new list from start to end */ if(domain->numlist_prev) domain->numlist_prev->numlist_next = last; last->numlist_prev = domain->numlist_prev; last->numlist_next = span_start; span_start->numlist_prev = last; span_end->numlist_next = domain; domain->numlist_prev = span_end; domain->numlist_next = NULL; } else { /* case 2: domain and last are neighbors */ /* these assignments walk the new list from start to end */ if(domain->numlist_prev) domain->numlist_prev->numlist_next = last; last->numlist_prev = domain->numlist_prev; last->numlist_next = domain; domain->numlist_prev = last; domain->numlist_next = NULL; } table->numlist_last = domain; } domain_type* numlist_pop_last(domain_table_type* table) { domain_type* d = table->numlist_last; table->numlist_last = table->numlist_last->numlist_prev; if(table->numlist_last) table->numlist_last->numlist_next = NULL; return d; } /** see if a domain is eligible to be deleted, and thus is not used */ static int domain_can_be_deleted(domain_type* domain) { domain_type* n; /* it has data or it has usage, do not delete it */ if(domain->rrsets) return 0; if(domain->usage) return 0; n = domain_next(domain); /* it has children domains, do not delete it */ if(n && domain_is_subdomain(n, domain)) return 0; return 1; } #ifdef NSEC3 /** see if domain is on the prehash list */ int domain_is_prehash(domain_table_type* table, domain_type* domain) { if(domain->nsec3 && (domain->nsec3->prehash_prev || domain->nsec3->prehash_next)) return 1; return (table->prehash_list == domain); } /** remove domain node from NSEC3 tree in hash space */ void zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node) { if(!node->key) return; rbtree_delete(tree, node->key); /* note that domain is no longer in the tree */ node->key = NULL; } /** clear the prehash list */ void prehash_clear(domain_table_type* table) { domain_type* d = table->prehash_list, *n; while(d) { n = d->nsec3->prehash_next; d->nsec3->prehash_prev = NULL; d->nsec3->prehash_next = NULL; d = n; } table->prehash_list = NULL; } /** add domain to prehash list */ void prehash_add(domain_table_type* table, domain_type* domain) { if(domain_is_prehash(table, domain)) return; allocate_domain_nsec3(table, domain); domain->nsec3->prehash_next = table->prehash_list; if(table->prehash_list) table->prehash_list->nsec3->prehash_prev = domain; table->prehash_list = domain; } /** remove domain from prehash list */ void prehash_del(domain_table_type* table, domain_type* domain) { if(domain->nsec3->prehash_next) domain->nsec3->prehash_next->nsec3->prehash_prev = domain->nsec3->prehash_prev; if(domain->nsec3->prehash_prev) domain->nsec3->prehash_prev->nsec3->prehash_next = domain->nsec3->prehash_next; else table->prehash_list = domain->nsec3->prehash_next; domain->nsec3->prehash_next = NULL; domain->nsec3->prehash_prev = NULL; } #endif /* NSEC3 */ /** perform domain name deletion */ static void do_deldomain(namedb_type* db, domain_type* domain) { assert(domain && domain->parent); /* exists and not root */ /* first adjust the number list so that domain is the last one */ numlist_make_last(db->domains, domain); /* pop off the domain from the number list */ (void)numlist_pop_last(db->domains); #ifdef NSEC3 /* if on prehash list, remove from prehash */ if(domain_is_prehash(db->domains, domain)) prehash_del(db->domains, domain); /* see if nsec3-nodes are used */ if(domain->nsec3) { if(domain->nsec3->nsec3_node.key) zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) ->nsec3tree, &domain->nsec3->nsec3_node); if(domain->nsec3->hash_wc) { if(domain->nsec3->hash_wc->hash.node.key) zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) ->hashtree, &domain->nsec3->hash_wc->hash.node); if(domain->nsec3->hash_wc->wc.node.key) zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) ->wchashtree, &domain->nsec3->hash_wc->wc.node); } if(domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key) zone_del_domain_in_hash_tree(nsec3_tree_dszone(db, domain) ->dshashtree, &domain->nsec3->ds_parent_hash->node); if(domain->nsec3->hash_wc) { region_recycle(db->domains->region, domain->nsec3->hash_wc, sizeof(nsec3_hash_wc_node_type)); } if(domain->nsec3->ds_parent_hash) { region_recycle(db->domains->region, domain->nsec3->ds_parent_hash, sizeof(nsec3_hash_node_type)); } region_recycle(db->domains->region, domain->nsec3, sizeof(struct nsec3_domain_data)); } #endif /* NSEC3 */ /* see if this domain is someones wildcard-child-closest-match, * which can only be the parent, and then it should use the * one-smaller than this domain as closest-match. */ if(domain->parent->wildcard_child_closest_match == domain) domain->parent->wildcard_child_closest_match = domain_previous_existing_child(domain); /* actual removal */ #ifdef USE_RADIX_TREE radix_delete(db->domains->nametree, domain->rnode); #else rbtree_delete(db->domains->names_to_domains, domain->node.key); #endif region_recycle(db->domains->region, domain_dname(domain), dname_total_size(domain_dname(domain))); region_recycle(db->domains->region, domain, sizeof(domain_type)); } void domain_table_deldomain(namedb_type* db, domain_type* domain) { domain_type* parent; while(domain_can_be_deleted(domain)) { parent = domain->parent; /* delete it */ do_deldomain(db, domain); /* test parent */ domain = parent; } } void hash_tree_delete(region_type* region, rbtree_type* tree) { region_recycle(region, tree, sizeof(rbtree_type)); } /** add domain nsec3 node to hashedspace tree */ void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree, int (*cmpf)(const void*, const void*), domain_type* domain, rbnode_type* node) { if(!*tree) *tree = rbtree_create(region, cmpf); if(node->key && node->key == domain && rbtree_search(*tree, domain) == node) return; memset(node, 0, sizeof(rbnode_type)); node->key = domain; rbtree_insert(*tree, node); } domain_table_type * domain_table_create(region_type* region) { const dname_type* origin; domain_table_type* result; domain_type* root; assert(region); origin = dname_make(region, (uint8_t *) "", 0); root = (domain_type *) region_alloc(region, sizeof(domain_type)); #ifdef USE_RADIX_TREE root->dname #else root->node.key #endif = origin; root->parent = NULL; root->wildcard_child_closest_match = root; root->rrsets = NULL; root->number = 1; /* 0 is used for after header */ root->usage = 1; /* do not delete root, ever */ root->is_existing = 0; root->is_apex = 0; root->numlist_prev = NULL; root->numlist_next = NULL; #ifdef NSEC3 root->nsec3 = NULL; #endif result = (domain_table_type *) region_alloc(region, sizeof(domain_table_type)); result->region = region; #ifdef USE_RADIX_TREE result->nametree = radix_tree_create(region); root->rnode = radname_insert(result->nametree, dname_name(root->dname), root->dname->name_size, root); #else result->names_to_domains = rbtree_create( region, (int (*)(const void *, const void *)) dname_compare); rbtree_insert(result->names_to_domains, (rbnode_type *) root); #endif result->root = root; result->numlist_last = root; #ifdef NSEC3 result->prehash_list = NULL; #endif return result; } int domain_table_search(domain_table_type *table, const dname_type *dname, domain_type **closest_match, domain_type **closest_encloser) { int exact; uint8_t label_match_count; assert(table); assert(dname); assert(closest_match); assert(closest_encloser); #ifdef USE_RADIX_TREE exact = radname_find_less_equal(table->nametree, dname_name(dname), dname->name_size, (struct radnode**)closest_match); *closest_match = (domain_type*)((*(struct radnode**)closest_match)->elem); #else exact = rbtree_find_less_equal(table->names_to_domains, dname, (rbnode_type **) closest_match); #endif assert(*closest_match); *closest_encloser = *closest_match; if (!exact) { label_match_count = dname_label_match_count( domain_dname(*closest_encloser), dname); assert(label_match_count < dname->label_count); while (label_match_count < domain_dname(*closest_encloser)->label_count) { (*closest_encloser) = (*closest_encloser)->parent; assert(*closest_encloser); } } return exact; } domain_type * domain_table_find(domain_table_type* table, const dname_type* dname) { domain_type* closest_match; domain_type* closest_encloser; int exact; exact = domain_table_search( table, dname, &closest_match, &closest_encloser); return exact ? closest_encloser : NULL; } domain_type * domain_table_insert(domain_table_type* table, const dname_type* dname) { domain_type* closest_match; domain_type* closest_encloser; domain_type* result; int exact; assert(table); assert(dname); exact = domain_table_search( table, dname, &closest_match, &closest_encloser); if (exact) { result = closest_encloser; } else { assert(domain_dname(closest_encloser)->label_count < dname->label_count); /* Insert new node(s). */ do { result = allocate_domain_info(table, dname, closest_encloser); #ifdef USE_RADIX_TREE result->rnode = radname_insert(table->nametree, dname_name(result->dname), result->dname->name_size, result); #else rbtree_insert(table->names_to_domains, (rbnode_type *) result); #endif /* * If the newly added domain name is larger * than the parent's current * wildcard_child_closest_match but smaller or * equal to the wildcard domain name, update * the parent's wildcard_child_closest_match * field. */ if (label_compare(dname_name(domain_dname(result)), (const uint8_t *) "\001*") <= 0 && dname_compare(domain_dname(result), domain_dname(closest_encloser->wildcard_child_closest_match)) > 0) { closest_encloser->wildcard_child_closest_match = result; } closest_encloser = result; } while (domain_dname(closest_encloser)->label_count < dname->label_count); } return result; } domain_type *domain_previous_existing_child(domain_type* domain) { domain_type* parent = domain->parent; domain = domain_previous(domain); while(domain && !domain->is_existing) { if(domain == parent) /* do not walk back above parent */ return parent; domain = domain_previous(domain); } return domain; } void domain_add_rrset(domain_type* domain, rrset_type* rrset) { #if 0 /* fast */ rrset->next = domain->rrsets; domain->rrsets = rrset; #else /* preserve ordering, add at end */ rrset_type** p = &domain->rrsets; while(*p) p = &((*p)->next); *p = rrset; rrset->next = 0; #endif while (domain && !domain->is_existing) { domain->is_existing = 1; /* does this name in existance update the parent's * wildcard closest match? */ if(domain->parent && label_compare(dname_name(domain_dname(domain)), (const uint8_t *) "\001*") <= 0 && dname_compare(domain_dname(domain), domain_dname(domain->parent->wildcard_child_closest_match)) > 0) { domain->parent->wildcard_child_closest_match = domain; } domain = domain->parent; } } rrset_type * domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type) { rrset_type* result = domain->rrsets; while (result) { if (result->zone == zone && rrset_rrtype(result) == type) { return result; } result = result->next; } return NULL; } rrset_type * domain_find_any_rrset(domain_type* domain, zone_type* zone) { rrset_type* result = domain->rrsets; while (result) { if (result->zone == zone) { return result; } result = result->next; } return NULL; } zone_type * domain_find_zone(namedb_type* db, domain_type* domain) { rrset_type* rrset; while (domain) { if(domain->is_apex) { for (rrset = domain->rrsets; rrset; rrset = rrset->next) { if (rrset_rrtype(rrset) == TYPE_SOA) { return rrset->zone; } } return namedb_find_zone(db, domain_dname(domain)); } domain = domain->parent; } return NULL; } zone_type * domain_find_parent_zone(namedb_type* db, zone_type* zone) { rrset_type* rrset; assert(zone); for (rrset = zone->apex->rrsets; rrset; rrset = rrset->next) { if (rrset->zone != zone && rrset_rrtype(rrset) == TYPE_NS) { return rrset->zone; } } /* the NS record in the parent zone above this zone is not present, * workaround to find that parent zone anyway */ if(zone->apex->parent) return domain_find_zone(db, zone->apex->parent); return NULL; } domain_type * domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns) { /* return highest NS RRset in the zone that is a delegation above */ domain_type* result = NULL; rrset_type* rrset = NULL; while (domain && domain != zone->apex) { rrset = domain_find_rrset(domain, zone, TYPE_NS); if (rrset) { *ns = rrset; result = domain; } domain = domain->parent; } if(result) return result; *ns = NULL; return NULL; } domain_type * find_dname_above(domain_type* domain, zone_type* zone) { domain_type* d = domain->parent; while(d && d != zone->apex) { if(domain_find_rrset(d, zone, TYPE_DNAME)) return d; d = d->parent; } return NULL; } int domain_is_glue(domain_type* domain, zone_type* zone) { rrset_type* unused; domain_type* ns_domain = domain_find_ns_rrsets(domain, zone, &unused); return (ns_domain != NULL && domain_find_rrset(ns_domain, zone, TYPE_SOA) == NULL); } domain_type * domain_wildcard_child(domain_type* domain) { domain_type* wildcard_child; assert(domain); assert(domain->wildcard_child_closest_match); wildcard_child = domain->wildcard_child_closest_match; if (wildcard_child != domain && label_is_wildcard(dname_name(domain_dname(wildcard_child)))) { return wildcard_child; } else { return NULL; } } int zone_is_secure(zone_type* zone) { assert(zone); return zone->is_secure; } uint16_t rr_rrsig_type_covered(rr_type* rr) { assert(rr->type == TYPE_RRSIG); assert(rr->rdata_count > 0); assert(rdata_atom_size(rr->rdatas[0]) == sizeof(uint16_t)); return ntohs(* (uint16_t *) rdata_atom_data(rr->rdatas[0])); } zone_type * namedb_find_zone(namedb_type* db, const dname_type* dname) { struct radnode* n = radname_search(db->zonetree, dname_name(dname), dname->name_size); if(n) return (zone_type*)n->elem; return NULL; } rrset_type * domain_find_non_cname_rrset(domain_type* domain, zone_type* zone) { /* find any rrset type that is not allowed next to a CNAME */ /* nothing is allowed next to a CNAME, except RRSIG, NSEC, NSEC3 */ rrset_type *result = domain->rrsets; while (result) { if (result->zone == zone && /* here is the list of exceptions*/ rrset_rrtype(result) != TYPE_CNAME && rrset_rrtype(result) != TYPE_RRSIG && rrset_rrtype(result) != TYPE_NXT && rrset_rrtype(result) != TYPE_SIG && rrset_rrtype(result) != TYPE_NSEC && rrset_rrtype(result) != TYPE_NSEC3 ) { return result; } result = result->next; } return NULL; } int namedb_lookup(struct namedb* db, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser) { return domain_table_search( db->domains, dname, closest_match, closest_encloser); } void zone_rr_iter_init(struct zone_rr_iter *iter, struct zone *zone) { assert(iter != NULL); assert(zone != NULL); memset(iter, 0, sizeof(*iter)); iter->zone = zone; } rr_type *zone_rr_iter_next(struct zone_rr_iter *iter) { assert(iter != NULL); assert(iter->zone != NULL); if(iter->index == -1) { assert(iter->domain == NULL); assert(iter->rrset == NULL); return NULL; } else if(iter->rrset == NULL) { /* ensure SOA RR is returned first */ assert(iter->domain == NULL); assert(iter->index == 0); iter->rrset = iter->zone->soa_rrset; } while(iter->rrset != NULL) { if(iter->index < iter->rrset->rr_count) { return &iter->rrset->rrs[iter->index++]; } iter->index = 0; if(iter->domain == NULL) { assert(iter->rrset == iter->zone->soa_rrset); iter->domain = iter->zone->apex; iter->rrset = iter->domain->rrsets; } else { iter->rrset = iter->rrset->next; } /* ensure SOA RR is not returned again and RR belongs to zone */ while((iter->rrset == NULL && iter->domain != NULL) || (iter->rrset != NULL && (iter->rrset == iter->zone->soa_rrset || iter->rrset->zone != iter->zone))) { if(iter->rrset != NULL) { iter->rrset = iter->rrset->next; } else { iter->domain = domain_next(iter->domain); if(iter->domain != NULL && dname_is_subdomain(domain_dname(iter->domain), domain_dname(iter->zone->apex))) { iter->rrset = iter->domain->rrsets; } } } } assert(iter->rrset == NULL); assert(iter->domain == NULL); iter->index = -1; return NULL; } nsd-4.12.0/mkinstalldirs0000755000175000017500000000123715002373054014606 0ustar mozziemozzie#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id$ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here nsd-4.12.0/mini_event.h0000644000175000017500000001416315002373054014310 0ustar mozziemozzie/* * mini-event.h - micro implementation of libevent api, using select() only. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * This file implements part of the event(3) libevent api. * The back end is only select. Max number of fds is limited. * Max number of signals is limited, one handler per signal only. * And one handler per fd. * * Although limited to select() and a max (1024) open fds, it * is efficient: * o dispatch call caches fd_sets to use. * o handler calling takes time ~ to the number of fds. * o timeouts are stored in a redblack tree, sorted, so take log(n). * Timeouts are only accurate to the second (no subsecond accuracy). * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. */ #ifndef MINI_EVENT_H #define MINI_EVENT_H struct region; #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) #ifdef HAVE_SYS_SELECT_H /* for fd_set on OpenBSD */ #include #endif #ifndef HAVE_EVENT_BASE_FREE #define HAVE_EVENT_BASE_FREE #endif /** event timeout */ #define EV_TIMEOUT 0x01 /** event fd readable */ #define EV_READ 0x02 /** event fd writable */ #define EV_WRITE 0x04 /** event signal */ #define EV_SIGNAL 0x08 /** event must persist */ #define EV_PERSIST 0x10 /* needs our redblack tree */ #include "rbtree.h" /** max number of file descriptors to support */ #define MAX_FDS 1024 /** max number of signals to support */ #define MAX_SIG 32 /** event base */ struct event_base { /** sorted by timeout (absolute), ptr */ rbtree_type* times; /** array of 0 - maxfd of ptr to event for it */ struct event** fds; /** max fd in use */ int maxfd; /** capacity - size of the fds array */ int capfd; /* fdset for read write, for fds ready, and added */ fd_set /** fds for reading */ reads, /** fds for writing */ writes, /** fds determined ready for use */ ready, /** ready plus newly added events. */ content; /** array of 0 - maxsig of ptr to event for it */ struct event** signals; /** if we need to exit */ int need_to_exit; /** where to store time in seconds */ time_t* time_secs; /** where to store time in microseconds */ struct timeval* time_tv; /** region for allocation */ struct region* region; }; /** * Event structure. Has some of the event elements. */ struct event { /** node in timeout rbtree */ rbnode_type node; /** is event already added */ int added; /** event base it belongs to */ struct event_base *ev_base; /** fd to poll or -1 for timeouts. signal number for sigs. */ int ev_fd; /** what events this event is interested in, see EV_.. above. */ short ev_flags; /** timeout value */ struct timeval ev_timeout; /** callback to call: fd, eventbits, userarg */ void (*ev_callback)(int, short, void *arg); /** callback user arg */ void *ev_arg; }; /* function prototypes (some are as they appear in event.h) */ /** create event base */ void *event_init(time_t* time_secs, struct timeval* time_tv); /** get version */ const char *event_get_version(void); /** get polling method, select */ const char *event_get_method(void); /** run select in a loop */ int event_base_dispatch(struct event_base *); /** exit that loop */ int event_base_loopexit(struct event_base *, struct timeval *); /** exit loop */ int event_base_loopbreak(struct event_base *); /** run select once */ #define EVLOOP_ONCE 1 int event_base_loop(struct event_base* base, int flags); /** free event base. Free events yourself */ void event_base_free(struct event_base *); /** set content of event */ void event_set(struct event *, int, short, void (*)(int, short, void *), void *); /** add event to a base. You *must* call this for every event. */ int event_base_set(struct event_base *, struct event *); /** add event to make it active. You may not change it with event_set anymore */ int event_add(struct event *, struct timeval *); /** remove event. You may change it again */ int event_del(struct event *); /** add a timer */ #define evtimer_add(ev, tv) event_add(ev, tv) /** remove a timer */ #define evtimer_del(ev) event_del(ev) /* uses different implementation. Cannot mix fd/timeouts and signals inside * the same struct event. create several event structs for that. */ /** install signal handler */ int signal_add(struct event *, struct timeval *); /** set signal event contents */ #define signal_set(ev, x, cb, arg) \ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) /** remove signal handler */ int signal_del(struct event *); #endif /* USE_MINI_EVENT and not USE_WINSOCK */ /** compare events in tree, based on timevalue, ptr for uniqueness */ int mini_ev_cmp(const void* a, const void* b); #endif /* MINI_EVENT_H */ nsd-4.12.0/mini_event.c0000644000175000017500000002504015002373054014277 0ustar mozziemozzie/* * mini_event.c - implementation of part of libevent api, portably. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * fake libevent implementation. Less broad in functionality, and only * supports select(2). */ #include "config.h" #ifdef HAVE_TIME_H #include #endif #include #include #include #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) #ifdef HAVE_WINSOCK2_H #define FD_SET_T (u_int) #else #define FD_SET_T #endif #include #include "mini_event.h" #include "util.h" /** compare events in tree, based on timevalue, ptr for uniqueness */ int mini_ev_cmp(const void* a, const void* b) { const struct event* e = (const struct event*)a; const struct event* f = (const struct event*)b; if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) return -1; if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) return 1; if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) return -1; if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) return 1; if(e < f) return -1; if(e > f) return 1; return 0; } /** set time */ static int settime(struct event_base* base) { if(gettimeofday(base->time_tv, NULL) < 0) { return -1; } #ifndef S_SPLINT_S *base->time_secs = (time_t)base->time_tv->tv_sec; #endif return 0; } /** create event base */ void * event_init(time_t* time_secs, struct timeval* time_tv) { struct event_base* base = (struct event_base*)malloc( sizeof(struct event_base)); if(!base) return NULL; memset(base, 0, sizeof(*base)); base->region = region_create(xalloc, free); if(!base->region) { free(base); return NULL; } base->time_secs = time_secs; base->time_tv = time_tv; if(settime(base) < 0) { event_base_free(base); return NULL; } base->times = rbtree_create(base->region, mini_ev_cmp); if(!base->times) { event_base_free(base); return NULL; } base->capfd = MAX_FDS; #ifdef FD_SETSIZE if((int)FD_SETSIZE < base->capfd) base->capfd = (int)FD_SETSIZE; #endif base->fds = (struct event**)calloc((size_t)base->capfd, sizeof(struct event*)); if(!base->fds) { event_base_free(base); return NULL; } base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); if(!base->signals) { event_base_free(base); return NULL; } #ifndef S_SPLINT_S FD_ZERO(&base->reads); FD_ZERO(&base->writes); #endif return base; } /** get version */ const char * event_get_version(void) { return "mini-event-"PACKAGE_VERSION; } /** get polling method, select */ const char * event_get_method(void) { return "select"; } /** call timeouts handlers, and return how long to wait for next one or -1 */ static int handle_timeouts(struct event_base* base, struct timeval* now, struct timeval* wait) { struct event* p; int tofired = 0; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } return tofired; } #endif /* event times out, remove it */ tofired = 1; (void)rbtree_delete(base->times, p); p->ev_flags &= ~EV_TIMEOUT; (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } return tofired; } /** call select and callbacks for that */ static int handle_select(struct event_base* base, struct timeval* wait) { fd_set r, w; int ret, i; #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { ret = errno; if(settime(base) < 0) return -1; errno = ret; if(ret == EAGAIN || ret == EINTR) return 0; return -1; } if(settime(base) < 0) return -1; for(i=0; imaxfd+1; i++) { short bits = 0; if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { continue; } if(FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if(FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->fds[i]->ev_flags; if(bits) { (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, bits, base->fds[i]->ev_arg); if(ret==0) break; } } return 0; } /** run select once */ int event_base_loop(struct event_base* base, int flags) { struct timeval wait; if(!(flags & EVLOOP_ONCE)) return event_base_dispatch(base); /* see if timeouts need handling */ if(handle_timeouts(base, base->time_tv, &wait)) return 0; /* there were timeouts, end of loop */ if(base->need_to_exit) return 0; /* do select */ if(handle_select(base, &wait) < 0) { if(base->need_to_exit) return 0; return -1; } return 0; } /** run select in a loop */ int event_base_dispatch(struct event_base* base) { struct timeval wait; if(settime(base) < 0) return -1; while(!base->need_to_exit) { /* see if timeouts need handling */ (void)handle_timeouts(base, base->time_tv, &wait); if(base->need_to_exit) return 0; /* do select */ if(handle_select(base, &wait) < 0) { if(base->need_to_exit) return 0; return -1; } } return 0; } /** exit that loop */ int event_base_loopexit(struct event_base* base, struct timeval* ATTR_UNUSED(tv)) { base->need_to_exit = 1; return 0; } int event_base_loopbreak(struct event_base * base) { return event_base_loopexit(base, NULL); } /* free event base, free events yourself */ void event_base_free(struct event_base* base) { if(!base) return; /* base->times is allocated in region and is freed with the region */ if(base->fds) free(base->fds); if(base->signals) free(base->signals); region_destroy(base->region); free(base); } /** set content of event */ void event_set(struct event* ev, int fd, short bits, void (*cb)(int, short, void *), void* arg) { ev->node.key = ev; ev->ev_fd = fd; ev->ev_flags = bits; ev->ev_callback = cb; ev->ev_arg = arg; ev->added = 0; } /* add event to a base */ int event_base_set(struct event_base* base, struct event* ev) { ev->ev_base = base; ev->added = 0; return 0; } /* add event to make it active, you may not change it with event_set anymore */ int event_add(struct event* ev, struct timeval* tv) { if(ev->added) event_del(ev); if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) return -1; if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { ev->ev_base->fds[ev->ev_fd] = ev; if(ev->ev_flags&EV_READ) { FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); } if(ev->ev_flags&EV_WRITE) { FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); } FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); if(ev->ev_fd > ev->ev_base->maxfd) ev->ev_base->maxfd = ev->ev_fd; } if(tv && (ev->ev_flags&EV_TIMEOUT)) { #ifndef S_SPLINT_S struct timeval* now = ev->ev_base->time_tv; ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; while(ev->ev_timeout.tv_usec >= 1000000) { ev->ev_timeout.tv_usec -= 1000000; ev->ev_timeout.tv_sec++; } #endif (void)rbtree_insert(ev->ev_base->times, &ev->node); } ev->added = 1; return 0; } /* remove event, you may change it again */ int event_del(struct event* ev) { if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) return -1; if((ev->ev_flags&EV_TIMEOUT)) (void)rbtree_delete(ev->ev_base->times, &ev->node); if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { ev->ev_base->fds[ev->ev_fd] = NULL; FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); } ev->added = 0; return 0; } /** which base gets to handle signals */ static struct event_base* signal_base = NULL; /** signal handler */ static RETSIGTYPE sigh(int sig) { struct event* ev; if(!signal_base || sig < 0 || sig >= MAX_SIG) return; ev = signal_base->signals[sig]; if(!ev) return; (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); } /** install signal handler */ int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) { struct sigaction action; if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) return -1; signal_base = ev->ev_base; ev->ev_base->signals[ev->ev_fd] = ev; ev->added = 1; action.sa_handler = sigh; sigfillset(&action.sa_mask); action.sa_flags = 0; return sigaction(ev->ev_fd, &action, NULL); } /** remove signal handler */ int signal_del(struct event* ev) { if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) return -1; ev->ev_base->signals[ev->ev_fd] = NULL; ev->added = 0; return 0; } #else /* USE_MINI_EVENT */ #ifndef USE_WINSOCK int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) { return 0; } #endif /* not USE_WINSOCK */ #endif /* USE_MINI_EVENT */ nsd-4.12.0/metrics.h0000644000175000017500000000477715002373054013633 0ustar mozziemozzie/* * metrics.h -- prometheus metrics endpoint * * Copyright (c) 2001-2025, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DAEMON_METRICS_H #define DAEMON_METRICS_H struct xfrd_state; struct nsd_options; struct daemon_metrics; struct evbuffer; #ifdef BIND8_STATS struct nsdst; #endif /* BIND8_STATS */ /* the metrics daemon needs little backlog */ #define TCP_BACKLOG_METRICS 16 /* listen() tcp backlog */ /** * Create new metrics endpoint for the daemon. * @param cfg: config. * @return new state, or NULL on failure. */ struct daemon_metrics* daemon_metrics_create(struct nsd_options* cfg); /** * Delete metrics daemon and close HTTP listeners. * @param m: daemon to delete. */ void daemon_metrics_delete(struct daemon_metrics* m); /** * Close metrics HTTP listener ports. * Does not delete the object itself. * @param m: state to close. */ void daemon_metrics_close(struct daemon_metrics* m); /** * Open and create HTTP listeners for metrics daemon. * @param m: metrics state that contains list of accept sockets. * @param cfg: config options. * @return false on failure. */ int daemon_metrics_open_ports(struct daemon_metrics* m, struct nsd_options* cfg); /** * Setup HTTP listener. * @param m: state * @param xfrd: the process that hosts the daemon. * m's HTTP listener is attached to its event base. */ void daemon_metrics_attach(struct daemon_metrics* m, struct xfrd_state* xfrd); #ifdef BIND8_STATS /** * Print stats as prometheus metrics to HTTP buffer * @param buf: the HTTP buffer to write to * @param xfrd: the process that hosts the daemon. * @param now: current time * @param clear: whether to reset the stats time * @param st: the stats * @param zonestats: the zonestats * @param rc_stats_time: pointer to the remote-control stats_time member * to correctly print the elapsed time since last stats reset */ void metrics_print_stats(struct evbuffer *buf, struct xfrd_state *xfrd, struct timeval *now, int clear, struct nsdst *st, struct nsdst **zonestats, struct timeval *rc_stats_time); #ifdef USE_ZONE_STATS /** * Print zonestat metrics for a single zonestats object * @param buf: the HTTP buffer to write to * @param name: the zonestats name * @param zst: the stats to print */ void metrics_zonestat_print_one(struct evbuffer *buf, char *name, struct nsdst *zst); #endif /* USE_ZONE_STATS */ #endif /*BIND8_STATS*/ #endif /* DAEMON_METRICS_H */ nsd-4.12.0/metrics.c0000644000175000017500000004630715002373054013621 0ustar mozziemozzie/* * metrics.c -- prometheus metrics endpoint * * Copyright (c) 2001-2025, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #ifdef USE_METRICS #include #include #include #include #include #include #include #include "nsd.h" #include "xfrd.h" #include "options.h" #include "remote.h" #include "metrics.h" /** if you want zero to be inhibited in stats output. * it omits zeroes for types that have no acronym and unused-rcodes */ const int metrics_inhibit_zero = 1; /** * list of connection accepting file descriptors */ struct metrics_acceptlist { struct metrics_acceptlist* next; int accept_fd; char* ident; struct daemon_metrics* metrics; }; /** * The metrics daemon state. */ struct daemon_metrics { /** the master process for this metrics daemon */ struct xfrd_state* xfrd; /** commpoints for accepting HTTP connections */ struct metrics_acceptlist* accept_list; /** last time stats was reported */ struct timeval stats_time, boot_time; /** libevent http server */ struct evhttp *http_server; }; static void metrics_http_callback(struct evhttp_request *req, void *p); struct daemon_metrics* daemon_metrics_create(struct nsd_options* cfg) { struct daemon_metrics* metrics = (struct daemon_metrics*)xalloc_zero( sizeof(*metrics)); assert(cfg->metrics_enable); /* and try to open the ports */ if(!daemon_metrics_open_ports(metrics, cfg)) { log_msg(LOG_ERR, "could not open metrics port"); daemon_metrics_delete(metrics); return NULL; } if(gettimeofday(&metrics->boot_time, NULL) == -1) log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); metrics->stats_time = metrics->boot_time; return metrics; } void daemon_metrics_close(struct daemon_metrics* metrics) { struct metrics_acceptlist *h, *nh; if(!metrics) return; /* close listen sockets */ h = metrics->accept_list; while(h) { nh = h->next; close(h->accept_fd); free(h->ident); free(h); h = nh; } metrics->accept_list = NULL; if (metrics->http_server) { evhttp_free(metrics->http_server); } } void daemon_metrics_delete(struct daemon_metrics* metrics) { if(!metrics) return; daemon_metrics_close(metrics); free(metrics); } static int create_tcp_accept_sock(struct addrinfo* addr, int* noproto) { #if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU))) int on = 1; #endif int s; *noproto = 0; if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) { *noproto = 1; log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); return -1; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } #ifdef SO_REUSEADDR if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); } #endif /* SO_REUSEADDR */ #if defined(INET6) && defined(IPV6_V6ONLY) if (addr->ai_family == AF_INET6 && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); close(s); return -1; } #endif /* set it nonblocking */ /* (StevensUNP p463), if tcp listening socket is blocking, then it may block in accept, even if select() says readable. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno)); } /* Bind it... */ if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); close(s); return -1; } /* Listen to it... */ if (listen(s, TCP_BACKLOG_METRICS) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); close(s); return -1; } return s; } /** * Add and open a new metrics port * @param metrics: metrics with result list. * @param ip: ip str * @param nr: port nr * @param noproto_is_err: if lack of protocol support is an error. * @return false on failure. */ static int metrics_add_open(struct daemon_metrics* metrics, struct nsd_options* cfg, const char* ip, int nr, int noproto_is_err) { struct addrinfo hints; struct addrinfo* res; struct metrics_acceptlist* hl; int noproto = 0; int fd, r; char port[15]; snprintf(port, sizeof(port), "%d", nr); port[sizeof(port)-1]=0; memset(&hints, 0, sizeof(hints)); assert(ip); if(ip[0] == '/') { /* This looks like a local socket */ fd = create_local_accept_sock(ip, &noproto); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same * group as the user we run as. */ if(fd != -1) { #ifdef HAVE_CHOWN if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) { VERBOSITY(3, (LOG_INFO, "cannot chmod metrics socket %s: %s", ip, strerror(errno))); } if (cfg->username && cfg->username[0] && nsd.uid != (uid_t)-1) { if(chown(ip, nsd.uid, nsd.gid) == -1) VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s", (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror(errno))); } #else (void)cfg; #endif } } else { hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; /* if we had no interface ip name, "default" is what we * would do getaddrinfo for. */ if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { log_msg(LOG_ERR, "metrics interface %s:%s getaddrinfo: %s %s", ip, port, gai_strerror(r), #ifdef EAI_SYSTEM r==EAI_SYSTEM?(char*)strerror(errno):"" #else "" #endif ); return 0; } /* open fd */ fd = create_tcp_accept_sock(res, &noproto); freeaddrinfo(res); } if(fd == -1 && noproto) { if(!noproto_is_err) return 1; /* return success, but do nothing */ log_msg(LOG_ERR, "cannot open metrics interface %s %d : " "protocol not supported", ip, nr); return 0; } if(fd == -1) { log_msg(LOG_ERR, "cannot open metrics interface %s %d", ip, nr); return 0; } /* alloc */ hl = (struct metrics_acceptlist*)xalloc_zero(sizeof(*hl)); hl->metrics = metrics; hl->ident = strdup(ip); if(!hl->ident) { log_msg(LOG_ERR, "malloc failure"); close(fd); free(hl); return 0; } hl->next = metrics->accept_list; metrics->accept_list = hl; hl->accept_fd = fd; return 1; } int daemon_metrics_open_ports(struct daemon_metrics* metrics, struct nsd_options* cfg) { assert(cfg->metrics_enable && cfg->metrics_port); if(cfg->metrics_interface) { ip_address_option_type* p; for(p = cfg->metrics_interface; p; p = p->next) { if(!metrics_add_open(metrics, cfg, p->address, cfg->metrics_port, 1)) { return 0; } } } else { /* defaults */ if(cfg->do_ip6 && !metrics_add_open(metrics, cfg, "::1", cfg->metrics_port, 0)) { return 0; } if(cfg->do_ip4 && !metrics_add_open(metrics, cfg, "127.0.0.1", cfg->metrics_port, 1)) { return 0; } } return 1; } void daemon_metrics_attach(struct daemon_metrics* metrics, struct xfrd_state* xfrd) { int fd; struct metrics_acceptlist* p; if(!metrics) return; metrics->xfrd = xfrd; metrics->http_server = evhttp_new(xfrd->event_base); for(p = metrics->accept_list; p; p = p->next) { fd = p->accept_fd; if (evhttp_accept_socket(metrics->http_server, fd)) { log_msg(LOG_ERR, "metrics: cannot set http server to accept socket"); } /* only handle requests to metrics_path, anything else returns 404 */ evhttp_set_cb(metrics->http_server, metrics->xfrd->nsd->options->metrics_path, metrics_http_callback, p); /* evhttp_set_gencb(metrics->http_server, metrics_http_callback_generic, p); */ } } /* Callback for handling the active http request to the specific URI */ static void metrics_http_callback(struct evhttp_request *req, void *p) { struct evbuffer *reply = NULL; struct daemon_metrics *metrics = ((struct metrics_acceptlist *)p)->metrics; /* currently only GET requests are supported/allowed */ enum evhttp_cmd_type cmd = evhttp_request_get_command(req); if (cmd != EVHTTP_REQ_GET /* && cmd != EVHTTP_REQ_HEAD */) { evhttp_send_error(req, HTTP_BADMETHOD, 0); return; } reply = evbuffer_new(); if (!reply) { evhttp_send_error(req, HTTP_INTERNAL, 0); log_msg(LOG_ERR, "failed to allocate reply buffer\n"); return; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain; version=0.0.4"); #ifdef BIND8_STATS process_stats(NULL, reply, metrics->xfrd, 1); evhttp_send_reply(req, HTTP_OK, NULL, reply); VERBOSITY(3, (LOG_INFO, "metrics operation completed, response sent")); #else evhttp_send_reply(req, HTTP_NOCONTENT, "No Content - Statistics disabled", reply); log_msg(LOG_NOTICE, "metrics requested, but no stats enabled at compile time\n"); (void)metrics; #endif /* BIND8_STATS */ evbuffer_free(reply); } #ifdef BIND8_STATS /** print long number*/ static int print_longnum(struct evbuffer *buf, char* desc, uint64_t x) { if(x > (uint64_t)1024*1024*1024) { /*more than a Gb*/ size_t front = (size_t)(x / (uint64_t)1000000); size_t back = (size_t)(x % (uint64_t)1000000); return evbuffer_add_printf(buf, "%s%lu%6.6lu\n", desc, (unsigned long)front, (unsigned long)back); } else { return evbuffer_add_printf(buf, "%s%lu\n", desc, (unsigned long)x); } } static void print_metric_help_and_type(struct evbuffer *buf, char *prefix, char *name, char *help, char *type) { evbuffer_add_printf(buf, "# HELP %s%s %s\n# TYPE %s%s %s\n", prefix, name, help, prefix, name, type); } static void print_stat_block(struct evbuffer *buf, struct nsdst* st, char *name) { size_t i; const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", "BADVERS" }; char prefix[512] = {0}; if (name) { snprintf(prefix, sizeof(prefix), "nsd_zonestats_%s_", name); } else { sprintf(prefix, "nsd_"); } /* nsd_queries_by_type_total */ print_metric_help_and_type(buf, prefix, "queries_by_type_total", "Total number of queries recieved by type.", "counter"); for(i=0; i<= 255; i++) { if(metrics_inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; evbuffer_add_printf(buf, "%squeries_by_type_total{type=\"%s\"} %lu\n", prefix, rrtype_to_string(i), (unsigned long)st->qtype[i]); } /* nsd_queries_by_class_total */ print_metric_help_and_type(buf, prefix, "queries_by_class_total", "Total number of queries recieved by class.", "counter"); for(i=0; i<4; i++) { if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; evbuffer_add_printf(buf, "%squeries_by_class_total{class=\"%s\"} %lu\n", prefix, rrclass_to_string(i), (unsigned long)st->qclass[i]); } /* nsd_queries_by_opcode_total */ print_metric_help_and_type(buf, prefix, "queries_by_opcode_total", "Total number of queries recieved by opcode.", "counter"); for(i=0; i<6; i++) { if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) continue; evbuffer_add_printf(buf, "%squeries_by_opcode_total{opcode=\"%s\"} %lu\n", prefix, opcode2str(i), (unsigned long)st->opcode[i]); } /* nsd_queries_by_rcode_total */ print_metric_help_and_type(buf, prefix, "queries_by_rcode_total", "Total number of queries recieved by rcode.", "counter"); for(i=0; i<17; i++) { if(metrics_inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /*NSD does not use larger*/ continue; evbuffer_add_printf(buf, "%squeries_by_rcode_total{rcode=\"%s\"} %lu\n", prefix, rcstr[i], (unsigned long)st->rcode[i]); } /* nsd_queries_by_transport_total */ print_metric_help_and_type(buf, prefix, "queries_by_transport_total", "Total number of queries recieved by transport.", "counter"); evbuffer_add_printf(buf, "%squeries_by_transport_total{transport=\"udp\"} %lu\n", prefix, (unsigned long)st->qudp); evbuffer_add_printf(buf, "%squeries_by_transport_total{transport=\"udp6\"} %lu\n", prefix, (unsigned long)st->qudp6); /* nsd_queries_with_edns_total */ print_metric_help_and_type(buf, prefix, "queries_with_edns_total", "Total number of queries recieved with EDNS OPT.", "counter"); evbuffer_add_printf(buf, "%squeries_with_edns_total %lu\n", prefix, (unsigned long)st->edns); /* nsd_queries_with_edns_failed_total */ print_metric_help_and_type(buf, prefix, "queries_with_edns_failed_total", "Total number of queries recieved with EDNS OPT where EDNS parsing failed.", "counter"); evbuffer_add_printf(buf, "%squeries_with_edns_failed_total %lu\n", prefix, (unsigned long)st->ednserr); /* nsd_connections_total */ print_metric_help_and_type(buf, prefix, "connections_total", "Total number of connections.", "counter"); evbuffer_add_printf(buf, "%sconnections_total{transport=\"tcp\"} %lu\n", prefix, (unsigned long)st->ctcp); evbuffer_add_printf(buf, "%sconnections_total{transport=\"tcp6\"} %lu\n", prefix, (unsigned long)st->ctcp6); evbuffer_add_printf(buf, "%sconnections_total{transport=\"tls\"} %lu\n", prefix, (unsigned long)st->ctls); evbuffer_add_printf(buf, "%sconnections_total{transport=\"tls6\"} %lu\n", prefix, (unsigned long)st->ctls6); /* nsd_xfr_requests_served_total */ print_metric_help_and_type(buf, prefix, "xfr_requests_served_total", "Total number of answered zone transfers.", "counter"); evbuffer_add_printf(buf, "%sxfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", prefix, (unsigned long)st->raxfr); evbuffer_add_printf(buf, "%sxfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", prefix, (unsigned long)st->rixfr); /* nsd_queries_dropped_total */ print_metric_help_and_type(buf, prefix, "queries_dropped_total", "Total number of dropped queries.", "counter"); evbuffer_add_printf(buf, "%squeries_dropped_total %lu\n", prefix, (unsigned long)st->dropped); /* nsd_queries_rx_failed_total */ print_metric_help_and_type(buf, prefix, "queries_rx_failed_total", "Total number of queries where receive failed.", "counter"); evbuffer_add_printf(buf, "%squeries_rx_failed_total %lu\n", prefix, (unsigned long)st->rxerr); /* nsd_answers_tx_failed_total */ print_metric_help_and_type(buf, prefix, "answers_tx_failed_total", "Total number of answers where transmit failed.", "counter"); evbuffer_add_printf(buf, "%sanswers_tx_failed_total %lu\n", prefix, (unsigned long)st->txerr); /* nsd_answers_without_aa_total */ print_metric_help_and_type(buf, prefix, "answers_without_aa_total", "Total number of NOERROR answers without AA flag set.", "counter"); evbuffer_add_printf(buf, "%sanswers_without_aa_total %lu\n", prefix, (unsigned long)st->nona); /* nsd_answers_truncated_total */ print_metric_help_and_type(buf, prefix, "answers_truncated_total", "Total number of truncated answers.", "counter"); evbuffer_add_printf(buf, "%sanswers_truncated_total %lu\n", prefix, (unsigned long)st->truncated); } #ifdef USE_ZONE_STATS void metrics_zonestat_print_one(struct evbuffer *buf, char *name, struct nsdst *zst) { char prefix[512] = {0}; snprintf(prefix, sizeof(prefix), "nsd_zonestats_%s_", name); print_metric_help_and_type(buf, prefix, "queries_total", "Total number of queries recieved.", "counter"); evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_total %lu\n", name, (unsigned long)(zst->qudp + zst->qudp6 + zst->ctcp + zst->ctcp6 + zst->ctls + zst->ctls6)); print_stat_block(buf, zst, name); } #endif /*USE_ZONE_STATS*/ void metrics_print_stats(struct evbuffer *buf, xfrd_state_type *xfrd, struct timeval *now, int clear, struct nsdst *st, struct nsdst **zonestats, struct timeval *rc_stats_time) { size_t i; struct timeval elapsed, uptime; /* nsd_queries_total */ print_metric_help_and_type(buf, "nsd_", "queries_total", "Total number of queries recieved.", "counter"); /*per CPU and total*/ for(i=0; insd->child_count; i++) { evbuffer_add_printf(buf, "nsd_queries_total{server=\"%d\"} %lu\n", (int)i, (unsigned long)xfrd->nsd->children[i].query_count); } print_stat_block(buf, st, NULL); /* uptime (in seconds) */ timeval_subtract(&uptime, now, &xfrd->nsd->metrics->boot_time); print_metric_help_and_type(buf, "nsd_", "time_up_seconds_total", "Uptime since server boot in seconds.", "counter"); evbuffer_add_printf(buf, "nsd_time_up_seconds_total %lu.%6.6lu\n", (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec); /* time elapsed since last nsd-control stats reset (in seconds) */ /* if remote-control is disabled aka rc_stats_time == NULL * use metrics' stats_time */ if (rc_stats_time) { timeval_subtract(&elapsed, now, rc_stats_time); } else { timeval_subtract(&elapsed, now, &xfrd->nsd->metrics->stats_time); } print_metric_help_and_type(buf, "nsd_", "time_elapsed_seconds", "Time since last statistics printout and " "reset (by nsd-control stats) in seconds.", "untyped"); evbuffer_add_printf(buf, "nsd_time_elapsed_seconds %lu.%6.6lu\n", (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec); /*mem info, database on disksize*/ print_metric_help_and_type(buf, "nsd_", "size_db_on_disk_bytes", "Size of DNS database on disk.", "gauge"); print_longnum(buf, "nsd_size_db_on_disk_bytes ", st->db_disk); print_metric_help_and_type(buf, "nsd_", "size_db_in_mem_bytes", "Size of DNS database in memory.", "gauge"); print_longnum(buf, "nsd_size_db_in_mem_bytes ", st->db_mem); print_metric_help_and_type(buf, "nsd_", "size_xfrd_in_mem_bytes", "Size of zone transfers and notifies in xfrd process, excluding TSIG data.", "gauge"); print_longnum(buf, "nsd_size_xfrd_in_mem_bytes ", region_get_mem(xfrd->region)); print_metric_help_and_type(buf, "nsd_", "size_config_on_disk_bytes", "Size of zonelist file on disk, excluding nsd.conf.", "gauge"); print_longnum(buf, "nsd_size_config_on_disk_bytes ", xfrd->nsd->options->zonelist_off); print_metric_help_and_type(buf, "nsd_", "size_config_in_mem_bytes", "Size of config data in memory.", "gauge"); print_longnum(buf, "nsd_size_config_in_mem_bytes ", region_get_mem( xfrd->nsd->options->region)); /* number of zones serverd */ print_metric_help_and_type(buf, "nsd_", "zones_primary", "Number of primary zones served.", "gauge"); evbuffer_add_printf(buf, "nsd_zones_primary %lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)); print_metric_help_and_type(buf, "nsd_", "zones_secondary", "Number of secondary zones served.", "gauge"); evbuffer_add_printf(buf, "nsd_zones_secondary %lu\n", (unsigned long)xfrd->zones->count); #ifdef USE_ZONE_STATS zonestat_print(NULL, buf, xfrd, clear, zonestats); /*per-zone statistics*/ #else (void)clear; (void)zonestats; #endif } #endif /*BIND8_STATS*/ #endif /* USE_METRICS */ nsd-4.12.0/lookup3.h0000644000175000017500000000517715002373054013554 0ustar mozziemozzie/* * util/storage/lookup3.h - header file for hashing functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains header definitions for the hash functions we use. * The hash functions are public domain (see lookup3.c). */ #ifndef UTIL_STORAGE_LOOKUP3_H #define UTIL_STORAGE_LOOKUP3_H /** * Hash key made of 4byte chunks. * @param k: the key, an array of uint32_t values * @param length: the length of the key, in uint32_ts * @param initval: the previous hash, or an arbitrary value * @return: hash value. */ uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval); /** * Hash key data. * @param k: the key, array of uint8_t * @param length: the length of the key, in uint8_ts * @param initval: the previous hash, or an arbitrary value * @return: hash value. */ uint32_t hashlittle(const void *k, size_t length, uint32_t initval); /** * Set the randomisation initial value, set this before threads start, * and before hashing stuff (because it changes subsequent results). * @param v: value */ void hash_set_raninit(uint32_t v); #endif /* UTIL_STORAGE_LOOKUP3_H */ nsd-4.12.0/lookup3.c0000644000175000017500000010704015002373054013537 0ustar mozziemozzie/* February 2013(Wouter) patch defines for BSD endianness, from Brad Smith. January 2012(Wouter) added randomised initial value, fallout from 28c3. March 2007(Wouter) adapted from lookup3.c original, add config.h include. added #ifdef VALGRIND to remove 298,384,660 'unused variable k8' warnings. added include of lookup3.h to check definitions match declarations. removed include of stdint - config.h takes care of platform independence. added fallthrough comments for new gcc warning suppression. url http://burtleburtle.net/bob/hash/index.html. */ /* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hashword(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. ------------------------------------------------------------------------------- */ /*#define SELF_TEST 1*/ #include "config.h" #include "lookup3.h" #include /* defines printf for tests */ #include /* defines time_t for timings in the test */ /*#include defines uint32_t etc (from config.h) */ #include /* attempt to define endianness */ #ifdef HAVE_SYS_TYPES_H # include /* attempt to define endianness (solaris) */ #endif #if defined(linux) || defined(__OpenBSD__) # ifdef HAVE_ENDIAN_H # include /* attempt to define endianness */ # else # include /* on older OpenBSD */ # endif #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include /* attempt to define endianness */ #endif /* random initial value */ static uint32_t raninit = 0xdeadbeef; void hash_set_raninit(uint32_t v) { raninit = v; } /* * My best guess at if you are big-endian or little-endian. This may * need adjustment. */ #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ __BYTE_ORDER == __LITTLE_ENDIAN) || \ (defined(i386) || defined(__i386__) || defined(__i486__) || \ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86)) # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 #elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ __BYTE_ORDER == __BIG_ENDIAN) || \ (defined(sparc) || defined(__sparc) || defined(__sparc__) || defined(POWERPC) || defined(mc68000) || defined(sel)) # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 #elif defined(_MACHINE_ENDIAN_H_) /* test for machine_endian_h protects failure if some are empty strings */ # if defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 # endif # if defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 # endif /* _MACHINE_ENDIAN_H_ */ #else # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 0 #endif #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) /* ------------------------------------------------------------------------------- mix -- mix 3 32-bit values reversibly. This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix(). If four pairs of (a,b,c) inputs are run through mix(), or through mix() in reverse, there are at least 32 bits of the output that are sometimes the same for one pair and different for another pair. This was tested for: * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this are 4 6 8 16 19 4 9 15 3 18 27 15 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) that fail to affect some output bits of (a,b,c), especially of a. The most thoroughly mixed value is c, but it doesn't really even achieve avalanche in c. This allows some parallelism. Read-after-writes are good at doubling the number of bits affected, so the goal of mixing pulls in the opposite direction as the goal of parallelism. I did what I could. Rotates seem to cost as much as shifts on every machine I could lay my hands on, and rotates are much kinder to the top and bottom bits, so I used rotates. ------------------------------------------------------------------------------- */ #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } /* ------------------------------------------------------------------------------- final -- final mixing of 3 32-bit values (a,b,c) into c Pairs of (a,b,c) values differing in only a few bits will usually produce values of c that look totally different. This was tested for * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: 14 11 25 16 4 14 24 12 14 25 16 4 14 24 and these came close: 4 8 15 26 3 22 24 10 8 15 26 3 22 24 11 8 15 26 3 22 24 ------------------------------------------------------------------------------- */ #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c,4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } /* -------------------------------------------------------------------- This works on all machines. To be useful, it requires -- that the key be an array of uint32_t's, and -- that the length be the number of uint32_t's in the key The function hashword() is identical to hashlittle() on little-endian machines, and identical to hashbig() on big-endian machines, except that the length has to be measured in uint32_ts rather than in bytes. hashlittle() is more complicated than hashword() only because hashlittle() has to dance around fitting the key bytes into registers. -------------------------------------------------------------------- */ uint32_t hashword( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t initval) /* the previous hash, or an arbitrary value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = raninit + (((uint32_t)length)<<2) + initval; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; /* fallthrough */ case 2 : b+=k[1]; /* fallthrough */ case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ return c; } #ifdef SELF_TEST /* -------------------------------------------------------------------- hashword2() -- same as hashword(), but take two seeds and return two 32-bit values. pc and pb must both be nonnull, and *pc and *pb must both be initialized with seeds. If you pass in (*pb)==0, the output (*pc) will be the same as the return value from hashword(). -------------------------------------------------------------------- */ void hashword2 ( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t *pc, /* IN: seed OUT: primary hash value */ uint32_t *pb) /* IN: more seed OUT: secondary hash value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = raninit + ((uint32_t)(length<<2)) + *pc; c += *pb; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ *pc=c; *pb=b; } #endif /* SELF_TEST */ /* ------------------------------------------------------------------------------- hashlittle() -- hash a variable-length key into a 32-bit value k : the key (the unaligned variable-length array of bytes) length : the length of the key, counting by bytes initval : can be any 4-byte value Returns a 32-bit value. Every bit of the key affects every bit of the return value. Two keys differing by one or two bits will have totally different hash values. The best hash table sizes are powers of 2. There is no need to do mod a prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. For example, if you need only 10 bits, do h = (h & hashmask(10)); In which case, the hash table should have hashsize(10) elements. If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0; i 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return c; } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return c; /* zero length requires no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; /* fallthrough */ case 11: c+=((uint32_t)k[10])<<16; /* fallthrough */ case 10: c+=((uint32_t)k[9])<<8; /* fallthrough */ case 9 : c+=k[8]; /* fallthrough */ case 8 : b+=((uint32_t)k[7])<<24; /* fallthrough */ case 7 : b+=((uint32_t)k[6])<<16; /* fallthrough */ case 6 : b+=((uint32_t)k[5])<<8; /* fallthrough */ case 5 : b+=k[4]; /* fallthrough */ case 4 : a+=((uint32_t)k[3])<<24; /* fallthrough */ case 3 : a+=((uint32_t)k[2])<<16; /* fallthrough */ case 2 : a+=((uint32_t)k[1])<<8; /* fallthrough */ case 1 : a+=k[0]; break; case 0 : return c; } } final(a,b,c); return c; } #ifdef SELF_TEST /* * hashlittle2: return 2 32-bit hash values * * This is identical to hashlittle(), except it returns two 32-bit hash * values instead of just one. This is good enough for hash table * lookup with 2^^64 buckets, or if you want a second hash if you're not * happy with the first, or if you want a probably-unique 64-bit ID for * the key. *pc is better mixed than *pb, so use *pc first. If you want * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". */ void hashlittle2( const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ { uint32_t a,b,c; /* internal state */ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ /* Set up the internal state */ a = b = c = raninit + ((uint32_t)length) + *pc; c += *pb; u.ptr = key; if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ #ifdef VALGRIND const uint8_t *k8; #endif /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; case 11: c+=((uint32_t)k[10])<<16; case 10: c+=((uint32_t)k[9])<<8; case 9 : c+=k[8]; case 8 : b+=((uint32_t)k[7])<<24; case 7 : b+=((uint32_t)k[6])<<16; case 6 : b+=((uint32_t)k[5])<<8; case 5 : b+=k[4]; case 4 : a+=((uint32_t)k[3])<<24; case 3 : a+=((uint32_t)k[2])<<16; case 2 : a+=((uint32_t)k[1])<<8; case 1 : a+=k[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } final(a,b,c); *pc=c; *pb=b; } #endif /* SELF_TEST */ #if 0 /* currently not used */ /* * hashbig(): * This is the same as hashword() on big-endian machines. It is different * from hashlittle() on all machines. hashbig() takes advantage of * big-endian byte ordering. */ uint32_t hashbig( const void *key, size_t length, uint32_t initval) { uint32_t a,b,c; union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ /* Set up the internal state */ a = b = c = raninit + ((uint32_t)length) + initval; u.ptr = key; if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ #ifdef VALGRIND const uint8_t *k8; #endif /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]<<8" actually reads beyond the end of the string, but * then shifts out the part it's not allowed to read. Because the * string is aligned, the illegal read is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; case 5 : b+=k[1]&0xff000000; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff00; break; case 2 : a+=k[0]&0xffff0000; break; case 1 : a+=k[0]&0xff000000; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) /* all the case statements fall through */ { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ case 1 : a+=((uint32_t)k8[0])<<24; break; case 0 : return c; } #endif /* !VALGRIND */ } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += ((uint32_t)k[0])<<24; a += ((uint32_t)k[1])<<16; a += ((uint32_t)k[2])<<8; a += ((uint32_t)k[3]); b += ((uint32_t)k[4])<<24; b += ((uint32_t)k[5])<<16; b += ((uint32_t)k[6])<<8; b += ((uint32_t)k[7]); c += ((uint32_t)k[8])<<24; c += ((uint32_t)k[9])<<16; c += ((uint32_t)k[10])<<8; c += ((uint32_t)k[11]); mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=k[11]; case 11: c+=((uint32_t)k[10])<<8; case 10: c+=((uint32_t)k[9])<<16; case 9 : c+=((uint32_t)k[8])<<24; case 8 : b+=k[7]; case 7 : b+=((uint32_t)k[6])<<8; case 6 : b+=((uint32_t)k[5])<<16; case 5 : b+=((uint32_t)k[4])<<24; case 4 : a+=k[3]; case 3 : a+=((uint32_t)k[2])<<8; case 2 : a+=((uint32_t)k[1])<<16; case 1 : a+=((uint32_t)k[0])<<24; break; case 0 : return c; } } final(a,b,c); return c; } #endif /* 0 == currently not used */ #ifdef SELF_TEST /* used for timings */ void driver1() { uint8_t buf[256]; uint32_t i; uint32_t h=0; time_t a,z; time(&a); for (i=0; i<256; ++i) buf[i] = 'x'; for (i=0; i<1; ++i) { h = hashlittle(&buf[0],1,h); } time(&z); if (z-a > 0) printf("time %lld %.8x\n", (long long) z-a, h); } /* check that every input bit changes every output bit half the time */ #define HASHSTATE 1 #define HASHLEN 1 #define MAXPAIR 60 #define MAXLEN 70 void driver2() { uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; uint32_t x[HASHSTATE],y[HASHSTATE]; uint32_t hlen; printf("No more than %d trials should ever be needed \n",MAXPAIR/2); for (hlen=0; hlen < MAXLEN; ++hlen) { z=0; for (i=0; i>(8-j)); c[0] = hashlittle(a, hlen, m); b[i] ^= ((k+1)<>(8-j)); d[0] = hashlittle(b, hlen, m); /* check every bit is 1, 0, set, and not set at least once */ for (l=0; lz) z=k; if (k==MAXPAIR) { printf("Some bit didn't change: "); printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0],f[0],g[0],h[0],x[0],y[0]); printf("i %d j %d m %d len %d\n", i, j, m, hlen); } if (z==MAXPAIR) goto done; } } } done: if (z < MAXPAIR) { printf("Mix success %2d bytes %2d initvals ",i,m); printf("required %d trials\n", z/2); } } printf("\n"); } /* Check for reading beyond the end of the buffer and alignment problems */ void driver3() { uint8_t buf[MAXLEN+20], *b; uint32_t len; uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; uint32_t h; uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; uint32_t i; uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; uint32_t j; uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; uint32_t ref,x,y; uint8_t *p; printf("Endianness. These lines should all be the same (for values filled in):\n"); printf("%.8x %.8x %.8x\n", hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); p = q; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qq[1]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqq[2]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqqq[3]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); printf("\n"); /* check that hashlittle2 and hashlittle produce the same results */ i=47; j=0; hashlittle2(q, sizeof(q), &i, &j); if (hashlittle(q, sizeof(q), 47) != i) printf("hashlittle2 and hashlittle mismatch\n"); /* check that hashword2 and hashword produce the same results */ len = raninit; i=47, j=0; hashword2(&len, 1, &i, &j); if (hashword(&len, 1, 47) != i) printf("hashword2 and hashword mismatch %x %x\n", i, hashword(&len, 1, 47)); /* check hashlittle doesn't read before or after the ends of the string */ for (h=0, b=buf+1; h<8; ++h, ++b) { for (i=0; i #include #include #include "ixfrcreate.h" #include "namedb.h" #include "ixfr.h" #include "options.h" /* spool a uint16_t to file */ static int spool_u16(FILE* out, uint16_t val) { if(!fwrite(&val, sizeof(val), 1, out)) { return 0; } return 1; } /* spool a uint32_t to file */ static int spool_u32(FILE* out, uint32_t val) { if(!fwrite(&val, sizeof(val), 1, out)) { return 0; } return 1; } /* spool dname to file */ static int spool_dname(FILE* out, dname_type* dname) { uint16_t namelen = dname->name_size; if(!fwrite(&namelen, sizeof(namelen), 1, out)) { return 0; } if(!fwrite(dname_name(dname), namelen, 1, out)) { return 0; } return 1; } /* calculate the rdatalen of an RR */ static size_t rr_rdatalen_uncompressed(rr_type* rr) { int i; size_t rdlen_uncompressed = 0; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { rdlen_uncompressed += domain_dname(rr->rdatas[i].domain) ->name_size; } else { rdlen_uncompressed += rr->rdatas[i].data[0]; } } return rdlen_uncompressed; } /* spool the data for one rr into the file */ static int spool_rr_data(FILE* out, rr_type* rr) { int i; uint16_t rdlen; if(!spool_u32(out, rr->ttl)) return 0; rdlen = rr_rdatalen_uncompressed(rr); if(!spool_u16(out, rdlen)) return 0; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { if(!fwrite(dname_name(domain_dname( rr->rdatas[i].domain)), domain_dname( rr->rdatas[i].domain)->name_size, 1, out)) return 0; } else { if(!fwrite(&rr->rdatas[i].data[1], rr->rdatas[i].data[0], 1, out)) return 0; } } return 1; } /* spool one rrset to file */ static int spool_rrset(FILE* out, rrset_type* rrset) { int i; if(rrset->rr_count == 0) return 1; if(!spool_u16(out, rrset->rrs[0].type)) return 0; if(!spool_u16(out, rrset->rrs[0].klass)) return 0; if(!spool_u16(out, rrset->rr_count)) return 0; for(i=0; irr_count; i++) { if(!spool_rr_data(out, &rrset->rrs[i])) return 0; } return 1; } /* spool rrsets to file */ static int spool_rrsets(FILE* out, rrset_type* rrsets, struct zone* zone) { rrset_type* s; for(s=rrsets; s; s=s->next) { if(s->zone != zone) continue; if(!spool_rrset(out, s)) { return 0; } } return 1; } /* count number of rrsets for a domain */ static size_t domain_count_rrsets(domain_type* domain, zone_type* zone) { rrset_type* s; size_t count = 0; for(s=domain->rrsets; s; s=s->next) { if(s->zone == zone) count++; } return count; } /* spool the domain names to file, each one in turn. end with enddelimiter */ static int spool_domains(FILE* out, struct zone* zone) { domain_type* domain; for(domain = zone->apex; domain && domain_is_subdomain(domain, zone->apex); domain = domain_next(domain)) { uint32_t count = domain_count_rrsets(domain, zone); if(count == 0) continue; /* write the name */ if(!spool_dname(out, domain_dname(domain))) return 0; if(!spool_u32(out, count)) return 0; /* write the rrsets */ if(!spool_rrsets(out, domain->rrsets, zone)) return 0; } /* the end delimiter is a 0 length. domain names are not zero length */ if(!spool_u16(out, 0)) return 0; return 1; } /* spool the namedb zone to the file. print error on failure. */ static int spool_zone_to_file(struct zone* zone, char* file_name, uint32_t serial) { FILE* out; out = fopen(file_name, "w"); if(!out) { log_msg(LOG_ERR, "could not open %s for writing: %s", file_name, strerror(errno)); return 0; } if(!spool_dname(out, domain_dname(zone->apex))) { log_msg(LOG_ERR, "could not write %s: %s", file_name, strerror(errno)); fclose(out); return 0; } if(!spool_u32(out, serial)) { log_msg(LOG_ERR, "could not write %s: %s", file_name, strerror(errno)); fclose(out); return 0; } if(!spool_domains(out, zone)) { log_msg(LOG_ERR, "could not write %s: %s", file_name, strerror(errno)); fclose(out); return 0; } fclose(out); return 1; } /* create ixfr spool file name */ static int create_ixfr_spool_name(struct ixfr_create* ixfrcr, const char* zfile) { char buf[1024]; snprintf(buf, sizeof(buf), "%s.spoolzone.%u", zfile, (unsigned)getpid()); ixfrcr->file_name = strdup(buf); if(!ixfrcr->file_name) return 0; return 1; } /* start ixfr creation */ struct ixfr_create* ixfr_create_start(struct zone* zone, const char* zfile, uint64_t ixfr_size, int errorcmdline) { struct ixfr_create* ixfrcr = (struct ixfr_create*)calloc(1, sizeof(*ixfrcr)); if(!ixfrcr) { log_msg(LOG_ERR, "malloc failure"); return NULL; } ixfrcr->zone_name_len = domain_dname(zone->apex)->name_size; ixfrcr->zone_name = (uint8_t*)malloc(ixfrcr->zone_name_len); if(!ixfrcr->zone_name) { free(ixfrcr); log_msg(LOG_ERR, "malloc failure"); return NULL; } memmove(ixfrcr->zone_name, dname_name(domain_dname(zone->apex)), ixfrcr->zone_name_len); if(!create_ixfr_spool_name(ixfrcr, zfile)) { ixfr_create_free(ixfrcr); log_msg(LOG_ERR, "malloc failure"); return NULL; } ixfrcr->old_serial = zone_get_current_serial(zone); if(!spool_zone_to_file(zone, ixfrcr->file_name, ixfrcr->old_serial)) { ixfr_create_free(ixfrcr); return NULL; } if(zone->opts && zone->opts->pattern) ixfrcr->max_size = (size_t)zone->opts->pattern->ixfr_size; else ixfrcr->max_size = (size_t)ixfr_size; ixfrcr->errorcmdline = errorcmdline; return ixfrcr; } /* free ixfr create */ void ixfr_create_free(struct ixfr_create* ixfrcr) { if(!ixfrcr) return; free(ixfrcr->file_name); free(ixfrcr->zone_name); free(ixfrcr); } /* read uint16_t from spool */ static int read_spool_u16(FILE* spool, uint16_t* val) { if(fread(val, sizeof(*val), 1, spool) < 1) return 0; return 1; } /* read uint32_t from spool */ static int read_spool_u32(FILE* spool, uint32_t* val) { if(fread(val, sizeof(*val), 1, spool) < 1) return 0; return 1; } /* read dname from spool */ static int read_spool_dname(FILE* spool, uint8_t* buf, size_t buflen, size_t* dname_len) { uint16_t len; if(fread(&len, sizeof(len), 1, spool) < 1) return 0; if(len > buflen) { log_msg(LOG_ERR, "dname too long"); return 0; } if(len > 0) { if(fread(buf, len, 1, spool) < 1) return 0; } *dname_len = len; return 1; } /* read and check the spool file header */ static int read_spool_header(FILE* spool, struct ixfr_create* ixfrcr) { uint8_t dname[MAXDOMAINLEN+1]; size_t dname_len; uint32_t serial; /* read apex */ if(!read_spool_dname(spool, dname, sizeof(dname), &dname_len)) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } /* read serial */ if(!read_spool_u32(spool, &serial)) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } /* check */ if(ixfrcr->zone_name_len != dname_len || memcmp(ixfrcr->zone_name, dname, ixfrcr->zone_name_len) != 0) { log_msg(LOG_ERR, "error file %s does not contain the correct zone apex", ixfrcr->file_name); return 0; } if(ixfrcr->old_serial != serial) { log_msg(LOG_ERR, "error file %s does not contain the correct zone serial", ixfrcr->file_name); return 0; } return 1; } /* store the old soa record when we encounter it on the spool */ static int process_store_oldsoa(struct ixfr_store* store, uint8_t* dname, size_t dname_len, uint16_t tp, uint16_t kl, uint32_t ttl, uint8_t* buf, uint16_t rdlen) { if(store->data->oldsoa) { log_msg(LOG_ERR, "error spool contains multiple SOA records"); return 0; } if(!ixfr_store_oldsoa_uncompressed(store, dname, dname_len, tp, kl, ttl, buf, rdlen)) { log_msg(LOG_ERR, "out of memory"); return 0; } return 1; } /* see if rdata matches, true if equal */ static int rdata_match(struct rr* rr, uint8_t* rdata, uint16_t rdlen) { size_t rdpos = 0; int i; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { if(rdpos + domain_dname(rr->rdatas[i].domain)->name_size > rdlen) return 0; if(memcmp(rdata+rdpos, dname_name(domain_dname(rr->rdatas[i].domain)), domain_dname(rr->rdatas[i].domain)->name_size) != 0) return 0; rdpos += domain_dname(rr->rdatas[i].domain)->name_size; } else { if(rdpos + rr->rdatas[i].data[0] > rdlen) return 0; if(memcmp(rdata+rdpos, &rr->rdatas[i].data[1], rr->rdatas[i].data[0]) != 0) return 0; rdpos += rr->rdatas[i].data[0]; } } if(rdpos != rdlen) return 0; return 1; } /* find an rdata in an rrset, true if found and sets index found */ static int rrset_find_rdata(struct rrset* rrset, uint32_t ttl, uint8_t* rdata, uint16_t rdlen, uint16_t* index) { int i; for(i=0; irr_count; i++) { if(rrset->rrs[i].ttl != ttl) continue; if(rdata_match(&rrset->rrs[i], rdata, rdlen)) { *index = i; return 1; } } return 0; } /* sort comparison for uint16 elements */ static int sort_uint16(const void* x, const void* y) { const uint16_t* ax = (const uint16_t*)x; const uint16_t* ay = (const uint16_t*)y; if(*ax < *ay) return -1; if(*ax > *ay) return 1; return 0; } /* spool read an rrset, it is a deleted RRset */ static int process_diff_rrset(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct domain* domain, uint16_t tp, uint16_t kl, uint16_t rrcount, struct rrset* rrset) { /* read RRs from file and see if they are added, deleted or in both */ uint8_t buf[MAX_RDLENGTH]; uint16_t marked[65536]; size_t marked_num = 0, atmarked; int i; for(i=0; ifile_name, strerror(errno)); return 0; } /* because rdlen is uint16_t always smaller than sizeof(buf)*/ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" assert(rdlen <= sizeof(buf)); #pragma GCC diagnostic pop if(fread(buf, rdlen, 1, spool) < 1) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } if(tp == TYPE_SOA) { if(!process_store_oldsoa(store, (void*)dname_name(domain_dname(domain)), domain_dname(domain)->name_size, tp, kl, ttl, buf, rdlen)) return 0; } /* see if the rr is in the RRset */ if(rrset_find_rdata(rrset, ttl, buf, rdlen, &index)) { /* it is in both, mark it */ marked[marked_num++] = index; } else { /* not in new rrset, but only on spool, it is * a deleted RR */ if(!ixfr_store_delrr_uncompressed(store, (void*)dname_name(domain_dname(domain)), domain_dname(domain)->name_size, tp, kl, ttl, buf, rdlen)) { log_msg(LOG_ERR, "out of memory"); return 0; } } } /* now that we are done, see if RRs in the rrset are not marked, * and thus are new rrs that are added */ qsort(marked, marked_num, sizeof(marked[0]), &sort_uint16); atmarked = 0; for(i=0; irr_count; i++) { if(atmarked < marked_num && marked[atmarked] == i) { /* the item is in the marked list, skip it */ atmarked++; continue; } /* not in the marked list, the RR is added */ if(!ixfr_store_addrr_rdatas(store, domain_dname(domain), rrset->rrs[i].type, rrset->rrs[i].klass, rrset->rrs[i].ttl, rrset->rrs[i].rdatas, rrset->rrs[i].rdata_count)) { log_msg(LOG_ERR, "out of memory"); return 0; } } return 1; } /* spool read an rrset, it is a deleted RRset */ static int process_spool_delrrset(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, uint8_t* dname, size_t dname_len, uint16_t tp, uint16_t kl, uint16_t rrcount) { /* read the RRs from file and add to del list. */ uint8_t buf[MAX_RDLENGTH]; int i; for(i=0; ifile_name, strerror(errno)); return 0; } /* because rdlen is uint16_t always smaller than sizeof(buf)*/ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" assert(rdlen <= sizeof(buf)); #pragma GCC diagnostic pop if(fread(buf, rdlen, 1, spool) < 1) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } if(tp == TYPE_SOA) { if(!process_store_oldsoa(store, dname, dname_len, tp, kl, ttl, buf, rdlen)) return 0; } if(!ixfr_store_delrr_uncompressed(store, dname, dname_len, tp, kl, ttl, buf, rdlen)) { log_msg(LOG_ERR, "out of memory"); return 0; } } return 1; } /* add the rrset to the added list */ static int process_add_rrset(struct ixfr_store* ixfr_store, struct domain* domain, struct rrset* rrset) { int i; for(i=0; irr_count; i++) { if(!ixfr_store_addrr_rdatas(ixfr_store, domain_dname(domain), rrset->rrs[i].type, rrset->rrs[i].klass, rrset->rrs[i].ttl, rrset->rrs[i].rdatas, rrset->rrs[i].rdata_count)) { log_msg(LOG_ERR, "out of memory"); return 0; } } return 1; } /* add the RR types that are not in the marktypes list from the new zone */ static int process_marktypes(struct ixfr_store* store, struct zone* zone, struct domain* domain, uint16_t* marktypes, size_t marktypes_used) { /* walk through the rrsets in the zone, if it is not in the * marktypes list, then it is new and an added RRset */ rrset_type* s; qsort(marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16); for(s=domain->rrsets; s; s=s->next) { uint16_t tp; if(s->zone != zone) continue; tp = rrset_rrtype(s); if(bsearch(&tp, marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16)) { /* the item is in the marked list, skip it */ continue; } if(!process_add_rrset(store, domain, s)) return 0; } return 1; } /* check the difference between the domain and RRs from spool */ static int process_diff_domain(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct zone* zone, struct domain* domain) { /* Read the RR types from spool. Mark off the ones seen, * later, the notseen ones from the new zone are added RRsets. * For the ones not in the new zone, they are deleted RRsets. * If they exist in old and new, check for RR differences. */ uint32_t spool_type_count, i; uint16_t marktypes[65536]; size_t marktypes_used = 0; if(!read_spool_u32(spool, &spool_type_count)) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } if(spool_type_count > sizeof(marktypes)) { log_msg(LOG_ERR, "error reading file %s: spool type count " "too large", ixfrcr->file_name); return 0; } for(i=0; ifile_name, strerror(errno)); return 0; } /* The rrcount is within limits of sizeof(marktypes), because * the uint16_t < 65536 */ rrset = domain_find_rrset(domain, zone, tp); if(!rrset) { /* rrset in spool but not in new zone, deleted RRset */ if(!process_spool_delrrset(spool, ixfrcr, store, (void*)dname_name(domain_dname(domain)), domain_dname(domain)->name_size, tp, kl, rrcount)) return 0; } else { /* add to the marked types, this one is present in * spool */ marktypes[marktypes_used++] = tp; /* rrset in old and in new zone, diff the RRset */ if(!process_diff_rrset(spool, ixfrcr, store, domain, tp, kl, rrcount, rrset)) return 0; } } /* process markoff to see if new zone has RRsets not in spool, * those are added RRsets. */ if(!process_marktypes(store, zone, domain, marktypes, marktypes_used)) return 0; return 1; } /* add the RRs for the domain in new zone */ static int process_domain_add_RRs(struct ixfr_store* store, struct zone* zone, struct domain* domain) { rrset_type* s; for(s=domain->rrsets; s; s=s->next) { if(s->zone != zone) continue; if(!process_add_rrset(store, domain, s)) return 0; } return 1; } /* del the RRs for the domain from the spool */ static int process_domain_del_RRs(struct ixfr_create* ixfrcr, struct ixfr_store* store, FILE* spool, uint8_t* dname, size_t dname_len) { uint32_t spool_type_count, i; if(!read_spool_u32(spool, &spool_type_count)) { log_msg(LOG_ERR, "error reading file %s: %s", ixfrcr->file_name, strerror(errno)); return 0; } if(spool_type_count > 65536) { log_msg(LOG_ERR, "error reading file %s: del RR spool type " "count too large", ixfrcr->file_name); return 0; } for(i=0; ifile_name, strerror(errno)); return 0; } /* The rrcount is within reasonable limits, because * the uint16_t < 65536 */ if(!process_spool_delrrset(spool, ixfrcr, store, dname, dname_len, tp, kl, rrcount)) return 0; } return 1; } /* init the spool dname iterator */ static void spool_dname_iter_init(struct spool_dname_iterator* iter, FILE* spool, char* file_name) { memset(iter, 0, sizeof(*iter)); iter->spool = spool; iter->file_name = file_name; } /* read the dname element into the buffer for the spool dname iterator */ static int spool_dname_iter_read(struct spool_dname_iterator* iter) { if(!read_spool_dname(iter->spool, iter->dname, sizeof(iter->dname), &iter->dname_len)) { log_msg(LOG_ERR, "error reading file %s: %s", iter->file_name, strerror(errno)); return 0; } return 1; } /* get the next name to operate on, that is not processed yet, 0 on failure * returns okay on endoffile, check with eof for that. * when done with an element, set iter->is_processed on the element. */ static int spool_dname_iter_next(struct spool_dname_iterator* iter) { if(iter->eof) return 1; if(!iter->read_first) { /* read the first one */ if(!spool_dname_iter_read(iter)) return 0; if(iter->dname_len == 0) iter->eof = 1; iter->read_first = 1; iter->is_processed = 0; } if(!iter->is_processed) { /* the current one needs processing */ return 1; } /* read the next one */ if(!spool_dname_iter_read(iter)) return 0; if(iter->dname_len == 0) iter->eof = 1; iter->is_processed = 0; return 1; } /* check if the ixfr is too large */ static int ixfr_create_too_large(struct ixfr_create* ixfrcr, struct ixfr_store* store) { if(store->cancelled) return 1; if(ixfrcr->max_size != 0 && ixfr_data_size(store->data) > ixfrcr->max_size) { if(ixfrcr->errorcmdline) { log_msg(LOG_ERR, "the ixfr for %s exceeds size %u, it is not created", wiredname2str(ixfrcr->zone_name), (unsigned)ixfrcr->max_size); } else { VERBOSITY(2, (LOG_INFO, "the ixfr for %s exceeds size %u, it is not created", wiredname2str(ixfrcr->zone_name), (unsigned)ixfrcr->max_size)); } ixfr_store_cancel(store); return 1; } return 0; } /* process the spool input before the domain */ static int process_spool_before_domain(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct domain* domain, struct spool_dname_iterator* iter, struct region* tmp_region) { const dname_type* dname; if(ixfr_create_too_large(ixfrcr, store)) return 0; /* read the domains and rrsets before the domain and those are from * the old zone. If the domain is equal, return to have that processed * if we bypass, that means the domain does not exist, do that */ while(!iter->eof) { if(!spool_dname_iter_next(iter)) return 0; if(iter->eof) break; /* see if we are at, before or after the domain */ dname = dname_make(tmp_region, iter->dname, 1); if(!dname) { log_msg(LOG_ERR, "error in dname in %s", iter->file_name); return 0; } if(dname_compare(dname, domain_dname(domain)) < 0) { /* the dname is smaller than the one from the zone. * it must be deleted, process it */ if(!process_domain_del_RRs(ixfrcr, store, spool, iter->dname, iter->dname_len)) return 0; iter->is_processed = 1; } else { /* we are at or after the domain we are looking for, * done here */ return 1; } if(ixfr_create_too_large(ixfrcr, store)) return 0; } /* no more domains on spool, done here */ return 1; } /* process the spool input for the domain */ static int process_spool_for_domain(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct zone* zone, struct domain* domain, struct spool_dname_iterator* iter, struct region* tmp_region) { /* process all the spool that is not the domain, that is before the * domain in the new zone */ if(!process_spool_before_domain(spool, ixfrcr, store, domain, iter, tmp_region)) return 0; if(ixfr_create_too_large(ixfrcr, store)) return 0; /* are we at the correct domain now? */ if(iter->eof || iter->dname_len != domain_dname(domain)->name_size || memcmp(iter->dname, dname_name(domain_dname(domain)), iter->dname_len) != 0) { /* the domain from the new zone is not present in the old zone, * the content is in the added RRs set */ if(!process_domain_add_RRs(store, zone, domain)) return 0; return 1; } /* process the domain */ /* the domain exists both in the old and new zone, * check for RR differences */ if(!process_diff_domain(spool, ixfrcr, store, zone, domain)) return 0; iter->is_processed = 1; return 1; } /* process remaining spool items */ static int process_spool_remaining(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct spool_dname_iterator* iter) { /* the remaining domain names in the spool file, that is after * the last domain in the new zone. */ if(ixfr_create_too_large(ixfrcr, store)) return 0; while(!iter->eof) { if(!spool_dname_iter_next(iter)) return 0; if(iter->eof) break; /* the domain only exists in the spool, the old zone, * and not in the new zone. That would be domains * after the new zone domains, or there are no new * zone domains */ if(!process_domain_del_RRs(ixfrcr, store, spool, iter->dname, iter->dname_len)) return 0; iter->is_processed = 1; if(ixfr_create_too_large(ixfrcr, store)) return 0; } return 1; } /* walk through the zone and find the differences */ static int ixfr_create_walk_zone(FILE* spool, struct ixfr_create* ixfrcr, struct ixfr_store* store, struct zone* zone) { struct domain* domain; struct spool_dname_iterator iter; struct region* tmp_region; spool_dname_iter_init(&iter, spool, ixfrcr->file_name); tmp_region = region_create(xalloc, free); for(domain = zone->apex; domain && domain_is_subdomain(domain, zone->apex); domain = domain_next(domain)) { uint32_t count = domain_count_rrsets(domain, zone); if(count == 0) continue; /* the domain is a domain in the new zone */ if(!process_spool_for_domain(spool, ixfrcr, store, zone, domain, &iter, tmp_region)) { region_destroy(tmp_region); return 0; } region_free_all(tmp_region); if(ixfr_create_too_large(ixfrcr, store)) return 0; } if(!process_spool_remaining(spool, ixfrcr, store, &iter)) { region_destroy(tmp_region); return 0; } region_destroy(tmp_region); return 1; } /* see if the ixfr has already been created by reading the file header * of the to-be-created file, if that file already exists */ static int ixfr_create_already_done_serial(struct zone* zone, const char* zfile, int checknew, uint32_t old_serial, uint32_t new_serial) { uint32_t file_oldserial = 0, file_newserial = 0; size_t data_size = 0; if(!ixfr_read_file_header(zone->opts->name, zfile, 1, &file_oldserial, &file_newserial, &data_size, 0)) { /* could not read, so it was not done */ return 0; } if(file_oldserial == old_serial && (!checknew || file_newserial == new_serial)) { log_msg(LOG_INFO, "IXFR already exists in file %s.ixfr, nothing to do", zfile); return 1; } return 0; } /* See the data size of the ixfr by reading the file header of the ixfr file */ static int ixfr_read_header_data_size(const char* zname, const char* zfile, int file_num, size_t* data_size) { uint32_t file_oldserial = 0, file_newserial = 0; if(!ixfr_read_file_header(zname, zfile, file_num, &file_oldserial, &file_newserial, data_size, 0)) { /* could not read */ return 0; } return 1; } /* see if the ixfr has already been created by reading the file header * of the to-be-created file, if that file already exists */ static int ixfr_create_already_done(struct ixfr_create* ixfrcr, struct zone* zone, const char* zfile, int checknew) { return ixfr_create_already_done_serial(zone, zfile, checknew, ixfrcr->old_serial, ixfrcr->new_serial); } /* store the new soa record for the ixfr */ static int ixfr_create_store_newsoa(struct ixfr_store* store, struct zone* zone) { if(!zone || !zone->soa_rrset) { log_msg(LOG_ERR, "error no SOA rrset"); return 0; } if(zone->soa_rrset->rr_count == 0) { log_msg(LOG_ERR, "error empty SOA rrset"); return 0; } if(!ixfr_store_add_newsoa_rdatas(store, domain_dname(zone->apex), zone->soa_rrset->rrs[0].type, zone->soa_rrset->rrs[0].klass, zone->soa_rrset->rrs[0].ttl, zone->soa_rrset->rrs[0].rdatas, zone->soa_rrset->rrs[0].rdata_count)) { log_msg(LOG_ERR, "out of memory"); return 0; } return 1; } /* initialise ixfr_create perform, open spool, read header, get serial */ static int ixfr_perform_init(struct ixfr_create* ixfrcr, struct zone* zone, struct ixfr_store* store_mem, struct ixfr_store** store, FILE** spool) { *spool = fopen(ixfrcr->file_name, "r"); if(!*spool) { log_msg(LOG_ERR, "could not open %s for reading: %s", ixfrcr->file_name, strerror(errno)); return 0; } if(!read_spool_header(*spool, ixfrcr)) { fclose(*spool); return 0; } ixfrcr->new_serial = zone_get_current_serial(zone); *store = ixfr_store_start(zone, store_mem); if(!ixfr_create_store_newsoa(*store, zone)) { fclose(*spool); ixfr_store_free(*store); return 0; } return 1; } /* rename the other ixfr files */ static int ixfr_create_rename_and_delete_files(const char* zname, const char* zoptsname, const char* zfile, uint32_t ixfr_number, size_t ixfr_size, size_t cur_data_size) { size_t size_in_use = cur_data_size; int dest_nr_files = (int)ixfr_number, maxsizehit = 0; int num = 1; while(ixfr_file_exists(zfile, num)) { size_t fsize = 0; if(!maxsizehit) { if(!ixfr_read_header_data_size(zoptsname, zfile, num, &fsize) || size_in_use + fsize > ixfr_size) { /* no more than this because of storage size */ dest_nr_files = num; maxsizehit = 1; } size_in_use += fsize; } num++; } num--; /* num is now the number of ixfr files that exist */ while(num > 0) { if(num+1 > dest_nr_files) { (void)ixfr_unlink_it(zname, zfile, num, 0); } else { if(!ixfr_rename_it(zname, zfile, num, 0, num+1, 0)) return 0; } num--; } return 1; } /* finish up ixfr create processing */ static void ixfr_create_finishup(struct ixfr_create* ixfrcr, struct ixfr_store* store, struct zone* zone, int append_mem, struct nsd* nsd, const char* zfile, uint32_t ixfr_number) { char log_buf[1024], nowstr[128]; /* create the log message */ time_t now = time(NULL); if(store->cancelled || ixfr_create_too_large(ixfrcr, store)) { /* remove unneeded files. * since this ixfr cannot be created the others are useless. */ ixfr_delete_superfluous_files(zone, zfile, 0); return; } snprintf(nowstr, sizeof(nowstr), "%s", ctime(&now)); if(strchr(nowstr, '\n')) *strchr(nowstr, '\n') = 0; snprintf(log_buf, sizeof(log_buf), "IXFR created by NSD %s for %s %u to %u of %u bytes at time %s", PACKAGE_VERSION, wiredname2str(ixfrcr->zone_name), (unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial, (unsigned)ixfr_data_size(store->data), nowstr); store->data->log_str = strdup(log_buf); if(!store->data->log_str) { log_msg(LOG_ERR, "out of memory"); ixfr_store_free(store); return; } if(!ixfr_create_rename_and_delete_files( wiredname2str(ixfrcr->zone_name), zone->opts->name, zfile, ixfr_number, ixfrcr->max_size, ixfr_data_size(store->data))) { log_msg(LOG_ERR, "could not rename other ixfr files"); ixfr_store_free(store); return; } if(!ixfr_write_file(zone, store->data, zfile, 1)) { log_msg(LOG_ERR, "could not write to file"); ixfr_store_free(store); return; } if(append_mem) { ixfr_store_finish(store, nsd, log_buf); } else { ixfr_store_free(store); } } void ixfr_readup_exist(struct zone* zone, struct nsd* nsd, const char* zfile) { /* the .ixfr file already exists with the correct serial numbers * on the disk. Read up the ixfr files from the drive and put them * in memory. To match the zone that has just been read. * We can skip ixfr creation, and read up the files from the drive. * If the files on the drive are consistent, we end up with exactly * those ixfrs and that zone in memory. * Presumably, the user has used nsd-checkzone to create an IXFR * file and has put a new zone file, so we read up the data that * we should have now. * This also takes into account the config on number and size. */ ixfr_read_from_file(nsd, zone, zfile); } int ixfr_create_perform(struct ixfr_create* ixfrcr, struct zone* zone, int append_mem, struct nsd* nsd, const char* zfile, uint32_t ixfr_number) { struct ixfr_store store_mem, *store; FILE* spool; if(!ixfr_perform_init(ixfrcr, zone, &store_mem, &store, &spool)) { (void)unlink(ixfrcr->file_name); return 0; } if(ixfrcr->new_serial == ixfrcr->old_serial || compare_serial(ixfrcr->new_serial, ixfrcr->old_serial)<0) { log_msg(LOG_ERR, "zone %s ixfr could not be created because the serial is the same or moves backwards, from %u to %u", wiredname2str(ixfrcr->zone_name), (unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial); ixfr_store_cancel(store); fclose(spool); ixfr_store_free(store); (void)unlink(ixfrcr->file_name); ixfr_delete_superfluous_files(zone, zfile, 0); if(append_mem) ixfr_store_delixfrs(zone); return 0; } if(ixfr_create_already_done(ixfrcr, zone, zfile, 1)) { ixfr_store_cancel(store); fclose(spool); ixfr_store_free(store); (void)unlink(ixfrcr->file_name); if(append_mem) { ixfr_readup_exist(zone, nsd, zfile); } return 0; } if(!ixfr_create_walk_zone(spool, ixfrcr, store, zone)) { fclose(spool); ixfr_store_free(store); (void)unlink(ixfrcr->file_name); ixfr_delete_superfluous_files(zone, zfile, 0); return 0; } if(store->data && !store->data->oldsoa) { log_msg(LOG_ERR, "error spool file did not contain a SOA record"); fclose(spool); ixfr_store_free(store); (void)unlink(ixfrcr->file_name); return 0; } if(!store->cancelled) ixfr_store_finish_data(store); fclose(spool); (void)unlink(ixfrcr->file_name); ixfr_create_finishup(ixfrcr, store, zone, append_mem, nsd, zfile, ixfr_number); return 1; } void ixfr_create_cancel(struct ixfr_create* ixfrcr) { if(!ixfrcr) return; (void)unlink(ixfrcr->file_name); ixfr_create_free(ixfrcr); } int ixfr_create_from_difference(struct zone* zone, const char* zfile, int* ixfr_create_already_done_flag) { uint32_t old_serial; *ixfr_create_already_done_flag = 0; /* only if the zone is ixfr enabled */ if(!zone_is_ixfr_enabled(zone)) return 0; /* only if ixfr create is enabled */ if(!zone->opts->pattern->create_ixfr) return 0; /* only if there is a zone in memory to compare with */ if(!zone->soa_rrset || !zone->apex) return 0; old_serial = zone_get_current_serial(zone); if(ixfr_create_already_done_serial(zone, zfile, 0, old_serial, 0)) { *ixfr_create_already_done_flag = 1; return 0; } return 1; } nsd-4.12.0/ixfr.h0000644000175000017500000002330615002373054013122 0ustar mozziemozzie/* * ixfr.h -- generating IXFR responses. * * Copyright (c) 2021, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef IXFR_H #define IXFR_H struct nsd; #include "query.h" #include "rbtree.h" struct ixfr_data; struct zone; struct buffer; struct region; /* default for number of ixfr versions in files */ #define IXFR_NUMBER_DEFAULT 5 /* number of versions */ /* default for IXFR storage */ #define IXFR_SIZE_DEFAULT 1048576 /* in bytes, 1M */ /* data structure that stores IXFR contents for a zone. */ struct zone_ixfr { /* Items are of type ixfr_data. The key is old_serial. * So it can be looked up on an incoming IXFR. They are sorted * by old_serial, so the looked up and next are the versions needed. * Tree of ixfr data for versions */ struct rbtree* data; /* total size stored at this time, in bytes, * sum of sizes of the ixfr data elements */ size_t total_size; /* the oldest serial number in the tree, searchable by old_serial */ uint32_t oldest_serial; /* the newest serial number in the tree, that is searchable in the * tree, so it is the old_serial of the newest data entry, that * has an even newer new_serial of that entry */ uint32_t newest_serial; }; /* Data structure that stores one IXFR. * The RRs are stored in uncompressed wireformat, that means * an uncompressed domain name, type, class, TTL, rdatalen, * uncompressed rdata in wireformat. * * The data structure is formatted like this so that making an IXFR * that moves across several versions can be done by collating the * pieces precisely from the versions involved. In particular, for * an IXFR from olddata to newdata, for a combined output: * newdata.newsoa olddata.oldsoa olddata.del olddata.add * newdata.del newdata.add * in sequence should produce a valid, non-condensed, IXFR with multiple * versions inside. */ struct ixfr_data { /* Node in the rbtree. Key is oldserial */ struct rbnode node; /* from what serial the IXFR starts from, the 'old' serial */ uint32_t oldserial; /* where to IXFR goes to, the 'new' serial */ uint32_t newserial; /* the new SOA record, with newserial */ uint8_t* newsoa; /* byte length of the uncompressed wireformat RR in newsoa */ size_t newsoa_len; /* the old SOA record, with oldserial */ uint8_t* oldsoa; /* byte length of the uncompressed wireformat RR in oldsoa*/ size_t oldsoa_len; /* the deleted RRs, ends with the newserial SOA record. * if the ixfr is collated out multiple versions, then * this deleted RRs section contains several add and del sections * for the older versions, and ends with the last del section, * and the SOA record with the newserial. * That is everything except the final add section for newserial. */ uint8_t* del; /* byte length of the uncompressed wireformat RRs in del */ size_t del_len; /* the added RRs, ends with the newserial SOA record. */ uint8_t* add; /* byte length of the uncompressed wireformat RRs in add */ size_t add_len; /* log string (if not NULL) about where data is from */ char* log_str; /* the number of the ixfr. file on disk. If 0, there is no * file. If 1, it is file ixfr. */ int file_num; }; /* process queries in IXFR state */ query_state_type query_ixfr(struct nsd *nsd, struct query *query); /* * While an IXFR is processed, in incoming IXFR that is downloaded by NSD, * this structure keeps track of how to store the data from it. That data * can then be used to answer IXFR queries. * * The structure keeps track of allocation data for the IXFR records. * If it is cancelled, that is flagged so storage stops. */ struct ixfr_store { /* the zone info, with options and zone ixfr reference */ struct zone* zone; /* are we cancelled, it is not an IXFR, no need to store information * any more. */ int cancelled; /* data has been trimmed and newsoa added */ int data_trimmed; /* the ixfr data that we are storing into */ struct ixfr_data* data; /* capacity for the delrrs storage, size of ixfr del allocation */ size_t del_capacity; /* capacity for the addrrs storage, size of ixfr add allocation */ size_t add_capacity; }; /* * Start the storage of the IXFR data from this IXFR. * If it returns NULL, the IXFR storage stops. On malloc failure, the * storage is returned NULL, or cancelled if failures happen later on. * * When done, the finish routine links the data into the memory for the zone. * If it turns out to not be used, use the cancel routine. Or the free * routine if the ixfr_store itself needs to be deleted too, like on error. * * zone: the zone structure * ixfr_store_mem: preallocated by caller, used to allocate the store struct. * old_serial: the start serial of the IXFR. * new_serial: the end serial of the IXFR. * return NULL or a fresh ixfr_store structure for adding records to the * IXFR with this serial number. The NULL is on error. */ struct ixfr_store* ixfr_store_start(struct zone* zone, struct ixfr_store* ixfr_store_mem); /* * Cancel the ixfr store in progress. The pointer remains valid, no store done. * ixfr_store: this is set to cancel. */ void ixfr_store_cancel(struct ixfr_store* ixfr_store); /* * Free ixfr store structure, it is no longer used. * ixfr_store: deleted */ void ixfr_store_free(struct ixfr_store* ixfr_store); /* * Finish ixfr store processing. Links the data into the zone ixfr data. * ixfr_store: Data is linked into the zone struct. The ixfr_store is freed. * nsd: nsd structure for allocation region and global options. * log_buf: log string for the update. */ void ixfr_store_finish(struct ixfr_store* ixfr_store, struct nsd* nsd, char* log_buf); /* finish just the data activities, trim up the storage and append newsoa */ void ixfr_store_finish_data(struct ixfr_store* ixfr_store); /* * Add the new SOA record to the ixfr store. * ixfr_store: stores ixfr data that is collected. * ttl: the TTL of the SOA record * packet: DNS packet that contains the SOA. position restored on function * exit. * rrlen: wire rdata length of the SOA. */ void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, uint32_t ttl, struct buffer* packet, size_t rrlen); /* * Add the old SOA record to the ixfr store. * ixfr_store: stores ixfr data that is collected. * ttl: the TTL of the SOA record * packet: DNS packet that contains the SOA. position restored on function * exit. * rrlen: wire rdata length of the SOA. */ void ixfr_store_add_oldsoa(struct ixfr_store* ixfr_store, uint32_t ttl, struct buffer* packet, size_t rrlen); void ixfr_store_delrr(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, struct buffer* packet, uint16_t rrlen, struct region* temp_region); void ixfr_store_addrr(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, struct buffer* packet, uint16_t rrlen, struct region* temp_region); int ixfr_store_addrr_rdatas(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num); int ixfr_store_delrr_uncompressed(struct ixfr_store* ixfr_store, uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len); int ixfr_store_add_newsoa_rdatas(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num); int ixfr_store_oldsoa_uncompressed(struct ixfr_store* ixfr_store, uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len); /* an AXFR has been received, the IXFRs do not connect in version number. * Delete the unconnected IXFRs from memory */ void ixfr_store_delixfrs(struct zone* zone); /* return if the zone has ixfr storage enabled for it */ int zone_is_ixfr_enabled(struct zone* zone); /* create new zone_ixfr structure */ struct zone_ixfr* zone_ixfr_create(struct nsd* nsd); /* free the zone_ixfr */ void zone_ixfr_free(struct zone_ixfr* ixfr); /* make space to fit in the data */ void zone_ixfr_make_space(struct zone_ixfr* ixfr, struct zone* zone, struct ixfr_data* data, struct ixfr_store* ixfr_store); /* remove ixfr data from the zone_ixfr */ void zone_ixfr_remove(struct zone_ixfr* ixfr, struct ixfr_data* data); /* add ixfr data to the zone_ixfr */ void zone_ixfr_add(struct zone_ixfr* ixfr, struct ixfr_data* data, int isnew); /* find serial number in ixfr list, or NULL if not found */ struct ixfr_data* zone_ixfr_find_serial(struct zone_ixfr* ixfr, uint32_t qserial); /* size of the ixfr data */ size_t ixfr_data_size(struct ixfr_data* data); /* write ixfr contents to file for the zone */ void ixfr_write_to_file(struct zone* zone, const char* zfile); /* read ixfr contents from file for the zone */ void ixfr_read_from_file(struct nsd* nsd, struct zone* zone, const char* zfile); /* get the current serial from the zone */ uint32_t zone_get_current_serial(struct zone* zone); /* write the ixfr data to file */ int ixfr_write_file(struct zone* zone, struct ixfr_data* data, const char* zfile, int file_num); /* see if ixfr file exists */ int ixfr_file_exists(const char* zfile, int file_num); /* rename the ixfr file */ int ixfr_rename_it(const char* zname, const char* zfile, int oldnum, int oldtemp, int newnum, int newtemp); /* read the file header of an ixfr file and return serial numbers. */ int ixfr_read_file_header(const char* zname, const char* zfile, int file_num, uint32_t* oldserial, uint32_t* newserial, size_t* data_size, int enoent_is_err); /* unlink an ixfr file */ int ixfr_unlink_it(const char* zname, const char* zfile, int file_num, int silent_enoent); /* delete the ixfr files that are too many */ void ixfr_delete_superfluous_files(struct zone* zone, const char* zfile, int dest_num_files); #endif /* IXFR_H */ nsd-4.12.0/ixfr.c0000644000175000017500000023321715002373054013121 0ustar mozziemozzie/* * ixfr.c -- generating IXFR responses. * * Copyright (c) 2021, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #include "ixfr.h" #include "packet.h" #include "rdata.h" #include "axfr.h" #include "options.h" #include "zonec.h" #include "zone.h" /* * For optimal compression IXFR response packets are limited in size * to MAX_COMPRESSION_OFFSET. */ #define IXFR_MAX_MESSAGE_LEN MAX_COMPRESSION_OFFSET /* draft-ietf-dnsop-rfc2845bis-06, section 5.3.1 says to sign every packet */ #define IXFR_TSIG_SIGN_EVERY_NTH 0 /* tsig sign every N packets. */ /* initial space in rrs data for storing records */ #define IXFR_STORE_INITIAL_SIZE 4096 /* store compression for one name */ struct rrcompress_entry { /* rbtree node, key is this struct */ struct rbnode node; /* the uncompressed domain name */ const uint8_t* dname; /* the length of the dname, includes terminating 0 label */ uint16_t len; /* the offset of the dname in the packet */ uint16_t offset; }; /* structure to store compression data for the packet */ struct pktcompression { /* rbtree of rrcompress_entry. sorted by dname */ struct rbtree tree; /* allocation information, how many bytes allocated now */ size_t alloc_now; /* allocation information, total size in block */ size_t alloc_max; /* region to use if block full, this is NULL if unused */ struct region* region; /* block of temp data for allocation */ uint8_t block[sizeof(struct rrcompress_entry)*1024]; }; /* compare two elements in the compression tree. Returns -1, 0, or 1. */ static int compression_cmp(const void* a, const void* b) { struct rrcompress_entry* rra = (struct rrcompress_entry*)a; struct rrcompress_entry* rrb = (struct rrcompress_entry*)b; if(rra->len != rrb->len) { if(rra->len < rrb->len) return -1; return 1; } return memcmp(rra->dname, rrb->dname, rra->len); } /* init the pktcompression to a new packet */ static void pktcompression_init(struct pktcompression* pcomp) { pcomp->alloc_now = 0; pcomp->alloc_max = sizeof(pcomp->block); pcomp->region = NULL; pcomp->tree.root = RBTREE_NULL; pcomp->tree.count = 0; pcomp->tree.region = NULL; pcomp->tree.cmp = &compression_cmp; } /* freeup the pktcompression data */ static void pktcompression_freeup(struct pktcompression* pcomp) { if(pcomp->region) { region_destroy(pcomp->region); pcomp->region = NULL; } pcomp->alloc_now = 0; pcomp->tree.root = RBTREE_NULL; pcomp->tree.count = 0; } /* alloc data in pktcompression */ static void* pktcompression_alloc(struct pktcompression* pcomp, size_t s) { /* first attempt to allocate in the fixed block, * that is very fast and on the stack in the pcomp struct */ if(pcomp->alloc_now + s <= pcomp->alloc_max) { void* ret = pcomp->block + pcomp->alloc_now; pcomp->alloc_now += s; return ret; } /* if that fails, create a region to allocate in, * it is freed in the freeup */ if(!pcomp->region) { pcomp->region = region_create(xalloc, free); if(!pcomp->region) return NULL; } return region_alloc(pcomp->region, s); } /* find a pktcompression name, return offset if found */ static uint16_t pktcompression_find(struct pktcompression* pcomp, const uint8_t* dname, size_t len) { struct rrcompress_entry key, *found; key.node.key = &key; key.dname = dname; key.len = len; found = (struct rrcompress_entry*)rbtree_search(&pcomp->tree, &key); if(found) return found->offset; return 0; } /* insert a new domain name into the compression tree. * it fails silently, no need to compress then. */ static void pktcompression_insert(struct pktcompression* pcomp, const uint8_t* dname, size_t len, uint16_t offset) { struct rrcompress_entry* entry; if(len > 65535) return; if(offset > MAX_COMPRESSION_OFFSET) return; /* too far for a compression pointer */ entry = pktcompression_alloc(pcomp, sizeof(*entry)); if(!entry) return; memset(&entry->node, 0, sizeof(entry->node)); entry->node.key = entry; entry->dname = dname; entry->len = len; entry->offset = offset; (void)rbtree_insert(&pcomp->tree, &entry->node); } /* insert all the labels of a domain name */ static void pktcompression_insert_with_labels(struct pktcompression* pcomp, uint8_t* dname, size_t len, uint16_t offset) { if(!dname) return; if(offset > MAX_COMPRESSION_OFFSET) return; /* while we have not seen the end root label */ while(len > 0 && dname[0] != 0) { size_t lablen; pktcompression_insert(pcomp, dname, len, offset); lablen = (size_t)(dname[0]); if( (lablen&0xc0) ) return; /* the dname should be uncompressed */ if(lablen+1 > len) return; /* len should be uncompressed wireformat len */ if(offset > MAX_COMPRESSION_OFFSET - lablen - 1) return; /* offset moves too far for compression */ /* skip label */ len -= lablen+1; dname += lablen+1; offset += lablen+1; } } /* calculate length of dname in uncompressed wireformat in buffer */ static size_t dname_length(const uint8_t* buf, size_t len) { size_t l = 0; if(!buf || len == 0) return l; while(len > 0 && buf[0] != 0) { size_t lablen = (size_t)(buf[0]); if( (lablen&0xc0) ) return 0; /* the name should be uncompressed */ if(lablen+1 > len) return 0; /* should fit in the buffer */ l += lablen+1; len -= lablen+1; buf += lablen+1; } if(len == 0) return 0; /* end label should fit in buffer */ if(buf[0] != 0) return 0; /* must end in root label */ l += 1; /* for the end root label */ return l; } /* write a compressed domain name into the packet, * returns uncompressed wireformat length, * 0 if it does not fit and -1 on failure, bad dname. */ static int pktcompression_write_dname(struct buffer* packet, struct pktcompression* pcomp, const uint8_t* rr, size_t rrlen) { size_t wirelen = 0; size_t dname_len = dname_length(rr, rrlen); if(!rr || rrlen == 0 || dname_len == 0) return 0; while(rrlen > 0 && rr[0] != 0) { size_t lablen = (size_t)(rr[0]); uint16_t offset; if( (lablen&0xc0) ) return -1; /* name should be uncompressed */ if(lablen+1 > rrlen) return -1; /* name should fit */ /* see if the domain name has a compression pointer */ if((offset=pktcompression_find(pcomp, rr, dname_len))!=0) { if(!buffer_available(packet, 2)) return 0; buffer_write_u16(packet, (uint16_t)(0xc000 | offset)); wirelen += dname_len; return wirelen; } else { if(!buffer_available(packet, lablen+1)) return 0; /* insert the domain name at this position */ pktcompression_insert(pcomp, rr, dname_len, buffer_position(packet)); /* write it */ buffer_write(packet, rr, lablen+1); } wirelen += lablen+1; rr += lablen+1; rrlen -= lablen+1; dname_len -= lablen+1; } if(rrlen > 0 && rr[0] == 0) { /* write end root label */ if(!buffer_available(packet, 1)) return 0; buffer_write_u8(packet, 0); wirelen += 1; } return wirelen; } /* write an RR into the packet with compression for domain names, * return 0 and resets position if it does not fit in the packet. */ static int ixfr_write_rr_pkt(struct query* query, struct buffer* packet, struct pktcompression* pcomp, const uint8_t* rr, size_t rrlen, uint16_t total_added) { size_t oldpos = buffer_position(packet); size_t rdpos; uint16_t tp; int dname_len; size_t rdlen; size_t i; rrtype_descriptor_type* descriptor; if(total_added == 0) { size_t oldmaxlen = query->maxlen; /* RR > 16K can be first RR */ query->maxlen = (query->tcp?TCP_MAX_MESSAGE_LEN:UDP_MAX_MESSAGE_LEN); if(query_overflow(query)) { query->maxlen = oldmaxlen; return 0; } query->maxlen = oldmaxlen; } else { if(buffer_position(packet) > MAX_COMPRESSION_OFFSET || query_overflow(query)) { /* we are past the maximum length */ return 0; } } /* write owner */ dname_len = pktcompression_write_dname(packet, pcomp, rr, rrlen); if(dname_len == -1) return 1; /* attempt to skip this malformed rr, could assert */ if(dname_len == 0) { buffer_set_position(packet, oldpos); return 0; } rr += dname_len; rrlen -= dname_len; /* type, class, ttl, rdatalen */ if(!buffer_available(packet, 10)) { buffer_set_position(packet, oldpos); return 0; } if(10 > rrlen) return 1; /* attempt to skip this malformed rr, could assert */ tp = read_uint16(rr); buffer_write(packet, rr, 8); rr += 8; rrlen -= 8; rdlen = read_uint16(rr); rr += 2; rrlen -= 2; rdpos = buffer_position(packet); buffer_write_u16(packet, 0); if(rdlen > rrlen) return 1; /* attempt to skip this malformed rr, could assert */ /* rdata */ descriptor = rrtype_descriptor_by_type(tp); for(i=0; imaximum; i++) { size_t copy_len = 0; if(rdlen == 0) break; switch(rdata_atom_wireformat_type(tp, i)) { case RDATA_WF_COMPRESSED_DNAME: dname_len = pktcompression_write_dname(packet, pcomp, rr, rdlen); if(dname_len == -1) return 1; /* attempt to skip malformed rr */ if(dname_len == 0) { buffer_set_position(packet, oldpos); return 0; } rr += dname_len; rdlen -= dname_len; break; case RDATA_WF_UNCOMPRESSED_DNAME: case RDATA_WF_LITERAL_DNAME: copy_len = rdlen; break; case RDATA_WF_BYTE: copy_len = 1; break; case RDATA_WF_SHORT: copy_len = 2; break; case RDATA_WF_LONG: copy_len = 4; break; case RDATA_WF_LONGLONG: copy_len = 8; break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: copy_len = rdlen; break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: copy_len = 1; if(rdlen > copy_len) copy_len += rr[0]; break; case RDATA_WF_A: copy_len = 4; break; case RDATA_WF_AAAA: copy_len = 16; break; case RDATA_WF_ILNP64: copy_len = 8; break; case RDATA_WF_EUI48: copy_len = EUI48ADDRLEN; break; case RDATA_WF_EUI64: copy_len = EUI64ADDRLEN; break; case RDATA_WF_BINARY: copy_len = rdlen; break; case RDATA_WF_APL: copy_len = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if(copy_len <= rdlen) copy_len += (rr[copy_len-1]&APL_LENGTH_MASK); break; case RDATA_WF_IPSECGATEWAY: copy_len = rdlen; break; case RDATA_WF_SVCPARAM: copy_len = 4; if(copy_len <= rdlen) copy_len += read_uint16(rr+2); break; default: copy_len = rdlen; break; } if(copy_len) { if(!buffer_available(packet, copy_len)) { buffer_set_position(packet, oldpos); return 0; } if(copy_len > rdlen) return 1; /* assert of skip malformed */ buffer_write(packet, rr, copy_len); rr += copy_len; rdlen -= copy_len; } } /* write compressed rdata length */ buffer_write_u16_at(packet, rdpos, buffer_position(packet)-rdpos-2); if(total_added == 0) { size_t oldmaxlen = query->maxlen; query->maxlen = (query->tcp?TCP_MAX_MESSAGE_LEN:UDP_MAX_MESSAGE_LEN); if(query_overflow(query)) { query->maxlen = oldmaxlen; buffer_set_position(packet, oldpos); return 0; } query->maxlen = oldmaxlen; } else { if(query_overflow(query)) { /* we are past the maximum length */ buffer_set_position(packet, oldpos); return 0; } } return 1; } /* parse the serial number from the IXFR query */ static int parse_qserial(struct buffer* packet, uint32_t* qserial, size_t* snip_pos) { unsigned int i; uint16_t type, rdlen; /* we must have a SOA in the authority section */ if(NSCOUNT(packet) == 0) return 0; /* skip over the question section, we want only one */ buffer_set_position(packet, QHEADERSZ); if(QDCOUNT(packet) != 1) return 0; if(!packet_skip_rr(packet, 1)) return 0; /* set position to snip off the authority section */ *snip_pos = buffer_position(packet); /* skip over the authority section RRs until we find the SOA */ for(i=0; irdata_count < 3) return 0; if(rr->rdatas[2].data[0] < 4) return 0; return read_uint32(&rr->rdatas[2].data[1]); } /* get the current serial from the zone */ uint32_t zone_get_current_serial(struct zone* zone) { if(!zone || !zone->soa_rrset) return 0; if(zone->soa_rrset->rr_count == 0) return 0; if(zone->soa_rrset->rrs[0].rdata_count < 3) return 0; if(zone->soa_rrset->rrs[0].rdatas[2].data[0] < 4) return 0; return read_uint32(&zone->soa_rrset->rrs[0].rdatas[2].data[1]); } /* iterator over ixfr data. find first element, eg. oldest zone version * change. * The iterator can be started with the ixfr_data_first, but also with * ixfr_data_last, or with an existing ixfr_data element to start from. * Continue by using ixfr_data_next or ixfr_data_prev to ask for more elements * until that returns NULL. NULL because end of list or loop was detected. * The ixfr_data_prev uses a counter, start it at 0, it returns NULL when * a loop is detected. */ static struct ixfr_data* ixfr_data_first(struct zone_ixfr* ixfr) { struct ixfr_data* n; if(!ixfr || !ixfr->data || ixfr->data->count==0) return NULL; n = (struct ixfr_data*)rbtree_search(ixfr->data, &ixfr->oldest_serial); if(!n || n == (struct ixfr_data*)RBTREE_NULL) return NULL; return n; } /* iterator over ixfr data. find last element, eg. newest zone version * change. */ static struct ixfr_data* ixfr_data_last(struct zone_ixfr* ixfr) { struct ixfr_data* n; if(!ixfr || !ixfr->data || ixfr->data->count==0) return NULL; n = (struct ixfr_data*)rbtree_search(ixfr->data, &ixfr->newest_serial); if(!n || n == (struct ixfr_data*)RBTREE_NULL) return NULL; return n; } /* iterator over ixfr data. fetch next item. If loop or nothing, NULL */ static struct ixfr_data* ixfr_data_next(struct zone_ixfr* ixfr, struct ixfr_data* cur) { struct ixfr_data* n; if(!cur || cur == (struct ixfr_data*)RBTREE_NULL) return NULL; if(cur->oldserial == ixfr->newest_serial) return NULL; /* that was the last element */ n = (struct ixfr_data*)rbtree_next(&cur->node); if(n && n != (struct ixfr_data*)RBTREE_NULL && cur->newserial == n->oldserial) { /* the next rbtree item is the next ixfr data item */ return n; } /* If the next item is last of tree, and we have to loop around, * the search performs the lookup for the next item we need. * If the next item exists, but also is not connected, the search * finds the correct connected ixfr in the sorted tree. */ /* try searching for the correct ixfr data item */ n = (struct ixfr_data*)rbtree_search(ixfr->data, &cur->newserial); if(!n || n == (struct ixfr_data*)RBTREE_NULL) return NULL; return n; } /* iterator over ixfr data. fetch the previous item. If loop or nothing NULL.*/ static struct ixfr_data* ixfr_data_prev(struct zone_ixfr* ixfr, struct ixfr_data* cur, size_t* prevcount) { struct ixfr_data* prev; if(!cur || cur == (struct ixfr_data*)RBTREE_NULL) return NULL; if(cur->oldserial == ixfr->oldest_serial) return NULL; /* this was the first element */ prev = (struct ixfr_data*)rbtree_previous(&cur->node); if(!prev || prev == (struct ixfr_data*)RBTREE_NULL) { /* We hit the first element in the tree, go again * at the last one. Wrap around. */ prev = (struct ixfr_data*)rbtree_last(ixfr->data); } while(prev && prev != (struct ixfr_data*)RBTREE_NULL) { if(prev->newserial == cur->oldserial) { /* This is the correct matching previous ixfr data */ /* Increase the prevcounter every time the routine * returns an item, and if that becomes too large, we * are in a loop. in that case, stop. */ if(prevcount) { (*prevcount)++; if(*prevcount > ixfr->data->count + 12) { /* Larger than the max number of items * plus a small margin. The longest * chain is all the ixfr elements in * the tree. It loops. */ return NULL; } } return prev; } prev = (struct ixfr_data*)rbtree_previous(&prev->node); if(!prev || prev == (struct ixfr_data*)RBTREE_NULL) { /* We hit the first element in the tree, go again * at the last one. Wrap around. */ prev = (struct ixfr_data*)rbtree_last(ixfr->data); } } /* no elements in list */ return NULL; } /* connect IXFRs, return true if connected, false if not. Return last serial */ static int connect_ixfrs(struct zone_ixfr* ixfr, struct ixfr_data* data, uint32_t* end_serial) { struct ixfr_data* p = data; while(p != NULL) { struct ixfr_data* next = ixfr_data_next(ixfr, p); if(next) { if(p->newserial != next->oldserial) { /* These ixfrs are not connected, * during IXFR processing that could already * have been deleted, but we check here * in any case */ return 0; } } else { /* the chain of IXFRs ends in this serial number */ *end_serial = p->newserial; } p = next; } return 1; } /* Count length of next record in data */ static size_t count_rr_length(const uint8_t* data, size_t data_len, size_t current) { uint8_t label_size; uint16_t rdlen; size_t i = current; if(current >= data_len) return 0; /* pass the owner dname */ while(1) { if(i+1 > data_len) return 0; label_size = data[i++]; if(label_size == 0) { break; } else if((label_size &0xc0) != 0) { return 0; /* uncompressed dnames in IXFR store */ } else if(i+label_size > data_len) { return 0; } else { i += label_size; } } /* after dname, we pass type, class, ttl, rdatalen */ if(i+10 > data_len) return 0; i += 8; rdlen = read_uint16(data+i); i += 2; /* pass over the rdata */ if(i+((size_t)rdlen) > data_len) return 0; i += ((size_t)rdlen); return i-current; } /* Copy RRs into packet until packet full, return number RRs added */ static uint16_t ixfr_copy_rrs_into_packet(struct query* query, struct pktcompression* pcomp) { uint16_t total_added = 0; /* Copy RRs into the packet until the answer is full, * when an RR does not fit, we return and add no more. */ /* Add first SOA */ if(query->ixfr_count_newsoa < query->ixfr_end_data->newsoa_len) { /* the new SOA is added from the end_data segment, it is * the final SOA of the result of the IXFR */ if(ixfr_write_rr_pkt(query, query->packet, pcomp, query->ixfr_end_data->newsoa, query->ixfr_end_data->newsoa_len, total_added)) { query->ixfr_count_newsoa = query->ixfr_end_data->newsoa_len; total_added++; query->ixfr_pos_of_newsoa = buffer_position(query->packet); } else { /* cannot add another RR, so return */ return total_added; } } /* Add second SOA */ if(query->ixfr_count_oldsoa < query->ixfr_data->oldsoa_len) { if(ixfr_write_rr_pkt(query, query->packet, pcomp, query->ixfr_data->oldsoa, query->ixfr_data->oldsoa_len, total_added)) { query->ixfr_count_oldsoa = query->ixfr_data->oldsoa_len; total_added++; } else { /* cannot add another RR, so return */ return total_added; } } /* Add del data, with deleted RRs and a SOA */ while(query->ixfr_count_del < query->ixfr_data->del_len) { size_t rrlen = count_rr_length(query->ixfr_data->del, query->ixfr_data->del_len, query->ixfr_count_del); if(rrlen && ixfr_write_rr_pkt(query, query->packet, pcomp, query->ixfr_data->del + query->ixfr_count_del, rrlen, total_added)) { query->ixfr_count_del += rrlen; total_added++; } else { /* the next record does not fit in the remaining * space of the packet */ return total_added; } } /* Add add data, with added RRs and a SOA */ while(query->ixfr_count_add < query->ixfr_data->add_len) { size_t rrlen = count_rr_length(query->ixfr_data->add, query->ixfr_data->add_len, query->ixfr_count_add); if(rrlen && ixfr_write_rr_pkt(query, query->packet, pcomp, query->ixfr_data->add + query->ixfr_count_add, rrlen, total_added)) { query->ixfr_count_add += rrlen; total_added++; } else { /* the next record does not fit in the remaining * space of the packet */ return total_added; } } return total_added; } query_state_type query_ixfr(struct nsd *nsd, struct query *query) { uint16_t total_added = 0; struct pktcompression pcomp; if (query->ixfr_is_done) return QUERY_PROCESSED; pktcompression_init(&pcomp); if (query->maxlen > IXFR_MAX_MESSAGE_LEN) query->maxlen = IXFR_MAX_MESSAGE_LEN; assert(!query_overflow(query)); /* only keep running values for most packets */ query->tsig_prepare_it = 0; query->tsig_update_it = 1; if(query->tsig_sign_it) { /* prepare for next updates */ query->tsig_prepare_it = 1; query->tsig_sign_it = 0; } if (query->ixfr_data == NULL) { /* This is the first packet, process the query further */ uint32_t qserial = 0, current_serial = 0, end_serial = 0; struct zone* zone; struct ixfr_data* ixfr_data; size_t oldpos; STATUP(nsd, rixfr); /* parse the serial number from the IXFR request */ oldpos = QHEADERSZ; if(!parse_qserial(query->packet, &qserial, &oldpos)) { NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); buffer_set_position(query->packet, oldpos); RCODE_SET(query->packet, RCODE_FORMAT); return QUERY_PROCESSED; } NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); buffer_set_position(query->packet, oldpos); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "ixfr query routine, %s IXFR=%u", dname_to_string(query->qname, NULL), (unsigned)qserial)); /* do we have an IXFR with this serial number? If not, serve AXFR */ zone = namedb_find_zone(nsd->db, query->qname); if(!zone) { /* no zone is present */ RCODE_SET(query->packet, RCODE_NOTAUTH); return QUERY_PROCESSED; } ZTATUP(nsd, zone, rixfr); /* if the query is for same or newer serial than our current * serial, then serve a single SOA with our current serial */ current_serial = zone_get_current_serial(zone); if(compare_serial(qserial, current_serial) >= 0) { if(!zone->soa_rrset || zone->soa_rrset->rr_count != 1){ RCODE_SET(query->packet, RCODE_SERVFAIL); return QUERY_PROCESSED; } query_add_compression_domain(query, zone->apex, QHEADERSZ); if(packet_encode_rr(query, zone->apex, &zone->soa_rrset->rrs[0], zone->soa_rrset->rrs[0].ttl)) { ANCOUNT_SET(query->packet, 1); } else { RCODE_SET(query->packet, RCODE_SERVFAIL); } AA_SET(query->packet); query_clear_compression_tables(query); if(query->tsig.status == TSIG_OK) query->tsig_sign_it = 1; return QUERY_PROCESSED; } if(!zone->ixfr) { /* we have no ixfr information for the zone, make an AXFR */ if(query->tsig_prepare_it) query->tsig_sign_it = 1; VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, no ixfr info for zone: %s", dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } ixfr_data = zone_ixfr_find_serial(zone->ixfr, qserial); if(!ixfr_data) { /* the specific version is not available, make an AXFR */ if(query->tsig_prepare_it) query->tsig_sign_it = 1; VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, no history for serial for zone: %s", dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } /* see if the IXFRs connect to the next IXFR, and if it ends * at the current served zone, if not, AXFR */ if(!connect_ixfrs(zone->ixfr, ixfr_data, &end_serial) || end_serial != current_serial) { if(query->tsig_prepare_it) query->tsig_sign_it = 1; VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, incomplete history from this serial for zone: %s", dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } query->zone = zone; query->ixfr_data = ixfr_data; query->ixfr_is_done = 0; /* set up to copy the last version's SOA as first SOA */ query->ixfr_end_data = ixfr_data_last(zone->ixfr); query->ixfr_count_newsoa = 0; query->ixfr_count_oldsoa = 0; query->ixfr_count_del = 0; query->ixfr_count_add = 0; query->ixfr_pos_of_newsoa = 0; /* the query name can be compressed to */ pktcompression_insert_with_labels(&pcomp, buffer_at(query->packet, QHEADERSZ), query->qname->name_size, QHEADERSZ); if(query->tsig.status == TSIG_OK) { query->tsig_sign_it = 1; /* sign first packet in stream */ } } else { /* * Query name need not be repeated after the * first response packet. */ buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); query_prepare_response(query); } total_added = ixfr_copy_rrs_into_packet(query, &pcomp); while(query->ixfr_count_add >= query->ixfr_data->add_len) { struct ixfr_data* next = ixfr_data_next(query->zone->ixfr, query->ixfr_data); /* finished the ixfr_data */ if(next) { /* move to the next IXFR */ query->ixfr_data = next; /* we need to skip the SOA records, set len to done*/ /* the newsoa count is already done, at end_data len */ query->ixfr_count_oldsoa = next->oldsoa_len; /* and then set up to copy the del and add sections */ query->ixfr_count_del = 0; query->ixfr_count_add = 0; total_added += ixfr_copy_rrs_into_packet(query, &pcomp); } else { /* we finished the IXFR */ /* sign the last packet */ query->tsig_sign_it = 1; query->ixfr_is_done = 1; break; } } /* return the answer */ AA_SET(query->packet); ANCOUNT_SET(query->packet, total_added); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); if(!query->tcp && !query->ixfr_is_done) { TC_SET(query->packet); if(query->ixfr_pos_of_newsoa) { /* if we recorded the newsoa in the result, snip off * the rest of the response, the RFC1995 response for * when it does not fit is only the latest SOA */ buffer_set_position(query->packet, query->ixfr_pos_of_newsoa); ANCOUNT_SET(query->packet, 1); } query->ixfr_is_done = 1; } /* check if it needs tsig signatures */ if(query->tsig.status == TSIG_OK) { #if IXFR_TSIG_SIGN_EVERY_NTH > 0 if(query->tsig.updates_since_last_prepare >= IXFR_TSIG_SIGN_EVERY_NTH) { #endif query->tsig_sign_it = 1; #if IXFR_TSIG_SIGN_EVERY_NTH > 0 } #endif } pktcompression_freeup(&pcomp); return QUERY_IN_IXFR; } /* free ixfr_data structure */ static void ixfr_data_free(struct ixfr_data* data) { if(!data) return; free(data->newsoa); free(data->oldsoa); free(data->del); free(data->add); free(data->log_str); free(data); } size_t ixfr_data_size(struct ixfr_data* data) { return sizeof(struct ixfr_data) + data->newsoa_len + data->oldsoa_len + data->del_len + data->add_len; } struct ixfr_store* ixfr_store_start(struct zone* zone, struct ixfr_store* ixfr_store_mem) { struct ixfr_store* ixfr_store = ixfr_store_mem; memset(ixfr_store, 0, sizeof(*ixfr_store)); ixfr_store->zone = zone; ixfr_store->data = xalloc_zero(sizeof(*ixfr_store->data)); return ixfr_store; } void ixfr_store_cancel(struct ixfr_store* ixfr_store) { ixfr_store->cancelled = 1; ixfr_data_free(ixfr_store->data); ixfr_store->data = NULL; } void ixfr_store_free(struct ixfr_store* ixfr_store) { if(!ixfr_store) return; ixfr_data_free(ixfr_store->data); } /* make space in record data for the new size, grows the allocation */ static void ixfr_rrs_make_space(uint8_t** rrs, size_t* len, size_t* capacity, size_t added) { size_t newsize = 0; if(*rrs == NULL) { newsize = IXFR_STORE_INITIAL_SIZE; } else { if(*len + added <= *capacity) return; /* already enough space */ newsize = (*capacity)*2; } if(*len + added > newsize) newsize = *len + added; if(*rrs == NULL) { *rrs = xalloc(newsize); } else { *rrs = xrealloc(*rrs, newsize); } *capacity = newsize; } /* put new SOA record after delrrs and addrrs */ static void ixfr_put_newsoa(struct ixfr_store* ixfr_store, uint8_t** rrs, size_t* len, size_t* capacity) { uint8_t* soa; size_t soa_len; if(!ixfr_store->data) return; /* data should be nonNULL, we are not cancelled */ soa = ixfr_store->data->newsoa; soa_len= ixfr_store->data->newsoa_len; ixfr_rrs_make_space(rrs, len, capacity, soa_len); if(!*rrs || *len + soa_len > *capacity) { log_msg(LOG_ERR, "ixfr_store addrr: cannot allocate space"); ixfr_store_cancel(ixfr_store); return; } memmove(*rrs + *len, soa, soa_len); *len += soa_len; } /* trim unused storage from the rrs data */ static void ixfr_trim_capacity(uint8_t** rrs, size_t* len, size_t* capacity) { if(*rrs == NULL) return; if(*capacity == *len) return; *rrs = xrealloc(*rrs, *len); *capacity = *len; } void ixfr_store_finish_data(struct ixfr_store* ixfr_store) { if(ixfr_store->data_trimmed) return; ixfr_store->data_trimmed = 1; /* put new serial SOA record after delrrs and addrrs */ ixfr_put_newsoa(ixfr_store, &ixfr_store->data->del, &ixfr_store->data->del_len, &ixfr_store->del_capacity); ixfr_put_newsoa(ixfr_store, &ixfr_store->data->add, &ixfr_store->data->add_len, &ixfr_store->add_capacity); /* trim the data in the store, the overhead from capacity is * removed */ if(!ixfr_store->data) return; /* data should be nonNULL, we are not cancelled */ ixfr_trim_capacity(&ixfr_store->data->del, &ixfr_store->data->del_len, &ixfr_store->del_capacity); ixfr_trim_capacity(&ixfr_store->data->add, &ixfr_store->data->add_len, &ixfr_store->add_capacity); } void ixfr_store_finish(struct ixfr_store* ixfr_store, struct nsd* nsd, char* log_buf) { if(ixfr_store->cancelled) { ixfr_store_free(ixfr_store); return; } ixfr_store_finish_data(ixfr_store); if(ixfr_store->cancelled) { ixfr_store_free(ixfr_store); return; } if(log_buf && !ixfr_store->data->log_str) ixfr_store->data->log_str = strdup(log_buf); /* store the data in the zone */ if(!ixfr_store->zone->ixfr) ixfr_store->zone->ixfr = zone_ixfr_create(nsd); zone_ixfr_make_space(ixfr_store->zone->ixfr, ixfr_store->zone, ixfr_store->data, ixfr_store); if(ixfr_store->cancelled) { ixfr_store_free(ixfr_store); return; } zone_ixfr_add(ixfr_store->zone->ixfr, ixfr_store->data, 1); ixfr_store->data = NULL; /* free structure */ ixfr_store_free(ixfr_store); } /* read SOA rdata section for SOA storage */ static int read_soa_rdata(struct buffer* packet, uint8_t* primns, int* primns_len, uint8_t* email, int* email_len, uint32_t* serial, uint32_t* refresh, uint32_t* retry, uint32_t* expire, uint32_t* minimum, size_t* sz) { if(!(*primns_len = dname_make_wire_from_packet(primns, packet, 1))) { log_msg(LOG_ERR, "ixfr_store: cannot parse soa nsname in packet"); return 0; } *sz += *primns_len; if(!(*email_len = dname_make_wire_from_packet(email, packet, 1))) { log_msg(LOG_ERR, "ixfr_store: cannot parse soa maintname in packet"); return 0; } *sz += *email_len; *serial = buffer_read_u32(packet); *sz += 4; *refresh = buffer_read_u32(packet); *sz += 4; *retry = buffer_read_u32(packet); *sz += 4; *expire = buffer_read_u32(packet); *sz += 4; *minimum = buffer_read_u32(packet); *sz += 4; return 1; } /* store SOA record data in memory buffer */ static void store_soa(uint8_t* soa, struct zone* zone, uint32_t ttl, uint16_t rdlen_uncompressed, uint8_t* primns, int primns_len, uint8_t* email, int email_len, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) { uint8_t* sp = soa; memmove(sp, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size); sp += domain_dname(zone->apex)->name_size; write_uint16(sp, TYPE_SOA); sp += 2; write_uint16(sp, CLASS_IN); sp += 2; write_uint32(sp, ttl); sp += 4; write_uint16(sp, rdlen_uncompressed); sp += 2; memmove(sp, primns, primns_len); sp += primns_len; memmove(sp, email, email_len); sp += email_len; write_uint32(sp, serial); sp += 4; write_uint32(sp, refresh); sp += 4; write_uint32(sp, retry); sp += 4; write_uint32(sp, expire); sp += 4; write_uint32(sp, minimum); } void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, uint32_t ttl, struct buffer* packet, size_t rrlen) { size_t oldpos, sz = 0; uint32_t serial, refresh, retry, expire, minimum; uint16_t rdlen_uncompressed; int primns_len = 0, email_len = 0; uint8_t primns[MAXDOMAINLEN + 1], email[MAXDOMAINLEN + 1]; if(ixfr_store->cancelled) return; if(ixfr_store->data->newsoa) { free(ixfr_store->data->newsoa); ixfr_store->data->newsoa = NULL; ixfr_store->data->newsoa_len = 0; } oldpos = buffer_position(packet); /* calculate the length */ sz = domain_dname(ixfr_store->zone->apex)->name_size; sz += 2 /* type */ + 2 /* class */ + 4 /* ttl */ + 2 /* rdlen */; if(!buffer_available(packet, rrlen)) { /* not possible already parsed, but fail nicely anyway */ log_msg(LOG_ERR, "ixfr_store: not enough rdata space in packet"); ixfr_store_cancel(ixfr_store); buffer_set_position(packet, oldpos); return; } if(!read_soa_rdata(packet, primns, &primns_len, email, &email_len, &serial, &refresh, &retry, &expire, &minimum, &sz)) { log_msg(LOG_ERR, "ixfr_store newsoa: cannot parse packet"); ixfr_store_cancel(ixfr_store); buffer_set_position(packet, oldpos); return; } rdlen_uncompressed = primns_len + email_len + 4 + 4 + 4 + 4 + 4; ixfr_store->data->newserial = serial; /* store the soa record */ ixfr_store->data->newsoa = xalloc(sz); ixfr_store->data->newsoa_len = sz; store_soa(ixfr_store->data->newsoa, ixfr_store->zone, ttl, rdlen_uncompressed, primns, primns_len, email, email_len, serial, refresh, retry, expire, minimum); buffer_set_position(packet, oldpos); } void ixfr_store_add_oldsoa(struct ixfr_store* ixfr_store, uint32_t ttl, struct buffer* packet, size_t rrlen) { size_t oldpos, sz = 0; uint32_t serial, refresh, retry, expire, minimum; uint16_t rdlen_uncompressed; int primns_len = 0, email_len = 0; uint8_t primns[MAXDOMAINLEN + 1], email[MAXDOMAINLEN + 1]; if(ixfr_store->cancelled) return; if(ixfr_store->data->oldsoa) { free(ixfr_store->data->oldsoa); ixfr_store->data->oldsoa = NULL; ixfr_store->data->oldsoa_len = 0; } /* we have the old SOA and thus we are sure it is an IXFR, make space*/ zone_ixfr_make_space(ixfr_store->zone->ixfr, ixfr_store->zone, ixfr_store->data, ixfr_store); if(ixfr_store->cancelled) return; oldpos = buffer_position(packet); /* calculate the length */ sz = domain_dname(ixfr_store->zone->apex)->name_size; sz += 2 /*type*/ + 2 /*class*/ + 4 /*ttl*/ + 2 /*rdlen*/; if(!buffer_available(packet, rrlen)) { /* not possible already parsed, but fail nicely anyway */ log_msg(LOG_ERR, "ixfr_store oldsoa: not enough rdata space in packet"); ixfr_store_cancel(ixfr_store); buffer_set_position(packet, oldpos); return; } if(!read_soa_rdata(packet, primns, &primns_len, email, &email_len, &serial, &refresh, &retry, &expire, &minimum, &sz)) { log_msg(LOG_ERR, "ixfr_store oldsoa: cannot parse packet"); ixfr_store_cancel(ixfr_store); buffer_set_position(packet, oldpos); return; } rdlen_uncompressed = primns_len + email_len + 4 + 4 + 4 + 4 + 4; ixfr_store->data->oldserial = serial; /* store the soa record */ ixfr_store->data->oldsoa = xalloc(sz); ixfr_store->data->oldsoa_len = sz; store_soa(ixfr_store->data->oldsoa, ixfr_store->zone, ttl, rdlen_uncompressed, primns, primns_len, email, email_len, serial, refresh, retry, expire, minimum); buffer_set_position(packet, oldpos); } /* store RR in data segment */ static int ixfr_putrr(const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num, uint8_t** rrs, size_t* rrs_len, size_t* rrs_capacity) { size_t rdlen_uncompressed, sz; uint8_t* sp; int i; /* find rdatalen */ rdlen_uncompressed = 0; for(i=0; iname_size; } else { rdlen_uncompressed += rdatas[i].data[0]; } } sz = dname->name_size + 2 /*type*/ + 2 /*class*/ + 4 /*ttl*/ + 2 /*rdlen*/ + rdlen_uncompressed; /* store RR in IXFR data */ ixfr_rrs_make_space(rrs, rrs_len, rrs_capacity, sz); if(!*rrs || *rrs_len + sz > *rrs_capacity) { return 0; } /* copy data into add */ sp = *rrs + *rrs_len; *rrs_len += sz; memmove(sp, dname_name(dname), dname->name_size); sp += dname->name_size; write_uint16(sp, type); sp += 2; write_uint16(sp, klass); sp += 2; write_uint32(sp, ttl); sp += 4; write_uint16(sp, rdlen_uncompressed); sp += 2; for(i=0; iname_size); sp += domain_dname(rdatas[i].domain)->name_size; } else { memmove(sp, &rdatas[i].data[1], rdatas[i].data[0]); sp += rdatas[i].data[0]; } } return 1; } void ixfr_store_putrr(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, struct buffer* packet, uint16_t rrlen, struct region* temp_region, uint8_t** rrs, size_t* rrs_len, size_t* rrs_capacity) { domain_table_type *temptable; rdata_atom_type *rdatas; ssize_t rdata_num; size_t oldpos; if(ixfr_store->cancelled) return; /* The SOA data is stored with separate calls. And then appended * during the finish operation. We do not have to store it here * when called from difffile's IXFR processing with type SOA. */ if(type == TYPE_SOA) return; /* make space for these RRs we have now; basically once we * grow beyond the current allowed amount an older IXFR is deleted. */ zone_ixfr_make_space(ixfr_store->zone->ixfr, ixfr_store->zone, ixfr_store->data, ixfr_store); if(ixfr_store->cancelled) return; /* parse rdata */ oldpos = buffer_position(packet); temptable = domain_table_create(temp_region); rdata_num = rdata_wireformat_to_rdata_atoms(temp_region, temptable, type, rrlen, packet, &rdatas); buffer_set_position(packet, oldpos); if(rdata_num == -1) { log_msg(LOG_ERR, "ixfr_store addrr: cannot parse packet"); ixfr_store_cancel(ixfr_store); return; } if(!ixfr_putrr(dname, type, klass, ttl, rdatas, rdata_num, rrs, rrs_len, rrs_capacity)) { log_msg(LOG_ERR, "ixfr_store addrr: cannot allocate space"); ixfr_store_cancel(ixfr_store); return; } } void ixfr_store_delrr(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, struct buffer* packet, uint16_t rrlen, struct region* temp_region) { if(ixfr_store->cancelled) return; ixfr_store_putrr(ixfr_store, dname, type, klass, ttl, packet, rrlen, temp_region, &ixfr_store->data->del, &ixfr_store->data->del_len, &ixfr_store->del_capacity); } void ixfr_store_addrr(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, struct buffer* packet, uint16_t rrlen, struct region* temp_region) { if(ixfr_store->cancelled) return; ixfr_store_putrr(ixfr_store, dname, type, klass, ttl, packet, rrlen, temp_region, &ixfr_store->data->add, &ixfr_store->data->add_len, &ixfr_store->add_capacity); } int ixfr_store_addrr_rdatas(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num) { if(ixfr_store->cancelled) return 1; if(type == TYPE_SOA) return 1; return ixfr_putrr(dname, type, klass, ttl, rdatas, rdata_num, &ixfr_store->data->add, &ixfr_store->data->add_len, &ixfr_store->add_capacity); } int ixfr_store_add_newsoa_rdatas(struct ixfr_store* ixfr_store, const struct dname* dname, uint16_t type, uint16_t klass, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num) { size_t capacity = 0; uint32_t serial; if(ixfr_store->cancelled) return 1; if(rdata_num < 2 || rdata_atom_size(rdatas[2]) < 4) return 0; memcpy(&serial, rdata_atom_data(rdatas[2]), sizeof(serial)); ixfr_store->data->newserial = ntohl(serial); if(!ixfr_putrr(dname, type, klass, ttl, rdatas, rdata_num, &ixfr_store->data->newsoa, &ixfr_store->data->newsoa_len, &ixfr_store->add_capacity)) return 0; ixfr_trim_capacity(&ixfr_store->data->newsoa, &ixfr_store->data->newsoa_len, &capacity); return 1; } /* store rr uncompressed */ int ixfr_storerr_uncompressed(uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len, uint8_t** rrs, size_t* rrs_len, size_t* rrs_capacity) { size_t sz; uint8_t* sp; /* find rdatalen */ sz = dname_len + 2 /*type*/ + 2 /*class*/ + 4 /*ttl*/ + 2 /*rdlen*/ + rdata_len; /* store RR in IXFR data */ ixfr_rrs_make_space(rrs, rrs_len, rrs_capacity, sz); if(!*rrs || *rrs_len + sz > *rrs_capacity) { return 0; } /* copy data into add */ sp = *rrs + *rrs_len; *rrs_len += sz; memmove(sp, dname, dname_len); sp += dname_len; write_uint16(sp, type); sp += 2; write_uint16(sp, klass); sp += 2; write_uint32(sp, ttl); sp += 4; write_uint16(sp, rdata_len); sp += 2; memmove(sp, rdata, rdata_len); return 1; } int ixfr_store_delrr_uncompressed(struct ixfr_store* ixfr_store, uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len) { if(ixfr_store->cancelled) return 1; if(type == TYPE_SOA) return 1; return ixfr_storerr_uncompressed(dname, dname_len, type, klass, ttl, rdata, rdata_len, &ixfr_store->data->del, &ixfr_store->data->del_len, &ixfr_store->del_capacity); } static size_t skip_dname(uint8_t* rdata, size_t rdata_len) { for (size_t index=0; index < rdata_len; ) { uint8_t label_size = rdata[index]; if (label_size == 0) { return index + 1; } else if ((label_size & 0xc0) != 0) { return (index + 1 < rdata_len) ? index + 2 : 0; } else { /* loop breaks if index exceeds rdata_len */ index += label_size + 1; } } return 0; } int ixfr_store_oldsoa_uncompressed(struct ixfr_store* ixfr_store, uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len) { size_t capacity = 0; if(ixfr_store->cancelled) return 1; if(!ixfr_storerr_uncompressed(dname, dname_len, type, klass, ttl, rdata, rdata_len, &ixfr_store->data->oldsoa, &ixfr_store->data->oldsoa_len, &capacity)) return 0; { uint32_t serial; size_t index, count = 0; if (!(count = skip_dname(rdata, rdata_len))) return 0; index = count; if (!(count = skip_dname(rdata+index, rdata_len-index))) return 0; index += count; if (rdata_len - index < 4) return 0; memcpy(&serial, rdata+index, sizeof(serial)); ixfr_store->data->oldserial = ntohl(serial); } ixfr_trim_capacity(&ixfr_store->data->oldsoa, &ixfr_store->data->oldsoa_len, &capacity); return 1; } int zone_is_ixfr_enabled(struct zone* zone) { return zone->opts->pattern->store_ixfr; } /* compare ixfr elements */ static int ixfrcompare(const void* x, const void* y) { uint32_t* serial_x = (uint32_t*)x; uint32_t* serial_y = (uint32_t*)y; if(*serial_x < *serial_y) return -1; if(*serial_x > *serial_y) return 1; return 0; } struct zone_ixfr* zone_ixfr_create(struct nsd* nsd) { struct zone_ixfr* ixfr = xalloc_zero(sizeof(struct zone_ixfr)); ixfr->data = rbtree_create(nsd->region, &ixfrcompare); return ixfr; } /* traverse tree postorder */ static void ixfr_tree_del(struct rbnode* node) { if(node == NULL || node == RBTREE_NULL) return; ixfr_tree_del(node->left); ixfr_tree_del(node->right); ixfr_data_free((struct ixfr_data*)node); } /* clear the ixfr data elements */ static void zone_ixfr_clear(struct zone_ixfr* ixfr) { if(!ixfr) return; if(ixfr->data) { ixfr_tree_del(ixfr->data->root); ixfr->data->root = RBTREE_NULL; ixfr->data->count = 0; } ixfr->total_size = 0; ixfr->oldest_serial = 0; ixfr->newest_serial = 0; } void zone_ixfr_free(struct zone_ixfr* ixfr) { if(!ixfr) return; if(ixfr->data) { ixfr_tree_del(ixfr->data->root); ixfr->data = NULL; } free(ixfr); } void ixfr_store_delixfrs(struct zone* zone) { if(!zone) return; zone_ixfr_clear(zone->ixfr); } /* remove the oldest data entry from the ixfr versions */ static void zone_ixfr_remove_oldest(struct zone_ixfr* ixfr) { if(ixfr->data->count > 0) { struct ixfr_data* oldest = ixfr_data_first(ixfr); if(ixfr->oldest_serial == oldest->oldserial) { if(ixfr->data->count > 1) { struct ixfr_data* next = ixfr_data_next(ixfr, oldest); assert(next); if(next) ixfr->oldest_serial = next->oldserial; else ixfr->oldest_serial = oldest->newserial; } else { ixfr->oldest_serial = 0; } } if(ixfr->newest_serial == oldest->oldserial) { ixfr->newest_serial = 0; } zone_ixfr_remove(ixfr, oldest); } } void zone_ixfr_make_space(struct zone_ixfr* ixfr, struct zone* zone, struct ixfr_data* data, struct ixfr_store* ixfr_store) { size_t addsize; if(!ixfr || !data) return; if(zone->opts->pattern->ixfr_number == 0) { ixfr_store_cancel(ixfr_store); return; } /* Check the number of IXFRs allowed for this zone, if too many, * shorten the number to make space for another one */ while(ixfr->data->count >= zone->opts->pattern->ixfr_number) { zone_ixfr_remove_oldest(ixfr); } if(zone->opts->pattern->ixfr_size == 0) { /* no size limits imposed */ return; } /* Check the size of the current added data element 'data', and * see if that overflows the maximum storage size for IXFRs for * this zone, and if so, delete the oldest IXFR to make space */ addsize = ixfr_data_size(data); while(ixfr->data->count > 0 && ixfr->total_size + addsize > zone->opts->pattern->ixfr_size) { zone_ixfr_remove_oldest(ixfr); } /* if deleting the oldest elements does not work, then this * IXFR is too big to store and we cancel it */ if(ixfr->data->count == 0 && ixfr->total_size + addsize > zone->opts->pattern->ixfr_size) { ixfr_store_cancel(ixfr_store); return; } } void zone_ixfr_remove(struct zone_ixfr* ixfr, struct ixfr_data* data) { rbtree_delete(ixfr->data, data->node.key); ixfr->total_size -= ixfr_data_size(data); ixfr_data_free(data); } void zone_ixfr_add(struct zone_ixfr* ixfr, struct ixfr_data* data, int isnew) { memset(&data->node, 0, sizeof(data->node)); if(ixfr->data->count == 0) { ixfr->oldest_serial = data->oldserial; ixfr->newest_serial = data->oldserial; } else if(isnew) { /* newest entry is last there is */ ixfr->newest_serial = data->oldserial; } else { /* added older entry, before the others */ ixfr->oldest_serial = data->oldserial; } data->node.key = &data->oldserial; rbtree_insert(ixfr->data, &data->node); ixfr->total_size += ixfr_data_size(data); } struct ixfr_data* zone_ixfr_find_serial(struct zone_ixfr* ixfr, uint32_t qserial) { struct ixfr_data* data; if(!ixfr) return NULL; if(!ixfr->data) return NULL; data = (struct ixfr_data*)rbtree_search(ixfr->data, &qserial); if(data) { assert(data->oldserial == qserial); return data; } /* not found */ return NULL; } /* calculate the number of files we want */ static int ixfr_target_number_files(struct zone* zone) { int dest_num_files; if(!zone->ixfr || !zone->ixfr->data) return 0; if(!zone_is_ixfr_enabled(zone)) return 0; /* if we store ixfr, it is the configured number of files */ dest_num_files = (int)zone->opts->pattern->ixfr_number; /* but if the number of available transfers is smaller, store less */ if(dest_num_files > (int)zone->ixfr->data->count) dest_num_files = (int)zone->ixfr->data->count; return dest_num_files; } /* create ixfrfile name in buffer for file_num. The num is 1 .. number. */ static void make_ixfr_name(char* buf, size_t len, const char* zfile, int file_num) { if(file_num == 1) snprintf(buf, len, "%s.ixfr", zfile); else snprintf(buf, len, "%s.ixfr.%d", zfile, file_num); } /* create temp ixfrfile name in buffer for file_num. The num is 1 .. number. */ static void make_ixfr_name_temp(char* buf, size_t len, const char* zfile, int file_num, int temp) { if(file_num == 1) snprintf(buf, len, "%s.ixfr%s", zfile, (temp?".temp":"")); else snprintf(buf, len, "%s.ixfr.%d%s", zfile, file_num, (temp?".temp":"")); } /* see if ixfr file exists */ static int ixfr_file_exists_ctmp(const char* zfile, int file_num, int temp) { struct stat statbuf; char ixfrfile[1024+24]; make_ixfr_name_temp(ixfrfile, sizeof(ixfrfile), zfile, file_num, temp); memset(&statbuf, 0, sizeof(statbuf)); if(stat(ixfrfile, &statbuf) < 0) { if(errno == ENOENT) return 0; /* file is not usable */ return 0; } return 1; } int ixfr_file_exists(const char* zfile, int file_num) { return ixfr_file_exists_ctmp(zfile, file_num, 0); } /* see if ixfr file exists */ static int ixfr_file_exists_temp(const char* zfile, int file_num) { return ixfr_file_exists_ctmp(zfile, file_num, 1); } /* unlink an ixfr file */ static int ixfr_unlink_it_ctmp(const char* zname, const char* zfile, int file_num, int silent_enoent, int temp) { char ixfrfile[1024+24]; make_ixfr_name_temp(ixfrfile, sizeof(ixfrfile), zfile, file_num, temp); VERBOSITY(3, (LOG_INFO, "delete zone %s IXFR data file %s", zname, ixfrfile)); if(unlink(ixfrfile) < 0) { if(silent_enoent && errno == ENOENT) return 0; log_msg(LOG_ERR, "error to delete file %s: %s", ixfrfile, strerror(errno)); return 0; } return 1; } int ixfr_unlink_it(const char* zname, const char* zfile, int file_num, int silent_enoent) { return ixfr_unlink_it_ctmp(zname, zfile, file_num, silent_enoent, 0); } /* unlink an ixfr file */ static int ixfr_unlink_it_temp(const char* zname, const char* zfile, int file_num, int silent_enoent) { return ixfr_unlink_it_ctmp(zname, zfile, file_num, silent_enoent, 1); } /* read ixfr file header */ int ixfr_read_file_header(const char* zname, const char* zfile, int file_num, uint32_t* oldserial, uint32_t* newserial, size_t* data_size, int enoent_is_err) { char ixfrfile[1024+24]; char buf[1024]; FILE* in; int num_lines = 0, got_old = 0, got_new = 0, got_datasize = 0; make_ixfr_name(ixfrfile, sizeof(ixfrfile), zfile, file_num); in = fopen(ixfrfile, "r"); if(!in) { if((errno == ENOENT && enoent_is_err) || (errno != ENOENT)) log_msg(LOG_ERR, "could not open %s: %s", ixfrfile, strerror(errno)); return 0; } /* read about 10 lines, this is where the header is */ while(!(got_old && got_new && got_datasize) && num_lines < 10) { buf[0]=0; buf[sizeof(buf)-1]=0; if(!fgets(buf, sizeof(buf), in)) { log_msg(LOG_ERR, "could not read %s: %s", ixfrfile, strerror(errno)); fclose(in); return 0; } num_lines++; if(buf[0]!=0 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]=0; if(strncmp(buf, "; zone ", 7) == 0) { if(strcmp(buf+7, zname) != 0) { log_msg(LOG_ERR, "file has wrong zone, expected zone %s, but found %s in file %s", zname, buf+7, ixfrfile); fclose(in); return 0; } } else if(strncmp(buf, "; from_serial ", 14) == 0) { *oldserial = atoi(buf+14); got_old = 1; } else if(strncmp(buf, "; to_serial ", 12) == 0) { *newserial = atoi(buf+12); got_new = 1; } else if(strncmp(buf, "; data_size ", 12) == 0) { *data_size = (size_t)atoi(buf+12); got_datasize = 1; } } fclose(in); if(!got_old) return 0; if(!got_new) return 0; if(!got_datasize) return 0; return 1; } /* delete rest ixfr files, that are after the current item */ static void ixfr_delete_rest_files(struct zone* zone, struct ixfr_data* from, const char* zfile, int temp) { size_t prevcount = 0; struct ixfr_data* data = from; while(data) { if(data->file_num != 0) { (void)ixfr_unlink_it_ctmp(zone->opts->name, zfile, data->file_num, 0, temp); data->file_num = 0; } data = ixfr_data_prev(zone->ixfr, data, &prevcount); } } void ixfr_delete_superfluous_files(struct zone* zone, const char* zfile, int dest_num_files) { int i = dest_num_files + 1; if(!ixfr_file_exists(zfile, i)) return; while(ixfr_unlink_it(zone->opts->name, zfile, i, 1)) { i++; } } int ixfr_rename_it(const char* zname, const char* zfile, int oldnum, int oldtemp, int newnum, int newtemp) { char ixfrfile_old[1024+24]; char ixfrfile_new[1024+24]; make_ixfr_name_temp(ixfrfile_old, sizeof(ixfrfile_old), zfile, oldnum, oldtemp); make_ixfr_name_temp(ixfrfile_new, sizeof(ixfrfile_new), zfile, newnum, newtemp); VERBOSITY(3, (LOG_INFO, "rename zone %s IXFR data file %s to %s", zname, ixfrfile_old, ixfrfile_new)); if(rename(ixfrfile_old, ixfrfile_new) < 0) { log_msg(LOG_ERR, "error to rename file %s: %s", ixfrfile_old, strerror(errno)); return 0; } return 1; } /* delete if we have too many items in memory */ static void ixfr_delete_memory_items(struct zone* zone, int dest_num_files) { if(!zone->ixfr || !zone->ixfr->data) return; if(dest_num_files == (int)zone->ixfr->data->count) return; if(dest_num_files > (int)zone->ixfr->data->count) { /* impossible, dest_num_files should be smaller */ return; } /* delete oldest ixfr, until we have dest_num_files entries */ while(dest_num_files < (int)zone->ixfr->data->count) { zone_ixfr_remove_oldest(zone->ixfr); } } /* rename the ixfr files that need to change name */ static int ixfr_rename_files(struct zone* zone, const char* zfile, int dest_num_files) { struct ixfr_data* data, *startspot = NULL; size_t prevcount = 0; int destnum; if(!zone->ixfr || !zone->ixfr->data) return 1; /* the oldest file is at the largest number */ data = ixfr_data_first(zone->ixfr); destnum = dest_num_files; if(!data) return 1; /* nothing to do */ if(data->file_num == destnum) return 1; /* nothing to do for rename */ /* rename the files to temporary files, because otherwise the * items would overwrite each other when the list touches itself. * On fail, the temporary files are removed and we end up with * the newly written data plus the remaining files, in order. * Thus, start the temporary rename at the oldest, then rename * to the final names starting from the newest. */ while(data && data->file_num != 0) { /* if existing file at temporary name, delete that */ if(ixfr_file_exists_temp(zfile, data->file_num)) { (void)ixfr_unlink_it_temp(zone->opts->name, zfile, data->file_num, 0); } /* rename to temporary name */ if(!ixfr_rename_it(zone->opts->name, zfile, data->file_num, 0, data->file_num, 1)) { /* failure, we cannot store files */ /* delete the renamed files */ ixfr_delete_rest_files(zone, data, zfile, 1); return 0; } /* the next cycle should start at the newest file that * has been renamed to a temporary name */ startspot = data; data = ixfr_data_next(zone->ixfr, data); destnum--; } /* rename the files to their final name position */ data = startspot; while(data && data->file_num != 0) { destnum++; /* if there is an existing file, delete it */ if(ixfr_file_exists(zfile, destnum)) { (void)ixfr_unlink_it(zone->opts->name, zfile, destnum, 0); } if(!ixfr_rename_it(zone->opts->name, zfile, data->file_num, 1, destnum, 0)) { /* failure, we cannot store files */ ixfr_delete_rest_files(zone, data, zfile, 1); /* delete the previously renamed files, so in * memory stays as is, on disk we have the current * item (and newer transfers) okay. */ return 0; } data->file_num = destnum; data = ixfr_data_prev(zone->ixfr, data, &prevcount); } return 1; } /* write the ixfr data file header */ static int ixfr_write_file_header(struct zone* zone, struct ixfr_data* data, FILE* out) { if(!fprintf(out, "; IXFR data file\n")) return 0; if(!fprintf(out, "; zone %s\n", zone->opts->name)) return 0; if(!fprintf(out, "; from_serial %u\n", (unsigned)data->oldserial)) return 0; if(!fprintf(out, "; to_serial %u\n", (unsigned)data->newserial)) return 0; if(!fprintf(out, "; data_size %u\n", (unsigned)ixfr_data_size(data))) return 0; if(data->log_str) { if(!fprintf(out, "; %s\n", data->log_str)) return 0; } return 1; } /* print rdata on one line */ static int oneline_print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor, rr_type* record) { size_t i; size_t saved_position = buffer_position(output); for (i = 0; i < record->rdata_count; ++i) { if (i == 0) { buffer_printf(output, "\t"); } else { buffer_printf(output, " "); } if (!rdata_atom_to_string( output, (rdata_zoneformat_type) descriptor->zoneformat[i], record->rdatas[i], record)) { buffer_set_position(output, saved_position); return 0; } } return 1; } /* parse wireformat RR into a struct RR in temp region */ static int parse_wirerr_into_temp(struct zone* zone, char* fname, struct region* temp, uint8_t* buf, size_t len, const dname_type** dname, struct rr* rr) { size_t bufpos = 0; uint16_t rdlen; ssize_t rdata_num; buffer_type packet; domain_table_type* owners; owners = domain_table_create(temp); memset(rr, 0, sizeof(*rr)); *dname = dname_make(temp, buf, 1); if(!*dname) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: failed to parse dname", zone->opts->name, fname); return 0; } bufpos = (*dname)->name_size; if(bufpos+10 > len) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: buffer too short", zone->opts->name, fname); return 0; } rr->type = read_uint16(buf+bufpos); bufpos += 2; rr->klass = read_uint16(buf+bufpos); bufpos += 2; rr->ttl = read_uint32(buf+bufpos); bufpos += 4; rdlen = read_uint16(buf+bufpos); bufpos += 2; if(bufpos + rdlen > len) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: buffer too short for rdatalen", zone->opts->name, fname); return 0; } buffer_create_from(&packet, buf+bufpos, rdlen); rdata_num = rdata_wireformat_to_rdata_atoms( temp, owners, rr->type, rdlen, &packet, &rr->rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: cannot parse rdata", zone->opts->name, fname); return 0; } rr->rdata_count = rdata_num; return 1; } /* print RR on one line in output buffer. caller must zeroterminate, if * that is needed. */ static int print_rr_oneline(struct buffer* rr_buffer, const dname_type* dname, struct rr* rr) { rrtype_descriptor_type *descriptor; descriptor = rrtype_descriptor_by_type(rr->type); buffer_printf(rr_buffer, "%s", dname_to_string(dname, NULL)); buffer_printf(rr_buffer, "\t%lu\t%s\t%s", (unsigned long)rr->ttl, rrclass_to_string(rr->klass), rrtype_to_string(rr->type)); if(!oneline_print_rdata(rr_buffer, descriptor, rr)) { if(!rdata_atoms_to_unknown_string(rr_buffer, descriptor, rr->rdata_count, rr->rdatas)) { return 0; } } return 1; } /* write one RR to file, on one line */ static int ixfr_write_rr(struct zone* zone, FILE* out, char* fname, uint8_t* buf, size_t len, struct region* temp, buffer_type* rr_buffer) { const dname_type* dname; struct rr rr; if(!parse_wirerr_into_temp(zone, fname, temp, buf, len, &dname, &rr)) { region_free_all(temp); return 0; } buffer_clear(rr_buffer); if(!print_rr_oneline(rr_buffer, dname, &rr)) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: cannot spool RR string into buffer", zone->opts->name, fname); region_free_all(temp); return 0; } buffer_write_u8(rr_buffer, 0); buffer_flip(rr_buffer); if(!fprintf(out, "%s\n", buffer_begin(rr_buffer))) { log_msg(LOG_ERR, "failed to write zone %s IXFR data %s: cannot print RR string to file: %s", zone->opts->name, fname, strerror(errno)); region_free_all(temp); return 0; } region_free_all(temp); return 1; } /* write ixfr RRs to file */ static int ixfr_write_rrs(struct zone* zone, FILE* out, char* fname, uint8_t* buf, size_t len, struct region* temp, buffer_type* rr_buffer) { size_t current = 0; if(!buf || len == 0) return 1; while(current < len) { size_t rrlen = count_rr_length(buf, len, current); if(rrlen == 0) return 0; if(current + rrlen > len) return 0; if(!ixfr_write_rr(zone, out, fname, buf+current, rrlen, temp, rr_buffer)) return 0; current += rrlen; } return 1; } /* write the ixfr data file data */ static int ixfr_write_file_data(struct zone* zone, struct ixfr_data* data, FILE* out, char* fname) { struct region* temp, *rrtemp; buffer_type* rr_buffer; temp = region_create(xalloc, free); rrtemp = region_create(xalloc, free); rr_buffer = buffer_create(rrtemp, MAX_RDLENGTH); if(!ixfr_write_rrs(zone, out, fname, data->newsoa, data->newsoa_len, temp, rr_buffer)) { region_destroy(temp); region_destroy(rrtemp); return 0; } if(!ixfr_write_rrs(zone, out, fname, data->oldsoa, data->oldsoa_len, temp, rr_buffer)) { region_destroy(temp); region_destroy(rrtemp); return 0; } if(!ixfr_write_rrs(zone, out, fname, data->del, data->del_len, temp, rr_buffer)) { region_destroy(temp); region_destroy(rrtemp); return 0; } if(!ixfr_write_rrs(zone, out, fname, data->add, data->add_len, temp, rr_buffer)) { region_destroy(temp); region_destroy(rrtemp); return 0; } region_destroy(temp); region_destroy(rrtemp); return 1; } int ixfr_write_file(struct zone* zone, struct ixfr_data* data, const char* zfile, int file_num) { char ixfrfile[1024+24]; FILE* out; make_ixfr_name(ixfrfile, sizeof(ixfrfile), zfile, file_num); VERBOSITY(1, (LOG_INFO, "writing zone %s IXFR data to file %s", zone->opts->name, ixfrfile)); out = fopen(ixfrfile, "w"); if(!out) { log_msg(LOG_ERR, "could not open for writing zone %s IXFR file %s: %s", zone->opts->name, ixfrfile, strerror(errno)); return 0; } if(!ixfr_write_file_header(zone, data, out)) { log_msg(LOG_ERR, "could not write file header for zone %s IXFR file %s: %s", zone->opts->name, ixfrfile, strerror(errno)); fclose(out); return 0; } if(!ixfr_write_file_data(zone, data, out, ixfrfile)) { fclose(out); return 0; } fclose(out); data->file_num = file_num; return 1; } /* write the ixfr files that need to be stored on disk */ static void ixfr_write_files(struct zone* zone, const char* zfile) { size_t prevcount = 0; int num; struct ixfr_data* data; if(!zone->ixfr || !zone->ixfr->data) return; /* nothing to write */ /* write unwritten files to disk */ data = ixfr_data_last(zone->ixfr); num=1; while(data && data->file_num == 0) { if(!ixfr_write_file(zone, data, zfile, num)) { /* There could be more files that are sitting on the * disk, remove them, they are not used without * this ixfr file. * * Give this element a file num, so it can be * deleted, it failed to write. It may be partial, * and we do not want to read that back in. * We are left with the newer transfers, that form * a correct list of transfers, that are wholly * written. */ data->file_num = num; ixfr_delete_rest_files(zone, data, zfile, 0); return; } num++; data = ixfr_data_prev(zone->ixfr, data, &prevcount); } } void ixfr_write_to_file(struct zone* zone, const char* zfile) { int dest_num_files = 0; /* we just wrote the zonefile zfile, and it is time to write * the IXFR contents to the disk too. */ /* find out what the target number of files is that we want on * the disk */ dest_num_files = ixfr_target_number_files(zone); /* delete if we have more than we need */ ixfr_delete_superfluous_files(zone, zfile, dest_num_files); /* delete if we have too much in memory */ ixfr_delete_memory_items(zone, dest_num_files); /* rename the transfers that we have that already have a file */ if(!ixfr_rename_files(zone, zfile, dest_num_files)) return; /* write the transfers that are not written yet */ ixfr_write_files(zone, zfile); } /* delete from domain table */ static void domain_table_delete(struct domain_table* table, struct domain* domain) { /* first adjust the number list so that domain is the last one */ numlist_make_last(table, domain); /* pop off the domain from the number list */ (void)numlist_pop_last(table); #ifdef USE_RADIX_TREE radix_delete(table->nametree, domain->rnode); #else rbtree_delete(table->names_to_domains, domain->node.key); #endif } /* can we delete temp domain */ static int can_del_temp_domain(struct domain* domain) { struct domain* n; /* we want to keep the zone apex */ if(domain->is_apex) return 0; if(domain->rrsets) return 0; if(domain->usage) return 0; /* check if there are domains under it */ n = domain_next(domain); if(n && domain_is_subdomain(n, domain)) return 0; return 1; } /* delete temporary domain */ static void ixfr_temp_deldomain(struct domain_table* temptable, struct domain* domain, struct domain* avoid) { struct domain* p; if(domain == avoid || !can_del_temp_domain(domain)) return; p = domain->parent; /* see if this domain is someones wildcard-child-closest-match, * which can only be the parent, and then it should use the * one-smaller than this domain as closest-match. */ if(domain->parent && domain->parent->wildcard_child_closest_match == domain) domain->parent->wildcard_child_closest_match = domain_previous_existing_child(domain); domain_table_delete(temptable, domain); while(p) { struct domain* up = p->parent; if(p == avoid || !can_del_temp_domain(p)) break; if(p->parent && p->parent->wildcard_child_closest_match == p) p->parent->wildcard_child_closest_match = domain_previous_existing_child(p); domain_table_delete(temptable, p); p = up; } } /* clear out the just read RR from the temp table */ static void clear_temp_table_of_rr(struct domain_table* temptable, struct zone* tempzone, struct rr* rr) { #if 0 /* clear out by removing everything, alternate for the cleanout code */ /* clear domains from the tempzone, * the only domain left is the zone apex and its parents */ domain_type* domain; #ifdef USE_RADIX_TREE struct radnode* first = radix_first(temptable->nametree); domain = first?(domain_type*)first->elem:NULL; #else domain = (domain_type*)rbtree_first(temptable->names_to_domains); #endif while(domain != (domain_type*)RBTREE_NULL && domain) { domain_type* next = domain_next(domain); if(domain != tempzone->apex && !domain_is_subdomain(tempzone->apex, domain)) { domain_table_delete(temptable, domain); } else { if(!domain->parent /* is the root */ || domain == tempzone->apex) domain->usage = 1; else domain->usage = 0; } domain = next; } if(rr->owner == tempzone->apex) { tempzone->apex->rrsets = NULL; tempzone->soa_rrset = NULL; tempzone->soa_nx_rrset = NULL; tempzone->ns_rrset = NULL; } return; #endif /* clear domains in the rdata */ unsigned i; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { /* clear out that dname */ struct domain* domain = rdata_atom_domain(rr->rdatas[i]); domain->usage --; if(domain != tempzone->apex && domain->usage == 0) ixfr_temp_deldomain(temptable, domain, rr->owner); } } /* clear domain_parsed */ if(rr->owner == tempzone->apex) { tempzone->apex->rrsets = NULL; tempzone->soa_rrset = NULL; tempzone->soa_nx_rrset = NULL; tempzone->ns_rrset = NULL; } else { rr->owner->rrsets = NULL; if(rr->owner->usage == 0) { ixfr_temp_deldomain(temptable, rr->owner, NULL); } } } /* read ixfr data new SOA */ static int ixfr_data_readnewsoa(struct ixfr_data* data, struct zone* zone, struct rr *rr, zone_parser_t *parser, struct region* tempregion, struct domain_table* temptable, struct zone* tempzone, uint32_t dest_serial) { size_t capacity = 0; if(rr->type != TYPE_SOA) { zone_error(parser, "zone %s ixfr data: IXFR data does not start with SOA", zone->opts->name); return 0; } if(rr->klass != CLASS_IN) { zone_error(parser, "zone %s ixfr data: IXFR data is not class IN", zone->opts->name); return 0; } if(!zone->apex) { zone_error(parser, "zone %s ixfr data: zone has no apex, no zone data", zone->opts->name); return 0; } if(dname_compare(domain_dname(zone->apex), domain_dname(rr->owner)) != 0) { zone_error(parser, "zone %s ixfr data: IXFR data wrong SOA for zone %s", zone->opts->name, domain_to_string(rr->owner)); return 0; } data->newserial = soa_rr_get_serial(rr); if(data->newserial != dest_serial) { zone_error(parser, "zone %s ixfr data: IXFR data contains the wrong version, serial %u but want destination serial %u", zone->opts->name, data->newserial, dest_serial); return 0; } if(!ixfr_putrr(domain_dname(rr->owner), rr->type, rr->klass, rr->ttl, rr->rdatas, rr->rdata_count, &data->newsoa, &data->newsoa_len, &capacity)) { zone_error(parser, "zone %s ixfr data: cannot allocate space", zone->opts->name); return 0; } clear_temp_table_of_rr(temptable, tempzone, rr); region_free_all(tempregion); ixfr_trim_capacity(&data->newsoa, &data->newsoa_len, &capacity); return 1; } /* read ixfr data old SOA */ static int ixfr_data_readoldsoa(struct ixfr_data* data, struct zone* zone, struct rr *rr, zone_parser_t *parser, struct region* tempregion, struct domain_table* temptable, struct zone* tempzone, uint32_t* dest_serial) { size_t capacity = 0; if(rr->type != TYPE_SOA) { zone_error(parser, "zone %s ixfr data: IXFR data 2nd RR is not SOA", zone->opts->name); return 0; } if(rr->klass != CLASS_IN) { zone_error(parser, "zone %s ixfr data: IXFR data 2ndSOA is not class IN", zone->opts->name); return 0; } if(!zone->apex) { zone_error(parser, "zone %s ixfr data: zone has no apex, no zone data", zone->opts->name); return 0; } if(dname_compare(domain_dname(zone->apex), domain_dname(rr->owner)) != 0) { zone_error(parser, "zone %s ixfr data: IXFR data wrong 2nd SOA for zone %s", zone->opts->name, domain_to_string(rr->owner)); return 0; } data->oldserial = soa_rr_get_serial(rr); if(!ixfr_putrr(domain_dname(rr->owner), rr->type, rr->klass, rr->ttl, rr->rdatas, rr->rdata_count, &data->oldsoa, &data->oldsoa_len, &capacity)) { zone_error(parser, "zone %s ixfr data: cannot allocate space", zone->opts->name); return 0; } clear_temp_table_of_rr(temptable, tempzone, rr); region_free_all(tempregion); ixfr_trim_capacity(&data->oldsoa, &data->oldsoa_len, &capacity); *dest_serial = data->oldserial; return 1; } /* read ixfr data del section */ static int ixfr_data_readdel(struct ixfr_data* data, struct zone* zone, struct rr *rr, zone_parser_t *parser, struct region* tempregion, struct domain_table* temptable, struct zone* tempzone) { size_t capacity = 0; if(!ixfr_putrr(domain_dname(rr->owner), rr->type, rr->klass, rr->ttl, rr->rdatas, rr->rdata_count, &data->del, &data->del_len, &capacity)) { zone_error(parser, "zone %s ixdr data: cannot allocate space", zone->opts->name); return 0; } clear_temp_table_of_rr(temptable, tempzone, rr); /* check SOA and also serial, because there could be other * add and del sections from older versions collated, we can * see this del section end when it has the serial */ if(rr->type != TYPE_SOA && soa_rr_get_serial(rr) != data->newserial) { region_free_all(tempregion); return 1; } region_free_all(tempregion); ixfr_trim_capacity(&data->del, &data->del_len, &capacity); return 2; } /* read ixfr data add section */ static int ixfr_data_readadd(struct ixfr_data* data, struct zone* zone, struct rr *rr, zone_parser_t *parser, struct region* tempregion, struct domain_table* temptable, struct zone* tempzone) { size_t capacity = 0; if(!ixfr_putrr(domain_dname(rr->owner), rr->type, rr->klass, rr->ttl, rr->rdatas, rr->rdata_count, &data->add, &data->add_len, &capacity)) { zone_error(parser, "zone %s ixfr data: cannot allocate space", zone->opts->name); return 0; } clear_temp_table_of_rr(temptable, tempzone, rr); if(rr->type != TYPE_SOA || soa_rr_get_serial(rr) != data->newserial) { region_free_all(tempregion); return 1; } region_free_all(tempregion); ixfr_trim_capacity(&data->add, &data->add_len, &capacity); return 2; } struct ixfr_data_state { struct zone *zone; struct ixfr_data *data; struct region *tempregion, *stayregion; struct domain_table *temptable; struct zone *tempzone; uint32_t *dest_serial; size_t rr_count, soa_rr_count; }; /* read one RR from file */ static int32_t ixfr_data_accept( zone_parser_t *parser, const zone_name_t *name, uint16_t type, uint16_t class, uint32_t ttl, uint16_t rdlength, const uint8_t *rdata, void *user_data) { struct rr *rr; const struct dname *dname; struct domain *domain; struct buffer buffer; union rdata_atom *rdatas; ssize_t rdata_count; struct ixfr_data_state *state = (struct ixfr_data_state *)user_data; assert(parser); buffer_create_from(&buffer, rdata, rdlength); dname = dname_make(state->tempregion, name->octets, 1); assert(dname); domain = domain_table_insert(state->temptable, dname); assert(domain); rdata_count = rdata_wireformat_to_rdata_atoms( state->tempregion, state->temptable, type, rdlength, &buffer, &rdatas); assert(rdata_count > 0); rr = region_alloc(state->tempregion, sizeof(*rr)); assert(rr); rr->owner = domain; rr->rdatas = rdatas; rr->ttl = ttl; rr->type = type; rr->klass = class; rr->rdata_count = rdata_count; if (state->rr_count == 0) { if (!ixfr_data_readnewsoa(state->data, state->zone, rr, parser, state->tempregion, state->temptable, state->tempzone, *state->dest_serial)) return ZONE_SEMANTIC_ERROR; } else if (state->rr_count == 1) { if(!ixfr_data_readoldsoa(state->data, state->zone, rr, parser, state->tempregion, state->temptable, state->tempzone, state->dest_serial)) return ZONE_SEMANTIC_ERROR; } else if (state->soa_rr_count == 0) { switch (ixfr_data_readdel(state->data, state->zone, rr, parser, state->tempregion, state->temptable, state->tempzone)) { case 0: return ZONE_SEMANTIC_ERROR; case 1: break; case 2: state->soa_rr_count++; break; } } else if (state->soa_rr_count == 1) { switch (ixfr_data_readadd(state->data, state->zone, rr, parser, state->tempregion, state->temptable, state->tempzone)) { case 0: return ZONE_SEMANTIC_ERROR; case 1: break; case 2: state->soa_rr_count++; break; } } state->rr_count++; return 0; } static void ixfr_data_log( zone_parser_t *parser, uint32_t category, const char *file, size_t line, const char *message, void *user_data) { int priority = LOG_ERR; (void)parser; (void)file; (void)line; (void)user_data; if (category == ZONE_WARNING) priority = LOG_WARNING; log_msg(priority, "%s", message); } /* read ixfr data from file */ static int ixfr_data_read(struct nsd* nsd, struct zone* zone, const char* ixfrfile, uint32_t* dest_serial, int file_num) { struct ixfr_data_state state = { 0 }; if(!zone->apex) { return 0; } if(zone->ixfr && zone->ixfr->data->count == zone->opts->pattern->ixfr_number) { VERBOSITY(3, (LOG_INFO, "zone %s skip %s IXFR data because only %d ixfr-number configured", zone->opts->name, ixfrfile, (int)zone->opts->pattern->ixfr_number)); return 0; } /* the file has header comments, new soa, old soa, delsection, * addsection. The delsection and addsection end in a SOA of oldver * and newver respectively. */ state.zone = zone; state.data = xalloc_zero(sizeof(*state.data)); state.data->file_num = file_num; state.dest_serial = dest_serial; /* the temp region is cleared after every RR */ state.tempregion = region_create(xalloc, free); /* the stay region holds the temporary data that stays between RRs */ state.stayregion = region_create(xalloc, free); state.temptable = domain_table_create(state.stayregion); state.tempzone = region_alloc_zero(state.stayregion, sizeof(*state.tempzone)); if(!zone->apex) { ixfr_data_free(state.data); region_destroy(state.tempregion); region_destroy(state.stayregion); return 0; } state.tempzone->apex = domain_table_insert(state.temptable, domain_dname(zone->apex)); state.temptable->root->usage++; state.tempzone->apex->usage++; state.tempzone->opts = zone->opts; /* switch to per RR region for new allocations in temp domain table */ state.temptable->region = state.tempregion; { const struct dname *origin; zone_parser_t parser; zone_options_t options; zone_name_buffer_t name_buffer; zone_rdata_buffer_t rdata_buffer; zone_buffers_t buffers = { 1, &name_buffer, &rdata_buffer }; memset(&options, 0, sizeof(options)); origin = domain_dname(zone->apex); options.origin.octets = dname_name(origin); options.origin.length = origin->name_size; options.no_includes = true; options.pretty_ttls = false; options.default_ttl = DEFAULT_TTL; options.default_class = CLASS_IN; options.log.callback = &ixfr_data_log; options.accept.callback = &ixfr_data_accept; if(zone_parse(&parser, &options, &buffers, ixfrfile, &state) != 0) { ixfr_data_free(state.data); region_destroy(state.tempregion); region_destroy(state.stayregion); return 0; } } region_destroy(state.tempregion); region_destroy(state.stayregion); if(!zone->ixfr) zone->ixfr = zone_ixfr_create(nsd); if(zone->opts->pattern->ixfr_size != 0 && zone->ixfr->total_size + ixfr_data_size(state.data) > zone->opts->pattern->ixfr_size) { VERBOSITY(3, (LOG_INFO, "zone %s skip %s IXFR data because only ixfr-size: %u configured, and it is %u size", zone->opts->name, ixfrfile, (unsigned)zone->opts->pattern->ixfr_size, (unsigned)ixfr_data_size(state.data))); ixfr_data_free(state.data); return 0; } zone_ixfr_add(zone->ixfr, state.data, 0); VERBOSITY(3, (LOG_INFO, "zone %s read %s IXFR data of %u bytes", zone->opts->name, ixfrfile, (unsigned)ixfr_data_size(state.data))); return 1; } /* try to read the next ixfr file. returns false if it fails or if it * does not fit in the configured sizes */ static int ixfr_read_one_more_file(struct nsd* nsd, struct zone* zone, const char* zfile, int num_files, uint32_t *dest_serial) { char ixfrfile[1024+24]; struct stat statbuf; int file_num = num_files+1; make_ixfr_name(ixfrfile, sizeof(ixfrfile), zfile, file_num); /* if the file does not exist, all transfers have been read */ if (stat(ixfrfile, &statbuf) != 0 && errno == ENOENT) return 0; return ixfr_data_read(nsd, zone, ixfrfile, dest_serial, file_num); } void ixfr_read_from_file(struct nsd* nsd, struct zone* zone, const char* zfile) { uint32_t serial; int num_files = 0; /* delete the existing data, the zone data in memory has likely * changed, eg. due to reading a new zonefile. So that needs new * IXFRs */ zone_ixfr_clear(zone->ixfr); /* track the serial number that we need to end up with, and check * that the IXFRs match up and result in the required version */ serial = zone_get_current_serial(zone); while(ixfr_read_one_more_file(nsd, zone, zfile, num_files, &serial)) { num_files++; } if(num_files > 0) { VERBOSITY(1, (LOG_INFO, "zone %s read %d IXFR transfers with success", zone->opts->name, num_files)); } } nsd-4.12.0/iterated_hash.h0000644000175000017500000000102715002373054014752 0ustar mozziemozzie/* * iterated_hash.h -- nsec3 hash calculation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * With thanks to Ben Laurie. */ #ifndef ITERATED_HASH_H #define ITERATED_HASH_H #ifdef NSEC3 #include #define NSEC3_SHA1_HASH 1 /* same type code as DS hash */ int iterated_hash(unsigned char out[SHA_DIGEST_LENGTH], const unsigned char *salt,int saltlength, const unsigned char *in,int inlength,int iterations); #endif /* NSEC3 */ #endif /* ITERATED_HASH_H */ nsd-4.12.0/iterated_hash.c0000644000175000017500000000371415002373054014752 0ustar mozziemozzie/* * iterated_hash.c -- nsec3 hash calculation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * With thanks to Ben Laurie. */ #include "config.h" #ifdef NSEC3 #if defined(HAVE_SHA1_INIT) && !defined(DEPRECATED_SHA1_INIT) #include #else #include #endif #include #include #include "iterated_hash.h" #include "util.h" int iterated_hash(unsigned char out[SHA_DIGEST_LENGTH], const unsigned char *salt, int saltlength, const unsigned char *in, int inlength, int iterations) { #if defined(NSEC3) && defined(HAVE_SSL) #if defined(HAVE_SHA1_INIT) && !defined(DEPRECATED_SHA1_INIT) SHA_CTX ctx; #else EVP_MD_CTX* ctx; #endif int n; #if defined(HAVE_SHA1_INIT) && !defined(DEPRECATED_SHA1_INIT) #else ctx = EVP_MD_CTX_create(); if(!ctx) { log_msg(LOG_ERR, "out of memory in iterated_hash"); return 0; } #endif assert(in && inlength > 0 && iterations >= 0); for(n=0 ; n <= iterations ; ++n) { #if defined(HAVE_SHA1_INIT) && !defined(DEPRECATED_SHA1_INIT) SHA1_Init(&ctx); SHA1_Update(&ctx, in, inlength); if(saltlength > 0) SHA1_Update(&ctx, salt, saltlength); SHA1_Final(out, &ctx); #else if(!EVP_DigestInit(ctx, EVP_sha1())) log_msg(LOG_ERR, "iterated_hash could not EVP_DigestInit"); if(!EVP_DigestUpdate(ctx, in, inlength)) log_msg(LOG_ERR, "iterated_hash could not EVP_DigestUpdate"); if(saltlength > 0) { if(!EVP_DigestUpdate(ctx, salt, saltlength)) log_msg(LOG_ERR, "iterated_hash could not EVP_DigestUpdate salt"); } if(!EVP_DigestFinal_ex(ctx, out, NULL)) log_msg(LOG_ERR, "iterated_hash could not EVP_DigestFinal_ex"); #endif in=out; inlength=SHA_DIGEST_LENGTH; } #if defined(HAVE_SHA1_INIT) && !defined(DEPRECATED_SHA1_INIT) #else EVP_MD_CTX_destroy(ctx); #endif return SHA_DIGEST_LENGTH; #else (void)out; (void)salt; (void)saltlength; (void)in; (void)inlength; (void)iterations; return 0; #endif } #endif /* NSEC3 */ nsd-4.12.0/ipc.h0000644000175000017500000000454015002373054012724 0ustar mozziemozzie/* * ipc.h - Interprocess communication routines. Handlers read and write. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef NSD_IPC_H #define NSD_IPC_H #include "netio.h" struct buffer; struct nsd; struct nsd_child; struct xfrd_tcp; struct xfrd_state; struct nsdst; struct event; /* * Data for the server_main IPC handler * Used by parent side to listen to children, and write to children. */ struct main_ipc_handler_data { struct nsd *nsd; struct nsd_child *child; }; /* * Data for ipc handler, nsd and a conn for reading ipc msgs. * Used by children to listen to parent. * Used by parent to listen to xfrd. */ struct ipc_handler_conn_data { struct nsd *nsd; struct xfrd_tcp *conn; }; /* * Routine used by server_main. * Handle a command received from the xfrdaemon processes. */ void parent_handle_xfrd_command(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); /* * Routine used by server_main. * Handle a command received from the reload process. */ void parent_handle_reload_command(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); /* * Routine used by server_main. * Handle a command received from the children processes. * Send commands and forwarded xfrd packets when writable. */ void parent_handle_child_command(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); /* * Routine used by server_child. * Handle a command received from the parent process. */ void child_handle_parent_command(int fd, short event, void* arg); /* * Routine used by xfrd * Handle interprocess communication with parent process, read and write. */ void xfrd_handle_ipc(int fd, short event, void* arg); /* receive incoming notifies received by and from the serve processes */ void xfrd_handle_notify(int fd, short event, void* arg); /* check if all children have exited in an orderly fashion and set mode */ void parent_check_all_children_exited(struct nsd* nsd); /** add stats to total */ void stats_add(struct nsdst* total, struct nsdst* s); /** subtract stats from total */ void stats_subtract(struct nsdst* total, struct nsdst* s); /** set event to listen to given mode, no timeout, must be added already */ void ipc_xfrd_set_listening(struct xfrd_state* xfrd, short mode); #endif /* NSD_IPC_H */ nsd-4.12.0/ipc.c0000644000175000017500000004232215002373054012717 0ustar mozziemozzie/* * ipc.c - Interprocess communication routines. Handlers read and write. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "ipc.h" #include "buffer.h" #include "xfrd-tcp.h" #include "nsd.h" #include "namedb.h" #include "xfrd.h" #include "xfrd-notify.h" #include "difffile.h" #include "rrl.h" /* attempt to send NSD_STATS command to child fd */ static void send_stat_to_child(struct main_ipc_handler_data* data, int fd); /* send reload request over the IPC channel */ static void xfrd_send_reload_req(xfrd_state_type* xfrd); /* send quit request over the IPC channel */ static void xfrd_send_quit_req(xfrd_state_type* xfrd); /* perform read part of handle ipc for xfrd */ static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd); static void ipc_child_quit(struct nsd* nsd) ATTR_NORETURN; static void ipc_child_quit(struct nsd* nsd) { /* call shutdown and quit routines */ nsd->mode = NSD_QUIT; service_remaining_tcp(nsd); #ifdef BIND8_STATS bind8_stats(nsd); #endif /* BIND8_STATS */ #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_deinit(nsd->this_child->child_num); #endif event_base_free(nsd->event_base); region_destroy(nsd->server_region); #endif server_shutdown(nsd); /* ENOTREACH */ exit(0); } void child_handle_parent_command(int fd, short event, void* arg) { sig_atomic_t mode; int len; struct ipc_handler_conn_data *data = (struct ipc_handler_conn_data *) arg; if (!(event & EV_READ)) { return; } if ((len = read(fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_parent_command: read: %s", strerror(errno)); return; } if (len == 0) { /* parent closed the connection. Quit */ ipc_child_quit(data->nsd); return; } switch (mode) { case NSD_STATS: data->nsd->mode = mode; break; case NSD_QUIT: ipc_child_quit(data->nsd); break; case NSD_QUIT_CHILD: /* close our listening sockets and ack */ server_close_all_sockets(data->nsd->udp, data->nsd->ifs); server_close_all_sockets(data->nsd->tcp, data->nsd->ifs); /* mode == NSD_QUIT_CHILD */ if(write(fd, &mode, sizeof(mode)) == -1) { VERBOSITY(3, (LOG_INFO, "quit child write: %s", strerror(errno))); } ipc_child_quit(data->nsd); break; default: log_msg(LOG_ERR, "handle_parent_command: bad mode %d", (int) mode); break; } } void parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; struct ipc_handler_conn_data *data = (struct ipc_handler_conn_data *) handler->user_data; if (!(event_types & NETIO_EVENT_READ)) { return; } if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_xfrd_command: read: %s", strerror(errno)); return; } if (len == 0) { /* xfrd closed, we must quit */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "handle_xfrd_command: xfrd closed channel.")); close(handler->fd); handler->fd = -1; data->nsd->mode = NSD_SHUTDOWN; return; } switch (mode) { case NSD_RELOAD: DEBUG(DEBUG_IPC,1, (LOG_INFO, "parent handle xfrd command RELOAD")); data->nsd->signal_hint_reload = 1; break; case NSD_QUIT: case NSD_SHUTDOWN: data->nsd->mode = mode; break; case NSD_STATS: data->nsd->signal_hint_stats = 1; break; case NSD_REAP_CHILDREN: data->nsd->signal_hint_child = 1; break; default: log_msg(LOG_ERR, "handle_xfrd_command: bad mode %d", (int) mode); break; } } static void send_stat_to_child(struct main_ipc_handler_data* data, int fd) { sig_atomic_t cmd = NSD_STATS; if(write(fd, &cmd, sizeof(cmd)) == -1) { if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "svrmain: problems sending stats to child %d command: %s", (int)data->child->pid, strerror(errno)); return; } data->child->need_to_send_STATS = 0; } static void send_quit_to_child(struct main_ipc_handler_data* data, int fd) { sig_atomic_t cmd = NSD_QUIT; if(write(fd, &cmd, sizeof(cmd)) == -1) { if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "svrmain: problems sending quit to child %d command: %s", (int)data->child->pid, strerror(errno)); return; } data->child->need_to_send_QUIT = 0; DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: sent quit to child %d", (int)data->child->pid)); } /** the child is done, mark it as exited */ static void child_is_done(struct nsd* nsd, int fd) { size_t i; if(fd != -1) close(fd); for(i=0; ichild_count; ++i) if(nsd->children[i].child_fd == fd) { nsd->children[i].child_fd = -1; nsd->children[i].handler->fd = -1; if(nsd->children[i].need_to_exit) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "server %d is done", (int)nsd->children[i].pid)); nsd->children[i].has_exited = 1; } else { log_msg(LOG_WARNING, "server %d died unexpectedly, restarting", (int)nsd->children[i].pid); /* this child is now going to be re-forked as * a subprocess of this server-main, and if a * reload is in progress the other children * are subprocesses of reload. Until the * reload is done and they are all reforked. */ nsd->children[i].pid = -1; nsd->restart_children = 1; } } parent_check_all_children_exited(nsd); } #ifdef BIND8_STATS /** add stats to total */ void stats_add(struct nsdst* total, struct nsdst* s) { unsigned i; for(i=0; iqtype)/sizeof(stc_type); i++) total->qtype[i] += s->qtype[i]; for(i=0; iqclass)/sizeof(stc_type); i++) total->qclass[i] += s->qclass[i]; total->qudp += s->qudp; total->qudp6 += s->qudp6; total->ctcp += s->ctcp; total->ctcp6 += s->ctcp6; total->ctls += s->ctls; total->ctls6 += s->ctls6; for(i=0; ircode)/sizeof(stc_type); i++) total->rcode[i] += s->rcode[i]; for(i=0; iopcode)/sizeof(stc_type); i++) total->opcode[i] += s->opcode[i]; total->dropped += s->dropped; total->truncated += s->truncated; total->wrongzone += s->wrongzone; total->txerr += s->txerr; total->rxerr += s->rxerr; total->edns += s->edns; total->ednserr += s->ednserr; total->raxfr += s->raxfr; total->nona += s->nona; total->rixfr += s->rixfr; total->db_disk = s->db_disk; total->db_mem = s->db_mem; } /** subtract stats from total */ void stats_subtract(struct nsdst* total, struct nsdst* s) { unsigned i; for(i=0; iqtype)/sizeof(stc_type); i++) total->qtype[i] -= s->qtype[i]; for(i=0; iqclass)/sizeof(stc_type); i++) total->qclass[i] -= s->qclass[i]; total->qudp -= s->qudp; total->qudp6 -= s->qudp6; total->ctcp -= s->ctcp; total->ctcp6 -= s->ctcp6; total->ctls -= s->ctls; total->ctls6 -= s->ctls6; for(i=0; ircode)/sizeof(stc_type); i++) total->rcode[i] -= s->rcode[i]; for(i=0; iopcode)/sizeof(stc_type); i++) total->opcode[i] -= s->opcode[i]; total->dropped -= s->dropped; total->truncated -= s->truncated; total->wrongzone -= s->wrongzone; total->txerr -= s->txerr; total->rxerr -= s->rxerr; total->edns -= s->edns; total->ednserr -= s->ednserr; total->raxfr -= s->raxfr; total->nona -= s->nona; total->rixfr -= s->rixfr; } #endif /* BIND8_STATS */ void parent_handle_child_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; struct main_ipc_handler_data *data = (struct main_ipc_handler_data*)handler->user_data; /* do a nonblocking write to the child if it is ready. */ if (event_types & NETIO_EVENT_WRITE) { if(data->child->need_to_send_STATS && !data->child->need_to_exit) { send_stat_to_child(data, handler->fd); } else if(data->child->need_to_send_QUIT) { send_quit_to_child(data, handler->fd); if(!data->child->need_to_send_QUIT) handler->event_types = NETIO_EVENT_READ; } else { handler->event_types = NETIO_EVENT_READ; } } if (!(event_types & NETIO_EVENT_READ)) { return; } /* read command from ipc */ if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_child_command: read: %s", strerror(errno)); return; } if (len == 0) { child_is_done(data->nsd, handler->fd); return; } switch (mode) { case NSD_QUIT: data->nsd->mode = mode; break; case NSD_STATS: data->nsd->signal_hint_stats = 1; break; case NSD_REAP_CHILDREN: data->nsd->signal_hint_child = 1; break; default: log_msg(LOG_ERR, "handle_child_command: bad mode %d", (int) mode); break; } } void parent_check_all_children_exited(struct nsd* nsd) { size_t i; for(i=0; i < nsd->child_count; i++) { if(!nsd->children[i].need_to_exit) return; if(!nsd->children[i].has_exited) return; } nsd->mode = NSD_QUIT_SYNC; DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: all children exited. quit sync.")); } void parent_handle_reload_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; size_t i; struct nsd *nsd = (struct nsd*) handler->user_data; if (!(event_types & NETIO_EVENT_READ)) { return; } /* read command from ipc */ if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_reload_command: read: %s", strerror(errno)); return; } if (len == 0) { assert(handler->fd != -1); /* or read() would have failed */ close(handler->fd); handler->fd = -1; log_msg(LOG_ERR, "handle_reload_cmd: reload closed cmd channel"); nsd->reload_failed = 1; return; } switch (mode) { case NSD_QUIT_SYNC: /* set all children to exit, only then notify xfrd. */ /* so that buffered packets to pass to xfrd can arrive. */ for(i=0; i < nsd->child_count; i++) { nsd->children[i].need_to_exit = 1; if(nsd->children[i].pid > 0 && nsd->children[i].child_fd != -1) { nsd->children[i].need_to_send_QUIT = 1; nsd->children[i].handler->event_types |= NETIO_EVENT_WRITE; } else { if(nsd->children[i].child_fd == -1) nsd->children[i].has_exited = 1; } } parent_check_all_children_exited(nsd); break; default: log_msg(LOG_ERR, "handle_reload_command: bad mode %d", (int) mode); break; } } static void xfrd_send_reload_req(xfrd_state_type* xfrd) { sig_atomic_t req = NSD_RELOAD; uint64_t p = xfrd->last_task->data; udb_ptr_unlink(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); task_process_sync(xfrd->nsd->task[xfrd->nsd->mytask]); /* ask server_main for a reload */ if(write(xfrd->ipc_handler.ev_fd, &req, sizeof(req)) == -1) { udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); udb_ptr_set(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask], p); if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "xfrd: problems sending reload command: %s", strerror(errno)); return; } DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: asked nsd to reload new updates")); /* swapped task to other side, start to use other task udb. */ xfrd->nsd->mytask = 1 - xfrd->nsd->mytask; task_remap(xfrd->nsd->task[xfrd->nsd->mytask]); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); assert(udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0); if(!xfrd->reload_cmd_first_sent) xfrd->reload_cmd_first_sent = xfrd_time(); xfrd->reload_cmd_last_sent = xfrd_time(); xfrd->need_to_send_reload = 0; xfrd->can_send_reload = 0; } void ipc_xfrd_set_listening(struct xfrd_state* xfrd, short mode) { int fd = xfrd->ipc_handler.ev_fd; struct event_base* base = xfrd->event_base; event_del(&xfrd->ipc_handler); memset(&xfrd->ipc_handler, 0, sizeof(xfrd->ipc_handler)); event_set(&xfrd->ipc_handler, fd, mode, xfrd_handle_ipc, xfrd); if(event_base_set(base, &xfrd->ipc_handler) != 0) log_msg(LOG_ERR, "ipc: cannot set event_base"); /* no timeout for IPC events */ if(event_add(&xfrd->ipc_handler, NULL) != 0) log_msg(LOG_ERR, "ipc: cannot add event"); xfrd->ipc_handler_flags = mode; } static void xfrd_send_shutdown_req(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_SHUTDOWN; xfrd->ipc_send_blocked = 1; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send shutdown")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing shutdown to main: %s", strerror(errno)); } xfrd->need_to_send_shutdown = 0; } static void xfrd_send_quit_req(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_QUIT; xfrd->ipc_send_blocked = 1; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send ackreload(quit)")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing ack to main: %s", strerror(errno)); } xfrd->need_to_send_quit = 0; } static void xfrd_send_stats(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_STATS; DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send stats")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing stats to main: %s", strerror(errno)); } xfrd->need_to_send_stats = 0; } void xfrd_handle_ipc(int ATTR_UNUSED(fd), short event, void* arg) { xfrd_state_type* xfrd = (xfrd_state_type*)arg; if ((event & EV_READ)) { /* first attempt to read as a signal from main * could block further send operations */ xfrd_handle_ipc_read(&xfrd->ipc_handler, xfrd); } if ((event & EV_WRITE)) { if(xfrd->ipc_send_blocked) { /* wait for RELOAD_DONE */ ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); return; } if(xfrd->need_to_send_shutdown) { xfrd_send_shutdown_req(xfrd); } else if(xfrd->need_to_send_quit) { xfrd_send_quit_req(xfrd); } else if(xfrd->can_send_reload && xfrd->need_to_send_reload) { xfrd_send_reload_req(xfrd); } else if(xfrd->need_to_send_stats) { xfrd_send_stats(xfrd); } if(!(xfrd->can_send_reload && xfrd->need_to_send_reload) && !xfrd->need_to_send_shutdown && !xfrd->need_to_send_quit && !xfrd->need_to_send_stats) { /* disable writing for now */ ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); } } } static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd) { sig_atomic_t cmd; int len; if((len = read(handler->ev_fd, &cmd, sizeof(cmd))) == -1) { if(errno != EINTR && errno != EAGAIN) log_msg(LOG_ERR, "xfrd_handle_ipc: read: %s", strerror(errno)); return; } if(len == 0) { /* parent closed the connection. Quit */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main closed connection.")); xfrd->shutdown = 1; return; } switch(cmd) { case NSD_QUIT: case NSD_SHUTDOWN: DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main sent shutdown cmd.")); xfrd->shutdown = 1; break; case NSD_RELOAD_FAILED: xfrd->reload_failed = 1; /* fall through */ case NSD_RELOAD_DONE: /* reload has finished */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv %s", xfrd->reload_failed ? "RELOAD FAILED" : "RELOAD DONE")); if(block_read(NULL, handler->ev_fd, &xfrd->reload_pid, sizeof(pid_t), -1) != sizeof(pid_t)) { log_msg(LOG_ERR, "xfrd cannot get reload_pid"); } /* read the not-mytask for the results and soainfo */ xfrd_process_task_result(xfrd, xfrd->nsd->task[1-xfrd->nsd->mytask]); /* reset the IPC, (and the nonblocking ipc write; the new parent does not want half a packet) */ xfrd->can_send_reload = 1; xfrd->ipc_send_blocked = 0; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); xfrd_reopen_logfile(); if(!xfrd->reload_failed) { xfrd_check_failed_updates(); xfrd->reload_cmd_first_sent = 0; } else { /* make reload happen again, right away */ xfrd_set_reload_now(xfrd); } xfrd_prepare_zones_for_reload(); xfrd->reload_failed = 0; break; case NSD_RELOAD_REQ: DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_REQ")); /* make reload happen, right away, and schedule file check */ task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, NULL); xfrd_set_reload_now(xfrd); break; case NSD_RELOAD: /* main tells us that reload is done, stop ipc send to main */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD")); ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); xfrd->need_to_send_quit = 1; break; default: log_msg(LOG_ERR, "xfrd_handle_ipc: bad mode %d (%d)", (int)cmd, (int)ntohl(cmd)); break; } } void xfrd_handle_notify(int ATTR_UNUSED(fd), short event, void* arg) { struct xfrd_tcp* notify_pipe = (struct xfrd_tcp*)arg; uint32_t acl_num; int32_t acl_xfr; if(!(event & EV_READ)) return; switch(conn_read(notify_pipe)){ case -1: /* TODO: What to do here? */ return; case 0: return; /* call back later */ default: break; } if(buffer_limit(notify_pipe->packet) < sizeof(acl_xfr)+sizeof(acl_num)) log_msg(LOG_ERR, "xfrd_handle_notify invalid message size"); else { size_t eop = buffer_position(notify_pipe->packet) - sizeof(acl_xfr) - sizeof(acl_num); buffer_set_position(notify_pipe->packet, eop); acl_num = buffer_read_u32(notify_pipe->packet); acl_xfr = (int32_t)buffer_read_u32(notify_pipe->packet); buffer_set_position(notify_pipe->packet, eop); buffer_flip(notify_pipe->packet); xfrd_handle_passed_packet(notify_pipe->packet,acl_num,acl_xfr); } notify_pipe->total_bytes = 0; notify_pipe->msglen = 0; buffer_clear(notify_pipe->packet); } nsd-4.12.0/edns.h0000644000175000017500000000630515002373054013103 0ustar mozziemozzie/* * edns.h -- EDNS definitions (RFC 2671). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef EDNS_H #define EDNS_H #include "buffer.h" struct nsd; struct query; #define OPT_LEN 9U /* Length of the NSD EDNS response record minus 2 */ #define OPT_RDATA 2 /* holds the rdata length comes after OPT_LEN */ #define OPT_HDR 4U /* NSID opt header length */ #define NSID_CODE 3 /* nsid option code */ #define COOKIE_CODE 10 /* COOKIE option code */ #define EDE_CODE 15 /* Extended DNS Errors option code */ #define ZONEVERSION_CODE 19 /* ZONEVERSION option code */ #define DNSSEC_OK_MASK 0x8000U /* do bit mask */ /* https://iana.org/assignments/dns-parameters/#zoneversion-type-values */ #define ZONEVERSION_SOA_SERIAL 0 struct edns_data { unsigned char ok[OPT_LEN]; unsigned char error[OPT_LEN]; unsigned char rdata_none[OPT_RDATA]; unsigned char nsid[OPT_HDR]; unsigned char cookie[OPT_HDR]; }; typedef struct edns_data edns_data_type; enum edns_status { EDNS_NOT_PRESENT, EDNS_OK, /* EDNS states may be extended in the future */ EDNS_ERROR }; typedef enum edns_status edns_status_type; enum cookie_status { COOKIE_NOT_PRESENT, COOKIE_UNVERIFIED, COOKIE_VALID, COOKIE_VALID_REUSE, COOKIE_INVALID }; typedef enum cookie_status cookie_status_type; struct edns_record { edns_status_type status; size_t position; size_t maxlen; size_t opt_reserved_space; int dnssec_ok; int nsid; int zoneversion; cookie_status_type cookie_status; size_t cookie_len; uint8_t cookie[40]; int ede; /* RFC 8914 - Extended DNS Errors */ char* ede_text; /* RFC 8914 - Extended DNS Errors text*/ uint16_t ede_text_len; }; typedef struct edns_record edns_record_type; /* The Extended DNS Error codes (RFC8914) we use */ #define EDE_OTHER 0 #define EDE_NOT_READY 14 #define EDE_PROHIBITED 18 #define EDE_NOT_AUTHORITATIVE 20 #define EDE_NOT_SUPPORTED 21 #define EDE_INVALID_DATA 24 /* ASSIGN_EDE_CODE_AND_STRING_LITERAL may only be used with string literals. * This is guaranteed by concatenating and empty string to LITERAL, which * will make compilation fail if this macro is used with variables. */ #define ASSIGN_EDE_CODE_AND_STRING_LITERAL(EDE, CODE, LITERAL) \ do { \ EDE = (CODE); \ EDE ## _text = (LITERAL ""); \ EDE ## _text_len = sizeof(LITERAL) - 1; \ } while (0) void edns_init_data(edns_data_type *data, uint16_t max_length); void edns_init_record(edns_record_type *data); int edns_parse_record(edns_record_type *data, buffer_type *packet, struct query* q, struct nsd* nsd); /* * The amount of space to reserve in the response for the EDNS data * (if required). */ size_t edns_reserved_space(edns_record_type *data); void edns_init_nsid(edns_data_type *data, uint16_t nsid_len); void cookie_verify(struct query *q, struct nsd* nsd, uint32_t *now_p); void cookie_create(struct query *q, struct nsd* nsd, uint32_t *now_p); #endif /* EDNS_H */ nsd-4.12.0/edns.c0000644000175000017500000002223115002373054013072 0ustar mozziemozzie/* * edns.c -- EDNS definitions (RFC 2671). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #ifdef HAVE_SSL #include #include #endif #include "dns.h" #include "edns.h" #include "nsd.h" #include "query.h" #if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP) /* we need fixed time compare, pull it in from tsig.c */ #define CRYPTO_memcmp memcmp_fixedtime int memcmp_fixedtime(const void *s1, const void *s2, size_t n); #endif void edns_init_data(edns_data_type *data, uint16_t max_length) { memset(data, 0, sizeof(edns_data_type)); /* record type: OPT */ data->ok[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ data->ok[2] = TYPE_OPT & 0x00ff; /* type_lo */ /* udp payload size */ data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */ data->ok[4] = max_length & 0x00ff; /* size_lo */ data->error[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ data->error[2] = TYPE_OPT & 0x00ff; /* type_lo */ data->error[3] = (max_length & 0xff00) >> 8; /* size_hi */ data->error[4] = max_length & 0x00ff; /* size_lo */ data->error[5] = 1; /* XXX Extended RCODE=BAD VERS */ /* COOKIE OPT HDR */ data->cookie[0] = (COOKIE_CODE & 0xff00) >> 8; data->cookie[1] = (COOKIE_CODE & 0x00ff); data->cookie[2] = (24 & 0xff00) >> 8; data->cookie[3] = (24 & 0x00ff); } void edns_init_nsid(edns_data_type *data, uint16_t nsid_len) { /* NSID OPT HDR */ data->nsid[0] = (NSID_CODE & 0xff00) >> 8; data->nsid[1] = (NSID_CODE & 0x00ff); data->nsid[2] = (nsid_len & 0xff00) >> 8; data->nsid[3] = (nsid_len & 0x00ff); } void edns_init_record(edns_record_type *edns) { edns->status = EDNS_NOT_PRESENT; edns->position = 0; edns->maxlen = 0; edns->opt_reserved_space = 0; edns->dnssec_ok = 0; edns->nsid = 0; edns->zoneversion = 0; edns->cookie_status = COOKIE_NOT_PRESENT; edns->cookie_len = 0; edns->ede = -1; /* -1 means no Extended DNS Error */ edns->ede_text = NULL; edns->ede_text_len = 0; } /** handle a single edns option in the query */ static int edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, edns_record_type* edns, struct query* query, nsd_type* nsd) { (void) query; /* in case edns options need the query structure */ /* handle opt code and read the optlen bytes from the packet */ switch(optcode) { case NSID_CODE: /* is NSID enabled? */ if(nsd->nsid_len > 0) { edns->nsid = 1; /* we have to check optlen, and move the buffer along */ buffer_skip(packet, optlen); /* in the reply we need space for optcode+optlen+nsid_bytes */ edns->opt_reserved_space += OPT_HDR + nsd->nsid_len; } else { /* ignore option */ buffer_skip(packet, optlen); } break; case COOKIE_CODE: /* Cookies enabled? */ if(nsd->do_answer_cookie) { if (optlen == 8) edns->cookie_status = COOKIE_INVALID; else if (optlen < 16 || optlen > 40) return 0; /* FORMERR */ else edns->cookie_status = COOKIE_UNVERIFIED; edns->cookie_len = optlen; memcpy(edns->cookie, buffer_current(packet), optlen); buffer_skip(packet, optlen); edns->opt_reserved_space += OPT_HDR + 24; } else { buffer_skip(packet, optlen); } break; case ZONEVERSION_CODE: edns->zoneversion = 1; if(optlen > 0) return 0; break; default: buffer_skip(packet, optlen); break; } return 1; } int edns_parse_record(edns_record_type *edns, buffer_type *packet, query_type* query, nsd_type* nsd) { /* OPT record type... */ uint8_t opt_owner; uint16_t opt_type; uint16_t opt_class; uint8_t opt_version; uint16_t opt_flags; uint16_t opt_rdlen; edns->position = buffer_position(packet); if (!buffer_available(packet, (OPT_LEN + OPT_RDATA))) return 0; opt_owner = buffer_read_u8(packet); opt_type = buffer_read_u16(packet); if (opt_owner != 0 || opt_type != TYPE_OPT) { /* Not EDNS. */ buffer_set_position(packet, edns->position); return 0; } opt_class = buffer_read_u16(packet); (void)buffer_read_u8(packet); /* opt_extended_rcode */ opt_version = buffer_read_u8(packet); opt_flags = buffer_read_u16(packet); opt_rdlen = buffer_read_u16(packet); if (opt_version != 0) { /* The only error is VERSION not implemented */ edns->status = EDNS_ERROR; return 1; } if (opt_rdlen > 0) { if(!buffer_available(packet, opt_rdlen)) return 0; if(opt_rdlen > 65530) return 0; /* there is more to come, read opt code */ while(opt_rdlen >= 4) { uint16_t optcode = buffer_read_u16(packet); uint16_t optlen = buffer_read_u16(packet); opt_rdlen -= 4; if(opt_rdlen < optlen) return 0; /* opt too long, formerr */ opt_rdlen -= optlen; if(!edns_handle_option(optcode, optlen, packet, edns, query, nsd)) return 0; } if(opt_rdlen != 0) return 0; } edns->status = EDNS_OK; edns->maxlen = opt_class; edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK; return 1; } size_t edns_reserved_space(edns_record_type *edns) { /* MIEK; when a pkt is too large?? */ return edns->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space); } int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, uint8_t *out, const size_t outlen); /** RFC 1982 comparison, uses unsigned integers, and tries to avoid * compiler optimization (eg. by avoiding a-b<0 comparisons), * this routine matches compare_serial(), for SOA serial number checks */ static int compare_1982(uint32_t a, uint32_t b) { /* for 32 bit values */ const uint32_t cutoff = ((uint32_t) 1 << (32 - 1)); if (a == b) { return 0; } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) { return -1; } else { return 1; } } /** if we know that b is larger than a, return the difference between them, * that is the distance between them. in RFC1982 arith */ static uint32_t subtract_1982(uint32_t a, uint32_t b) { /* for 32 bit values */ const uint32_t cutoff = ((uint32_t) 1 << (32 - 1)); if(a == b) return 0; if(a < b && b - a < cutoff) { return b-a; } if(a > b && a - b > cutoff) { return ((uint32_t)0xffffffff) - (a-b-1); } /* wrong case, b smaller than a */ return 0; } void cookie_verify(query_type *q, struct nsd* nsd, uint32_t *now_p) { uint8_t hash[8], hash2verify[8]; uint32_t cookie_time, now_uint32; size_t verify_size; int i; /* We support only draft-sury-toorop-dnsop-server-cookies sizes */ if(q->edns.cookie_len != 24) return; if(q->edns.cookie[8] != 1) return; q->edns.cookie_status = COOKIE_INVALID; cookie_time = (q->edns.cookie[12] << 24) | (q->edns.cookie[13] << 16) | (q->edns.cookie[14] << 8) | q->edns.cookie[15]; now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL)); if(compare_1982(now_uint32, cookie_time) > 0) { /* ignore cookies > 1 hour in past */ if (subtract_1982(cookie_time, now_uint32) > 3600) return; } else if (subtract_1982(now_uint32, cookie_time) > 300) { /* ignore cookies > 5 minutes in future */ return; } memcpy(hash2verify, q->edns.cookie + 16, 8); #ifdef INET6 if(q->client_addr.ss_family == AF_INET6) { memcpy(q->edns.cookie + 16, &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16); verify_size = 32; } else { memcpy(q->edns.cookie + 16, &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4); verify_size = 20; } #else memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4); verify_size = 20; #endif q->edns.cookie_status = COOKIE_INVALID; siphash(q->edns.cookie, verify_size, nsd->cookie_secrets[0].cookie_secret, hash, 8); if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) { if (subtract_1982(cookie_time, now_uint32) < 1800) { q->edns.cookie_status = COOKIE_VALID_REUSE; memcpy(q->edns.cookie + 16, hash, 8); } else q->edns.cookie_status = COOKIE_VALID; return; } for(i = 1; i < (int)nsd->cookie_count && i < NSD_COOKIE_HISTORY_SIZE; i++) { siphash(q->edns.cookie, verify_size, nsd->cookie_secrets[i].cookie_secret, hash, 8); if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) { q->edns.cookie_status = COOKIE_VALID; return; } } } void cookie_create(query_type *q, struct nsd* nsd, uint32_t *now_p) { uint8_t hash[8]; uint32_t now_uint32; if (q->edns.cookie_status == COOKIE_VALID_REUSE) return; now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL)); q->edns.cookie[ 8] = 1; q->edns.cookie[ 9] = 0; q->edns.cookie[10] = 0; q->edns.cookie[11] = 0; q->edns.cookie[12] = (now_uint32 & 0xFF000000) >> 24; q->edns.cookie[13] = (now_uint32 & 0x00FF0000) >> 16; q->edns.cookie[14] = (now_uint32 & 0x0000FF00) >> 8; q->edns.cookie[15] = now_uint32 & 0x000000FF; #ifdef INET6 if (q->client_addr.ss_family == AF_INET6) { memcpy( q->edns.cookie + 16 , &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16); siphash(q->edns.cookie, 32, nsd->cookie_secrets[0].cookie_secret, hash, 8); } else { memcpy( q->edns.cookie + 16 , &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4); siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); } #else memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4); siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); #endif memcpy(q->edns.cookie + 16, hash, 8); } nsd-4.12.0/doc/0000755000175000017500000000000015002373060012537 5ustar mozziemozziensd-4.12.0/doc/manual/0000755000175000017500000000000015002373054014017 5ustar mozziemozziensd-4.12.0/doc/manual/zonefile.rst0000644000175000017500000000420315002373054016363 0ustar mozziemozzieZonefile example ================ On this page we give an example of a basic zone file and it's contents. We recommend using the :command:`nsd-checkzone` tool to verify that you have a working zone. Creating a zone --------------- A minimal zone needs exactly one SOA (Source Of Authority) and one or more NS (Name Server) records. Refer to appropriate documentation if you need to learn about DNS basics. .. code:: bash $ORIGIN example.com. $TTL 86400 ; default time-to-live for this zone example.com. IN SOA ns.example.com. noc.dns.example.org. ( 2020080302 ;Serial 7200 ;Refresh 3600 ;Retry 1209600 ;Expire 3600 ;Negative response caching TTL ) ; The nameservers that are authoritative for this zone. NS example.com. ; A and AAAA records are for IPv4 and IPv6 addresses respectively example.com. A 192.0.2.1 AAAA 2001:db8::3 ; A CNAME redirects from www.example.com to example.com www CNAME example.com. mail MX 10 example.com. .. could add this structure eventually: .. Note:: In the example above the ``SOA`` record class is set to: ``IN``. The record class is omitted in the remaining records, in which case the resulting value will be set from the preceding record. Meaning the ``NS``, ``A`` and ``MX`` source records have implicitly the ``IN`` record class. .. Note:: The first domain in the ``SOA`` (start of authority) record, is the authoritative master name server for the zone. The second domain is actually the administrator email addresss for this zone. Where the first dot (``.``) will be converted into an ``@`` sign. So in this example above, the email is: ``noc@dns.example.org``. If you have a dot in the local-part of the email address, you need to backslash the dot. .. Note:: You can use the ``@`` symbol in the zone file for a shortcut to the origin of the zone domain. Meaning ``example.com. IN SOA`` could also have been written to: ``@ IN SOA``. Same can be applied to other records as well, like the A record: ``@ A 192.0.2.1``. Which is the same as: ``example.com. A 192.0.2.1`` nsd-4.12.0/doc/manual/running/0000755000175000017500000000000015002373054015477 5ustar mozziemozziensd-4.12.0/doc/manual/running/zone-expiry.rst0000644000175000017500000000447115002373054020530 0ustar mozziemozzieZone Expiry of Secondary Zones ============================== NSD will keep track of the status of secondary zones, according to the timing values in the SOA record for the zone. When the refresh time of a zone is reached, the serial number is checked and a zone transfer is started if the zone has changed. Each primary server is tried in turn. Primary zones cannot expire so they are always served. Zones are interpreted as primary zones if they have no ``request-xfr:`` statements in the config file. After the expire timeout (from the SOA record at the zone apex) is reached, the zone becomes expired. NSD will return ``SERVFAIL`` for expired zones, and will attempt to perform a zone transfer from any of the primaries. After a zone transfer succeeds, or if the primary indicates that the SOA serial number is still the same, the zone returns to an operational state. In contrast with e.g. BIND, the inception time for a secondary zone is stored on disk (in ``xfrdfile: "xfrd.state"``), together with timeouts. If a secondary zone acquisition time is recent enough, NSD can start serving a zone immediately on loading, without querying the primary server. If a secondary zone has expired and no primaries can be reached, but NSD should still serve the zone, delete the :file:`xfrd.state` file, but leave the zone file for the zone intact. Make sure to stop NSD before you delete the file, as NSD writes it on exit. Upon loading NSD will treat the zone file that you as operator have provided as recent and will serve the zone. Even though NSD will start to serve the zone immediately, the zone will expire after the timeout is reached again. NSD will also attempt to confirm that you have provided the correct data by polling the primaries. So when the primary servers come back up, it will transfer the updated zone within seconds. It is possible to provide zone files for both primary and secondary zones via alternative means (say from email or rsync). Reload with SIGHUP or :command:`nsd-control reload` to read the new zone file contents into the name database. When this is done the new zone will be served. For primary zones, NSD will issue notifications to all configured ``notify:`` targets. For secondary zones the above happens; NSD attempts to validate the zone from the primary (checking its SOA serial number). nsd-4.12.0/doc/manual/running/using-tsig.rst0000644000175000017500000000227215002373054020325 0ustar mozziemozzieUsing Transaction Signature (TSIG) ================================== NSD supports Transaction Signature (TSIG) for zone transfer and for notify sending and receiving, for any query to the server. TSIG keys are based on shared secrets. These must be configured in the config file. To keep the secret in a separate file use ``include: "filename"`` to include that file. An example TSIG key named :file:`sec1_key`: .. code:: text key: name: "sec1_key" algorithm: hmac-md5 secret: "6KM6qiKfwfEpamEq72HQdA==" This key can then be used for any query to the NSD server. NSD will check if the signature is valid, and if so, return a signed answer. Unsigned queries will be given unsigned replies. The key can be used to restrict the access control lists, for example to only allow zone transfer with the key, by listing the key name on the access control line. .. code:: text # provides AXFR to the subnet when TSIG is used. provide-xfr: 10.11.12.0/24 sec1_key # allow only notifications that are signed allow-notify: 192.168.0.0/16 sec1_key If the TSIG key name is used in ``notify`` or ``request-xfr`` lines, the key is used to sign the request/notification messages.nsd-4.12.0/doc/manual/running/tuning.rst0000644000175000017500000001307015002373054017536 0ustar mozziemozzieTuning ====== In version 4.3.0 of NSD, additional functionality was added to increase performance even more. Most notably, this includes processor affinity. NSD is performant by design because it matters when operators serve hundreds of thousands or even millions of queries per second. We strive to make the right choices by default, like enabling the use of ``libevent`` at the configure stage to ensure the most efficient event mechanism is used on a given platform. e.g. ``epoll`` on Linux and ``kqueue`` on FreeBSD. Switches are available for operators who know the implementation on their system behaves correctly, like enabling the use of ``recvmmsg`` at the configure stage (`--enable-recvmmsg`) to read multiple messages from a socket in one system call. By default NSD forks (only) one server. Modern computer systems however, may have more than one processor, and usually have more than one core per processor. The easiest way to scale up performance is to simply fork more servers by configuring server-count: to match the number of cores available in the system so that more queries can be answered simultaneously. If the operating system supports it, ensure ``reuseport:`` is set to ``yes`` to distribute incoming packets evenly across server processes to balance the load. A couple of other options that the operator may want to consider: 1. TCP capacity can be significantly increased by setting ``tcp-count: 1000`` and ``tcp-timeout: 3``. Set ``tcp-reject-overflow: yes`` to prevent the kernel connection queue from growing. Processor Affinity ------------------ The aforementioned settings provide an easy way to increase performance without the need for in-depth knowledge of the hardware. For operators that require even more throughput ``cpu-affinity`` is available. The operating system’s scheduling-algorithm determines which core a given task is allocated to. Processors build up state — e.g. by keeping frequently accessed data in cache memory — for the task that it is currently executing. Whenever a task switches cores, performance is degraded because the core it switched to has yet to build up said state. While this scheduling-algorithm works just fine for general-purpose computing, operators may want to designate a set of cores for best performance. The ``cpu-affinity`` family of configuration options was added to NSD specifically for that purpose. Processor affinity is currently supported on Linux and FreeBSD. Other operating systems may be supported in the future, but not all operating systems that can run NSD support CPU pinning. To fully benefit from this feature, one must first determine which cores should be allocated to NSD. This requires some knowledge of the underlying hardware, but generally speaking every process should run on a dedicated core and the use of Hyper-Threading cores should be avoided to prevent resource contention. List every core designated to NSD in ``cpu-affinity`` and bind each server process to a specific core using ``server--cpu-affinity`` and ``xfrd-cpu-affinity`` to improve L1/L2 cache hit rates and reduce pipeline stalls/flushes. .. code:: text server: server-count: 2 cpu-affinity: 0 1 2 server-1-cpu-affinity: 0 server-2-cpu-affinity: 1 xfrd-cpu-affinity: 2 Partition Sockets ----------------- ``ip-address:`` options in the ``server:`` clause can be configured per server or set of servers. Sockets configured for a specific server are closed by other servers on startup. This improves performance if a large number of sockets are scanned using ``select/poll`` and avoids waking up multiple servers when a packet comes in, known as the `thundering herd problem `_. Though both problems are solved using a modern kernel and a modern I/O event mechanism, there is one other reason to partition sockets, explained below. .. code:: text server: ip-address: 192.0.2.1 servers=1 Bind to Device -------------- ``ip-address:`` options in the server: clause can now also be configured to bind directly to the network interface device on Linux (``bindtodevice=yes``) and to use a specific routing table on FreeBSD (``setfib=``). These were added to ensure UDP responses go out over the same interface the query came in on if there are multiple interfaces configured on the same subnet, but there may be some performance benefits as well as the kernel does not have to go through the network interface selection process. .. code:: text server: ip-address: 192.0.2.1 bindtodevice=yes setfib= .. Note:: FreeBSD does not create extra routing tables on demand. Consult the FreeBSD Handbook, forums, etc. for information on how to configure multiple routing tables. Combining Options ----------------- Field tests have shown best performance is achieved by combining the aforementioned options so that each network interface is essentially bound to a specific core. To do so, use one IP address per server process, pin that process to a designated core and bind directly to the network interface device. .. code:: text server: server-count: 2 cpu-affinity: 0 1 2 server-1-cpu-affinity: 0 server-2-cpu-affinity: 1 xfrd-cpu-affinity: 2 ip-address: 192.0.2.1 servers=1 bindtodevice=yes setfib=1 ip-address: 192.0.2.2 servers=2 bindtodevice=yes setfib=2 The above snippet serves as an example on how to use the configuration options. Which cores, IP addresses and routing tables are best used depends entirely on the hardware and network layout. Be sure to test extensively before using the options. nsd-4.12.0/doc/manual/running/logging.rst0000644000175000017500000000322715002373054017663 0ustar mozziemozzieLogging ======= NSD does not provide any DNS logging. We believe that this is a separate task and has to be done independently from the core operation. This decision was taken in order to keep NSD focused and minimise its complexity. It is better to leave logging and tracing to separate dedicated tools. Do note, however, that NSD can be compiled with support for DNSTAP (see ``nsd.conf(5)``). If some visibility on individual queries is required, consider running ``tcpdump(1)`` on the server, using an appropriate filter rule to capture UDP and TCP packets to port 53. The tcpdump on most systems will decode the packets into readable requests and responses. The `CAIDA dnsstat tool `_ can easily be configured and/or modified to suit local statistics requirements without any danger of affecting the name server itself. We have run ``dnsstat`` on the same machine as NSD, and we would recommend using a multiprocessor if performance is an issue. Of course, ``dnsstat`` can also run on a separate machine that has MAC layer access to the network of the server. The :command:`nsd-control` tool can output some statistics, with :command:`nsd-control stats` and :command:`nsd-control stats_noreset`. In `contrib/nsd_munin_ `_ there is a Munin grapher plugin that uses it. The output of :command:`nsd-control stats` is easy to read (text only) with scripts. The output values are documented on the :command:`nsd-control` man page. Another available tool is `dnstop `_, which displays DNS statistics on your network. nsd-4.12.0/doc/manual/running/interfaces.rst0000644000175000017500000000264115002373054020357 0ustar mozziemozzieInterfaces ========== NSD will by default bind itself to the system default interface and service IPv4 and if available also IPv6. It is possible to service only IPv4 or IPv6 using the :option:`-4`, :option:`-6` command line options, or the ``ip4-only`` and ``ip6-only`` config file options. The command line option :option:`-a` and config file option ip-address can be given to bind to specific interfaces. Multiple interfaces can be specified, which is useful for two reasons: - The specific interface bound will result in the OS bypassing routing tables for the interface selection. This results in a small performance gain. It is not the performance gain that is the problem: sometimes the routing tables can give the wrong answer, see the next point. - The answer will be routed via the interface the query came from. This makes sure that the return address on the DNS replies is the same as the query was sent to. Many resolvers require the source address of the replies to be correct. The ``ip-address:`` option is easier than configuring the OS routing table to return the DNS replies via the correct interface. The above means that even for systems with multiple interfaces where you intend to provide DNS service to all interfaces, it is prudent to specify all the interfaces as ``ip-address`` config file options. With the config file option ``ip-transparent`` you can allow NSD to bind to non-local addresses.nsd-4.12.0/doc/manual/resources/0000755000175000017500000000000015002373054016031 5ustar mozziemozziensd-4.12.0/doc/manual/resources/nsd-duotone-white.svg0000644000175000017500000000576215002373054022141 0ustar mozziemozziensd-4.12.0/doc/manual/resources/nsd-duotone-white.png0000644000175000017500000013721615002373054022126 0ustar mozziemozzie‰PNG  IHDRH‡ÔúW†gAMA±Ź üa cHRMz&€„ú€ču0ę`:pśşQ<ÂeXIfMM*bj(1r2„‡i  Pixelmator 3.9.82021:10:05 15:10:54  H ‡ÔĆö pHYs,K,KĄ=–©)iTXtXML:com.adobe.xmp 1 1100 550 2021-10-05T15:10:54 Pixelmator 3.9.8 2 0 1 288 288 ü-&ë@IDATx인EŐĆBB€Đ{˝*¤‰T@!T©" Š *~‚TE¤JEEŠ‘&"Ň»R:„ ! ä{ßvďÝ»wűÎěÎîľó<çŢÝť™3çü¦ěělů˘ " " " -'0m`Ѧ»(ęČ™6ËčŞîl8ŽĘšĚöŇ=%´ozwŞi…Ň7ť€ŃF‚v±×8†GŽh8QÉrŢssgR†ĚŚť˛6¦ŠŮÂl mŹR٬hiŞŇ# +ť!źĽé“tC×ÁIńŠ+O p#AĺÜS¦˛‘÷éňć÷4,oHŹÔÄ(tş)Ó8v,Ř.´ ;-”Q™rČ=’j =# čúq.o•¸\Ť•zJ9 2©Pi™ 4”­:d’@®F‚‚‡y…_˙l,FB‘†‚‚Ô~’§đ_y˛–JU.ęäły”šI"őĺi(4žŽ1$82q‘e%ä1źŽČ«pşW˝ż±w–SüÎ\¤_VD†e#Ž%2 ŕöJ(í䄸¸(žVj=µÄĆăYDĹ/ŕWbř¸Ľ´2Âůýý°o˙Uč{2&.ö°ŃF[ "`Ü·“âSâŘPjť°ĆŮ—V‰^ľ…âňWx|fŘZč*cŤônä%9ťhś ^ú˛±¬— Ćăk$• ż_¦ď IéBq˝<ˇcEv™^ňĐIE23OŁ9W}l†¤6ßH‰ţv‰˙W"ď s{;˘Ę†iłŹCßűÁý¸í"ůç3ĐľŇXeľšPÎÄő]A†Óeµ7ś/i?¶°¤LḼôC¨lCŮÚłă7ř_VWźKE!ɇ<ףŕ\y&#Ą˛`ětSŔâE ä‰ĘÂÉ2OCSŁ"u¬<\­ť?ęts6Z÷ÝELľ‘ĎhC…-ą|*bw×ň”® ˘ „ ‘×ŮËw5#))ŰHޤ1çK 9‹VňŚJ5ÔË÷3–“¬D/["o˘MŠě'Pćęfxżšň[¬ě¶u?ď˛|"6†¸DIqqy2ף‹AIf¤‘ ň_ÉÚná"†ĆĺľSââtÜ R§Tß…ÉôĘAŔܰľ‰νÉW ,(ÜH˛ŽQ¶3݉ů Ôđ˝ËrźnXÁ eí2ˇ6lWÖĺO'«‘ŞŘ>«ĘčC^ŁOÚ÷ĄŤAr5ä> üęĐ …y ˛‘7Ź—ž?ФPĽŤ„&1‹©J*óµÚŁ`™@á‰+ěb^6ű{B žvňLd‘<ęMÂÂĺűˇ÷]lĎęďgµ‰öűyř?-_8}0oZţ´Ľž®—`±Ą†"#IŘ'ľŞÉĆ~;>ś.q?Łó‰:LGš¶‰úŇěśžjúß´´1ń ĐѧÚD#ń•=‹ 6–§üy˙Ó±´Ńűbß˙Ľ(Łţ‰$Ó„·‘gn¤y#âxbYÁôa»¶->nŰÔH˛T\4Š!.>ćxÜ(”Ř@bt9<‡âc‚i#±0-Ň j AY¶Ł¸ńĂT#Ů FsÄ}?3dqŽiÂÎ`˙ÇYóÚJ¶)G9űB =}:˛näa§ÓT#ń'“»Ł ľŻÁŔAC?Ťf3(x<ÓÔ—‘‚E$nGŮ ›6IĚ =ß ůŽ6˝˙dP!ĘŢ#¸ź¶ť©˛|%Pž4'á3~1 ˛ŻË˙źÖňH?´Ż#řejÁř¤mŘ2`Nâ۶Ń?îëJ‹gşp?Ż˙?¬Ó?ţÖc;Ë75’Pמç†čżőźN2DĹŽ%5Î@2k›|Ľˇ/¤ůÔ—0°‘ćc”÷'͉M“Ť„]ĺ• *Î?ćAśÇßýßűµ}K¶ :Ő•h(÷„|´ëń*µŠ=Hi‰¦ Mńç'ĚJk,¨Ś7ĽĆÂąM8đ2˛¶ŕŮ5 |řóő2ě@ĎZÔĹ’ülčß&%M%Ń6Ięµx†Ćrľńo! EÖ\B*ŠďFT,ż![8Pźb”\s<×ađ7Č\OÚh$ü‰Ô†Â4^cy“Ű1a,Žsd žjjm(°eŔŹNŇKśw!>5¤4–Ôü) ‚üX7}71Sňő˘Ť7Ľőż~#ćôË… iĎF\đ4¶CBZ«Qđ/ŞěpOµjCŐĘM7’‹iz{‡ĆxŤĄ÷I,lła„ Ĺä=Ťp©űđ+wŁ o©Š-$(÷•ĽĹm$`·GŘ€@ŻőK‚UÂEV˛źÇ/ż˘řźÁ¶(˘ďQpY°{Áđ±´}ŁŤ$®°<@:xĺĐ·z8îŇćŽEŚéµ”?yőE©ŽŁô¬s‹i0 qĄł¨p–«¸l,Ö{`ؤcđé÷IńeăJ0Tt]•Ś$ľĹe …6ÂşŻl|Wúţgń‰ié·}S6Ľô)©ŇŁ{O/;=qL #Ť6$Ž"ˇ˛źíçÝeC±ŐXć‡n^ú’É6ŻBý<±——H·3ÓúĘ˙*ŕÁ@\(Şo7X΀m?ođ_®ĽßRi€Kóź1]Pµ¶K(4qEEE‚öłÄ]ń¨qIU»]t$±fe¸1pźÁZR," " " " " " " " " " "J7yć†üňdTj††$€/KB–hą2SŚţ0Q%8ŃÁ˛ĂÎě[ĄéőĘß*-]ń°E3‘*@« ë¬$č(űŽRżńiÄ•´Ë°Î\ęP|Ô×iséPbp…€µÄë¨ŰĂŃBź?ŞmDř Š˛‚e L~căĂŕ1m‹@“ Ř\#ńż„üô$;Ď~ŽÁŃ6Uň -Ĺź<©í—Hc/sZBŔć@…ß»ńĆ©őG°h„Ţäxbs1úŹCYôYˇF¨‡ŁPü^ůBfĽ†ý»!ǡÜŠÓnkw0PYEůű×ě­*ę?hHź0Yx|úr넵=Ů ›üčm~Ř|őă…ˇĽÄu+”•»˝¦é,dč!?)GdÉ‹ň9eÝŰŻÂŽl(Ϋ3wĹd-‹ $aőÇÜť/¬¤č~‘†UX¬Ťă»GĹĄ .$=ó r26X@UWšď–’Üö Ę`耵ĹVCöÝ=Ľ˘p`Şô+ĎlŚ (·p@ö9ąĐ R¸ĐŠ3ö M›öTĹĹF[N =‘‘†¦ "†‹Ë¤Î« ţ»4SC‰\H‚nröÄźŕő–Ó‘6·˝Ę9¬`ÇĚ×´lK‘“F'Évţ˘zw wK*'k\V[ Źë9ŹfŐ‹t;xí¶’·â›4„ú ·XÖ`…„Ţ?*oGAz—w†Ý°«ÎkĽ/Ű-%Z;Ę~6:fúѲmůç¦/\T–é8”ůdeżpţGźĚPÎp›!]©$® $Ľ-ě˙&˙ϙë;Ŕ”—@˝;.>hě®CGć¤^GI=ó"]ç‘ÄČ)°_Őfâ]HôŁŞ ©˘´ő»í=©Č%ŕűµI ĘĆą2řł‹IžC|-8°ÄÝ2ĺ(yfŔń'|Čü}Ľĺg, b"+ďĘ ˛CСiÓŢKJc8nÉ}GҦ”4ŤŚöÚx’í[&E–ŤcłJv&"Ië#3^ZşX°ďiD¦5ĽŘüÁ`%–ô;¨¶· ÝÎ޵ńý†Ď©ťÓO;ČÁŔ4=uL…ĘĽżĎut[ąE źo˙fń)€(u3…áG(//›Ô2™Ŕ•IŘX®{\>ŘçÓ±{Âcă™7t)V˘2gŚH8ÝŚi/á?MçÂé5’÷ů3Τ¤Ąâ` /ovÉ©dOĎľđżCsęq=ąµţnM±˘\!瀒VŐţái˘âýĹ˙•&ĺŘ‚çY-ő윢§‘ŃŕvŮĄ?ë*%MéhÁŹYŃ–J*;:Ô¶¬Ű^ŇŢÚ˛»<řP8đR&kři¨ň—Ęš1Ž Ń8ľZ0.e›—"…/ąRt;Mf0’jlđꇗ VLᓟ}…[¶Ŕ@Űş˝¬®6ĺoÂ@BŢţběaŕ?¨üBg´Ä‡úZ#6`Ă ěŕ`˛q†t­KDŻWŠcĂX/)iŚFäCiW8 ľw“7¬[µýy ¬2}SŢÚÝr A@ÁAĄhC€ ‡xv|¶đMÜť‰ĺÇĄ“ź đÍ˙c_± *€ťgÓÖ`@±™îrmC6Ü‚-O¦čÝ)%ľptâ}÷ÂZ gD¸sÁ g&*1¤#óKhČ·!LXŐső·Ţţă”}˙Ŕ>7ýO'dYó emö.Şj2<â<Č)/žëbs ЬáěľĹkg¶]żßˇŚĄ“ĘOLc%8?ŔůHâŘ@ďĹ1ľÜg"¬jđ?@|ő@@šůq nt'Óŕ€ÁĆčOť9;ą2Ň©Ŕş˘Ă!ľaN "aŁ\ßOaÚ3ßçoË×/mLs€l>,+)Ç6™™fW žëX|éÜ `aű{/»ęĘß\%X~[¶áÜÓľi>ŮDXľË3’ŕ4H~Ś<ë‰ĐĽĘŢ:1‘˝H.ČrqŐ—•ěŐ|Í^]˝TÖč™J]á˝GĐݧ¶¬®’ů·ď3¤ٶA„ľXUqfŕóyÂp0Ů#O†ő|#¨xFú@ĆgOfAúÔĚšäżl' Î YĆ c .<YŇJ©ŇđľËw! Áß“)­·nđgóşmPů"‡@#_qçČăäĽ;{Lśó‡árôř€ˇŔë?ö(O›"P@Őß#)d¤ź íŹ “Í–ď«rő˙‰!Ă~Ú×®8I  ‡ĺ˝âKY("íÝYŇą”6ł.Â}jäŚŃ%®˛ĄÎ$Ţ’÷ł‡k!ß'«Ah¬”łŤi’"¨€ł ‚·˝A¤(’»Šf¬)źÖBjŻbËpn ÁŕqŚ7€”^4-9•§›Qě<+cR%' TůÍÖDčLs!Á‰‰ Dr0ńż˝Z {UYâîBUUľĘRśHŘŮKy‘’ęy[x¶”dµDöŁj)X…Š€Aµ^Ú = ±:x¬FˇäfRŐĽ&•I—ÔA –ťzgo©ňKě\{™©Čqež]ăât\šD ŇKt>ńQŤ€&ˇl—žÍX·F*ZڍlFâÍ@ęDzĐ<;Ś,Şv¬^4Żň‰€k¬$č07ąŇy}řŽŘó ßý¦°:xöÓ.B‚m××eĘ…˛«Xd®ËE•Ű1ÖGÎúIŐąl\!)Ÿ“-ę–j¨ś€µžĽů{ĺĺ+đ±|ÉŤĄžjL“‰€¬ÜÁŔ™ţ"řö~Ŕ?NĺżŘwjłĘ'_Áć\8źő˝š¶·S°dŚD°5#ů TÖ»Řçű$׆Ž;±[ńeXÖAÄ 62B˛°5„ż«áŰň68 8÷f.“W|#mýG§ÚŇ-˝"P'[IšO ”˙Ą%¬0~~tô=,—W逖}i¤zÔ1żUs$*<‚?„Ě×Hçj4ş®Äwůflś 1ţÖŻ_@Î˙ç ŮZ7rő]źXDQ=-plžŘŚ#şŁ6/¨v”ď+„~=oť]+ářĎ Żúé˝˙…é)»ËOŤŽ±˝ÖĂu$tž÷Ź3 ᵪ<ŘzúvÉĘ=±[ŕkv՗׎N·{.4RRđCťm”źýŔ7˙ťyWË…ÄŻcÚrät˙@]˙YQ&ˆş­LęsE—iN&ý‚m ď“:=]#č·δ ?ŹĘó=;žÎ“ÉFZ—ßżaŘŕúÉiţ:ţŁ‚âŚ‹ó…"™šśvÍNŘÄgřČí0‹í2ę_ŇP~ś1˝ńd.$ľ“\ä€ÂKž: ¨ś‹Ë m»¤ #Y>.>X×>lŮeWŇÁńŚĎşüŚ)÷řot6SΠĂ.$ľ±´‘ äŞ:ě„zY¸dˇ‡•Ě߄켭ďJpýijëśęLš0řŕůX9”Küýˇh9¨ĐáČkkń¶¨YVňŐŃxĂŽŔ†Ď‡ŹĹěĎĚG†“ňń=¬±1ůyxî„¸ÚŁŞ®Ź& $~ĺpŤĘßü¶˙—¨”şălŁ śžp úť«ÓŠô~ŕ*1 Ý%˝ôĽł8ŕ÷ĄqüÍD#}ýi˙ˇnĎŚ*ű’•h·}:˛n4q ń}‹ (˙ńŘü_°Rşö8ü"ŕ´˛Íz(Ł›ťµh~d=ĂďěĐqlQ=Eóˇěsĺg^»C}TrӢɉ_'÷0vţä°ő•ňTVÝH{vÖ´-KçÜ]Ó|ŃÜ5­3Ź>”?ĆkóY˛ IeÉP$Ť+Éş0žoąąĺÚ@öËÜ'‹€Čg) Yoĺń%Łn'ŁZî¸MĹĽu^{9M3ŞŁđ:_šn?Ţ•dĎ Žž{@2/P怵ě/ëćZŠŤpUšRTÜ iiÚŻ·ÝGüC[_( gHS*‰+ ×:üŔçGö…ěI;łý×ĎţŔł{J8Şô>:Iš]ł•.¤ů 榵]röç’=¦lÉŇÎáűş¦Ę‹ŇăĘ@BŰÂŹĆĎcű@¶`dTŔŁŽŹ2Cđ‰mTLä`‚Ă]ů¨óo2pĽ3Cš*“|őó‡* ¬°¬p˙ }{ř€É}—>~„sŁqŚë'k…â&‡öw§'f4ʨ»2«%ŇžČYł Đ`9ŕZÂđŹ zżB›8ëmM@]ě_§3. $äŔÁ!nŐ Äq@ pßä˙ĽÁküüÁraF4Čľ[Ř^߄҆čÇłs“4{Á%řŮÍ´ä…ăQ·ĺČ|:ěňĂś9ň)iךx$i±•—:{Ł,ÇÄEÜ[Ţ€b♇ďĂ–Ů=;v)bO“ó€ăͰ˙ífŁ-SŇŠ~·€˘7ý˙GČďJ–ÄđÍZ·¦¸$Ů,Ď`<áUľß‰s‰Nđ¨7 ěś;óŔ o{ °Ęiü@ jÜĂ,gôk«0¶”]čžŕµ«\—ÎUř–ˇŚoĄ¤Y/%ľp´« Ęúx9;q©ŚĆ÷[o@)łŞoëvsáĘ­2ŁÇ/±Č˛ő”¨<™Ĺ–@ň¸ÍáŢ€Âe?ŚW†Ńăđű™…ąłOŃ×íň@Â;-i+Ń}Žř•Ţw Ŕ*â^#Ľ¦@vfáN—òiÎŁž˘¨Ó˛ĺŽ74řĺúźjÜË?ĐĐ˙łe·Ë }ćťśëó8oh@ůĽ×Çĺ)ŰK»m<­Čf|Şř‰g¸@]ÉZ’W‡3ĄŘ“'ú,¶Ż<ş’Öő„őŔÎüNŢ ń”´EŔDµhŁ˝Ć811áŔH~śŇÉ^+dpü‚ iŚ$=“Y‡ FBI“L1ëiÂ@B›/ žqvo@y$cúČdhłälś•tö]›,¬ę茴‹uSún]öG6ÎŔAŘ´b`7jÓÚ×›2ĘעČd<¶’7 ü.cúČdÓ›ać3ßęrH˝{RWgD=öîÖęóŐ"űď(’Ďbž““tĂ_kO7f „KXńI 2Ä}ŐPË66‰g×oŇBg_ÁĎsÜőńí´4¶ăaë^ťŽČYÖ:9ÓŰNľąíâô7e y9ŕŔ"í˘›GyJÖO * ŹÍťąpPäŔ» ÜíÎm‘ÁŰ_dHSIŘ;… CÖŃŽćĘš¶Íé1 ^âW¶_Äöďüý’˙Żň”Ńyő ß—Ľ<ül”?ÇčŕY®+ďß BĄS˛e¬ů€g÷̸5CëI€đ×Ö I(  É F†JŢ > :žŕgZÔ3lĚy~Ć |¶} …p@ůGDa|ťľ ¬#L7r(ő2đŤ”dP ÚŮO2¨[5Cš*’¤˝uľ¦M#śoܨĚ}Łŕ¸ ŰßËŇ ‘fů(›ĽcŹă?”đˇ_DZ¤wĽěíű‡ş˘ß§4Ôł ]·í1ő!?ÔÁ˝6ý°ŃMÚ;Ř˙n`;nóDp@y1 rP Ä·vUu`Cťłv§Ă4Ó+ˇ‡K ă“"MÄą>đ,ž›´ĚIń˝ŃdÚ´łăĺĎ€cI:w5„ď ńUz˝Ź¶ęf7ŻÎĘĽ36/Ďĺn8ŻŐ}řú Ř*­ âó§Ą)ďň@2#¤vX¤™ Yś˘¬†zŤóuOA‘E-Îś.†\RÔ¶äC}Y™Ez|ÎóţóKh |dżlx>EAć_HŃ“9~ń3–ś1/š!OdÖËÉ÷łzʶyŇľ’5}Át~ĺń tŮSP}§˛Ą- ć†~ŧ‰Ăaiv8/|%™¶Ź|śŤĚ–’nŁ”xcѰç4ú…ţI-U7úŰ«ő0Łő Ľ ’9 ý‚äĚy &śůöđĺ4'nýôٶl¨+v.ľš<‘ĹÝ~÷ýüĂô>ŘŰ˝·„śÍF¤ĺLc©ČČŔAčx!°›{ĺđň$8Xđ}­‘á<ű°Íćěo€)®$ °2ăÁˇbŞš-đÎ …‹Şg4QÉ<¨Şa¦ę z¶É vS¤źb ©Ľ›łÜ¨äY.O˘ň%c_HL`8ŇäÁi`ŔÎY(T F® ٲP!;śÉ`]]^FŘźvŮS‡YüžqĄťtq ąßýU čČ«‚עPfΛ±ăé9;(ĽŽ3¶”’ü™—ÉźĹzŽwęDč•s @dţ*Z\µ@?Ŕëŕ:ÂĘĄňłBΖ-uutäţŢL¸\čYBć ÇYŘßEq Ĺ™@ßř[Pµ×ÖHJ7(ź" nfęÜ×™ó˙^^zŚĂrćíTrvSu]_&<čăËtoX9ʨj.ÍüŹ`‹mË©  ’F.O<ôą0+ŕwI8C‰˝Cǧ¶¦5]WĐ÷&u2€Čz»$»ý§k«}ąÓł˙śDČŐĄ‰[HŰÔŮ®lCD~>`ǧ\ťi)>Íš˙aB\Ń(žŘâÖRß'‰+M€ŹĎéÇŁ=p‘”·źwőŹĹü?yË~ć ‰aL±˝Ă˘ě’¸g匍ŠbgÉŤĎfX °g»T)|\ţ"H`ĘŮŚ‚8MŔ•KkďË>:ădü;̡šŕ“8·vČ&™"… ¸2X›Ťřd0í<_÷łÚüż ”sƱ^L!i3–l:,Őpa á*xáëß<¸PŽ«or® ?8 ¬ňgéĐľvEŔIV8szzTÎôĄ’c0qeń5ĘŹ pňČâŐ! "ŕ<Úôë±USr|0!޵řv?zÍC "ŕ$ş/m®®‘JÜşDŤ&őÍÁ®O["ŕ6Zô•«ę²ď@ŮĽ„p-Ľ¤Aĵ*‘=i꼴y&Í8Űńč°źpäaµž«@l׸ôŰ"PŰŚťćX[NĺŃëHç]Č;ň SZč#P×@RÉíŢ>/S6jěħ±l-ަԑ˘Ý&PËĄ :Îbá»oUd×d0©˘˛TŚX'PÇŚd„uŻ €ŽÍ·CY k®,(‡AH.jJě:Ęt˘Ý]…Ű‚m¶.»ÖĺâŞď˛Kʨz ±úr^~^ôuÓ3¦9€ Üé—ˇ˙"Đ6UŻ‘|» ŮëMܦž&ř+E ,*g$ěWĆ>ĄXÖń´üećeH+Cń"ĐU$§6ZŢď…ŚŃŇŔZ–ÉĄ Řş´ámÔ9Öˇ=ÜoÂ6lľ —8˙­Ë¦ŘűŇ.“’FŃ"ĐZVf$čTáßíýKS —ĺ`űďăěG<‘8@:.e ŕlţ©˛:\ĘO ÷C~ę’]˛ED@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@@@ż'Yq3ŔoXěŽ"ĎM)vâwÄĺü!%ť˘-@}ńWŃL°^Řgř‹rßGýŚÇ4!11INhł!ţQȢIéRâćÁÉ4Š6LuwT˛ţⓨ—źÇE글@vV~ň7{ńíL‰Ůţ^€‡ď@ĘLFéu(›Č …j€÷QRŇd„†¤ý¦|5ĆŞhMH T"N^3BôTžj@mXĹHOý‘áí›%Î{CăâfµJ›€@MH’č$Äᤵť7Aŕs|ľ`…„ä&Ł~ä•;‹IĄŇ5ťŘn‹­5ĹCD@D Z|8O!#ś¬î@Ňu2&·ťě=ŘóžaĐ•Ľ!Ňŕů)¨ÚŇ:©ČA@+$ °p‚ÚŇÔ•Éoőbžq_öč1ŕ¸rîQ,·r‰€€”%  I NLWú3DÝŠvu÷2ÚěŞq®ŰtsÁĆC]·Sö‰€@› t~B‚“ŃŞ©^@eoŐÔ ÷\¸Ą©ö×a7Í„růzďGu”Ż2E@D@¦čä„'ˇ ˝“7W„ kQŘČómµůdĹpâwxN‡LµR€”Š€€d&Љ‡ZqâYDĚś™Ló>ż§âˇ×áÍwĹšübîdkÚĄXD@D 3Ö®ŕdüsH/€ĆXH—&#~ŕ÷QÎđč˙t`r¶4QG´ćÓń8Á̦Ź@ću„­‹ḟ“×\4¬J›Ľ š‰¶śCů5’˝B‚Kßkąŕđ D“‘ä1Ě^ONŇîXř<41i7(y'" hä„'•µ!| őćŠyµˇ¸ąÉá€68“Çř|8ŇĎš'ŹŇŠ€€TC qśTΚ;«ÁÓęRNᬡqm H­ŔONŔ)’WyD@D@ěhÔ[68©¬$«Cř¦"ĺJÉHČ— Ł ů|®ăYUóekNjř·=¬m­Í© Y*" ńu/'–ßÁ• ńîôbř+>ŕş Äź´ô"ô'•Ŕ¦Ü”šŞA Đf6„ą;Y2YµZ+µ" Ý#ШTOÚd„5ČIß$á­†!ËC6áŽB"qÂłlbކD®¨ŮšŚ4„‚ĚfhÚ„¤U~…őIOź”ő!ZÂ'Ť€9o]y W™ŕÂ|0ü`WĚD@D@'Ш+aśdδŔ“'ß/@ôŔc4ÜĄ11y::ĘÍŁh'ü}šÓ S-[ČŤN~‡Ś˙¶E>6x]dą^J«‡üI Ž EÂiđŃĆX•ÉŘľ4ž±yAńô_9ľţ˙k đő'(x» çÇß…Ľ áJäżOUĺe,ç¤;rXXű"2|˙ ĘřzF›ęNv 8<ţR·!®–݇>Ö Of“ |xö,;úĺ®/űĎÄá(°p=ś «Ś¸ÎÁeűfŢś¦}Ăe#]¶ üřĽW/ŔN×&#D7;„’|;˝˙/â˙fLĐÁđqř|yw˙™§<଒AHđů>(ąqbŞöGŽÂ,˙=×ÜD§ćĘíŰ4A·A+$A E¶ ±H>›yx–(ˇßÚ ĚâjCk~0łlÝG“VH˛6©‡‘đă`SĺX–Ő6«é´B’/—™˙ áę …?]ĎßĎéZxÁó.9 {xĎľsŘĄ:(j ęŽáEów!řÜNHđµ5“ř2K殀ʫ ĎÖ7Â[t42‹&$媍”Ű!ţ…'Ĺ—Ę©lLîEzÝeÚ´ŻÖm1ě8ąnT~iǰ=•ÖŇB—u[ćÚ±0±e>Ůpg(őo{ýČF.éÔ„Älmpéů*'(śś\qîÖl2~Wç‰e gńŔ­IčmŐŶ„px[ýËëaäÍ“’žăŃ >Ď0o™„Žsĺb1Č:ý!†<1®D™WšRÖ!=G˛= üľ­>;wď6 4*‚'ů¦>»dkHُç~'šĘ®äІmËç°ĎtRŽĺ]}í·Ě[6™ęp3%´Ł~ µFž! \m]°„~ÖĹň9ÇôŘÉÉËw űAŇn/L‚-|“ŃH@Ůeź!Y˝€!s#ëeČ |¶°ęđ9°Ľ¶ęBm–7ŁMĺŇ=€WŁ^°1đŮ•!r§%a Č×@Gá+nÖŠŮĘ뜌XóMЧđÚŇńhKßďřľ(|.;™ě^·Íep˛ómO?ÁźAz¤56PPÁŘó`Á¬™˛ÁNx.†đąÓáčźŇ&¦Ëµ¦O·l¬ˇMU< )‡řĎźśŠm>$ۆp/: '\VtoĹXQ.Ą®řę»Ěj…kţdµç—YƤ['*ë“‘˛űÆźCún őEtdľ?YŇŕúťÝÎţĐŠďfiB2¸eđDjíd:¸¸Ţ‘ŃZ€ěď·Zĺ„ĺŽôM8ěkÂ_2b3:Ż8ľbD™”4†@oČť6Ť_ßíJŘ´ŚŁGx»GÁA¨›u㼩/»N@YĚAws™¤[6ý¸8 ŮŻ··Ĺ+łżB¸$É ‚Ť0Ťsʰbă3'ëůÇŃŘÁöÝ>‡Ň¤đuŘţuŔ#şř Ł}JĎ3˘ŘŽ’_ć<™đjxŞS¤µ󰡢ܿ({*ÚŇ%ô8Ąxx«ŘD8Űëkü·• …Ňať@Ůóň'P×sY·ŇBe·`’3*yUÎ7`®ÉaŃŠHëßŢá$…űQ'Ňc1ŕX]Zţ= ˝xkč.k'“’ŚBüąźś”FqŤ#°-Făü ţÍdŔúŃNÚöLÜňŘU\9Sßß[±µT0¶ë'€~ÁUóMKZŇČď“hB’^ëĎ#É" qĹ„_:ää„vň»g Á=…˙•”7˛6¤PđâW*3 ą ŐĽáqýp2ç:SÂǵßh“Ů(áŃo xĹß˙¸Â€'TËaÍU >‡ö”×˙‚˙NÂNŮ,ť`ŘT#P÷7Áö2+čźj˘ďšd«5rş ÂdŃ@[CřŤ†ç! UV&űs!˝]›”Ńg(ďm„âëÂ&źůČß×˙v@CÜrU˛lŘšíÁÄĘKY[Jç—«ˇdöŇŠň)8Éůi8śš¨äcY&őne2Ł®–,“żŽĽšäŁÎ&oăÜ‘/[djľĆűr Ç˙۵Ô˝›{3ďěĘőĐi¤wz<¸‚ÄŰL "€ć÷› \ţ•·'ˇ-ńY°Ć ™ŕqÉň\›M†ňđD…+,kÚ,´Ăş˙TŇ÷/–Ě_yöZN€•{iľŔ‡ˇ’C™%µ°Uëá_gôĂiáUícđű@? Ü‹Ş*Ű+g)üßŇ{Gżâ˛U\ÍĐîľĹ¶gŔŚ-ĽÎ4ł]µ«’އaČîµÓoűęüAËű\´¶Š@}—˝]˝GѲëʧ Iqň\^ľraq‰9ů¨`Ř31µĹHtŚ] ˝€b¸~ŹĹ₪wÂ;U–7—‚ů´Ýlppăp®ĽŹŽôzśP,ç÷:ăt>|ľÍµĐűÜż7x˝˙łąf`GěiÜ-oMHĘ·ĚIPq&ä‰ňŞ5_ßăĂ{ë&¦¶‰1!®—DQă-Gµ|sb?USˇcĐÎŽd[3ŕöŢ rNşśQ4ü–Q/Ŕ(>ßq§3ĆM7„“NJţěmm7gbÓÔ„ÄLŤqŔĽÂŰ8}fšQ©…'éۧ÷ńŢßqřËo˘T0Ž…đłđ˝¶°dÄZĐË·•Ôf-vY-ě3ńńż7ŃWîvŮע¶Ń{ľßIń-}7Ői8ß¶ŢőĂz[©¬ř!Î2áwe2בW»Y꼍óČ_ĚŞMŐ¶8RĽâuvţă䨖€Ađ„~€ß1l_źţ*D·q u]ÚTďăę~-ŻŻĚçşĎeíł§ ›ůýŃ˙˝ôýç®đVľBţUÚŔňv)isăV¤4!)YăŮůvČvěřřoâmś"Rmč ¸ţż“SsXJ 'ů ÇäREq·q–4 K*Fí+„Ű0›żŻô =ŤS†ŻAřµč™!śáĺoŮvĘśFŘ.§ÁúO-c;*ő…2ůëČ« ‰Yę(÷ACčÍţńźoÎpŐ¤îp ?3ńţďZ—A`ňU'kdu>ä HѰ92ň6ŽVKŠlh>4ˇËĽvTö+ľ«z}‚-Tp= 2ůú‡?)Ë:ŠŻÉ7Łô7ňÚägax™óó-MtĽŚĂMôצÍdy:đ€Wµ°ď[·\ ç&(`ű“5Ć[[ŕţ9 ·¸zRdĐăjÉV-B—úßúÚÄ€Ď/ˇôť ýáÉ ĽŐE¦śśPNdůYí/#Ý^©…@ßâ+˝kpůE::ˇĚ7ŁeŻćGvVŠ“ç〛’,5u˛~j"GhBRľb®@¸/ʤçëy\-96OľšŇnÂN'µ:8©(:űç3'÷Cü oń<‰ dË5Ü *RÇÚK€}Ńë[®­D¶ş™ŚŰĚ'Ő7ŚŤ÷"Ń«© Ó4z…X’ô NJń/ ~…Ż÷Pođś”Tcq&'ÜÜ)‹}Hw<Ň™|Ŕ—m÷'(gB΄‘yEłzű ú$€~Ĺ•Če4-—I^_;4W¦ęP}‘í(ő{5ëŢ|Ü€Gˡ݇Ç@j«SÁ«N…bř~˙yŲĚ=3ŁM.ŤŁOŚiÄŢŰýbĎRN¬Ö?śí÷Ä˙;sô0żÁ®Ľ\ć©ć'“ŮÉy\“nJ×ţˇ˛? Eű{˙—kš˙°›máhl=}ł÷—ß9Úţą2Ř#`[‘ÍÉE255ę’·Tn3l??N9ްÎĘŐi°.†ü T>ŻřŤčă‡'ĐËŤ)­^ďßĂÔ ü%ĐoŕŘčŠMa»ćjŚÚwĹŕ],Ýjyص‹¶ĹŮÄţ‡ăŰ@řkĆÁđł„ôÖ˘`ŔÚP~fÉŽ(™ßéě`´äqż˛`¬ŃÉĎŤźŚ°5`çoĘü-—CógË–şýŹŞeËŕvŞĄ`ŢŻ!|űeoČç \˝PJ  _˝ á„Ŕę]ĄFd, '®"}ä‡ţ /đźŻ2ď 1ľťk˛¸tgF·b“ˇZý– 0ĚYň Č3Ž?á¤Řt0ő;O¦í*¬ĎxC-lI32΀ÎóÍ*Lĺŕ‰V˝ Ęş±Šň**÷ő÷ ”u¶˙áj†‚X'€nĹ)żôËWĚť °Ť“NśL„ˇ„«gBo”>~”đČß ě‡|»Çއ0updWČ:ÓaaÓ óč—H0ytÔöY´ă%j(×z‘šdG<Ť`ŹěÉ˧Dy7A '&ă˙Ęĺ5:§rćâCŞĽďŻ ŠsUŐĐŻ&Ŕö«żă˙¦®x{¦Ň® íáźö¤ÂbűŠâC/őíi#ŤŔŕµBZ˘&ÇkB’­ö*źŚÍB#\ë*Ë÷;‚Y›¶˝9 ¦0ppćĂ{ŻAtkĚ@żÚ ýj´~`Vs~m°c$r=ůXţÜÍËöUNĽšh ĹüąŤKjçžúôzŽ$_OOf7äTŻËnIÎhçŚ9ŰÂçOv€°.š¸Ä ł\$€>ĹgÂxrüCťöÁ„IŹÓزä±:m˛Tv›ž‘ł„¨§ö›Ó[Bďo'&#ôZ’ä&Ĺ[˘IyČ,YsÁXŘň+6Qdł Š¦f›†ďńÝŰÎÔKSˇĘîéĐĄ8áućV!ěáC¸+Aúě™8ÝâĆýýçČ即ĽąĚ•x?đe€ÎMH⫝̸l~‚Öńn|’úb`ď˙ÎWźµ—Ľ8,đWO¸‚˛&„ß"QBЧüÂtňdű.†Ěé ptČ_ 9l?So5Ä3–Ď*L'p6ţÍ×W‰Ó7¶Ĺ?ަîtಸB4“Ń@^Žră(ěăó|8Ź_+ÝË «jł‚Š®ÇĆÓg®z}ĂZňźĎ^ NŹ;čW|“î›čWEoVÖć`+_)ŤüeWżâ€l™b3Üĺ{ž'lˇŰ•¶Ä•«g ÷C®‚đ+Ţcń_!.ý7& ťY‘±—ˇ1ý˝˘˛Ś>\!ĐŞ×`˘|KĹ|ĄŃ$4“ˇ\ťQFŔŘ1;XÂ˙|Ý7Řo^C[1xPŰ"`š€+łKÓ~•Ńw['#tvĂŔ˛:69KWč'Ŕ‡a·ďßí=Ă '*Ťš”|Ц#€±ßeˇ(@m4!ţ1tĚ‹jÖěç˝ZŢĆáęşÍ˛ľ2kçBI{J‹íë &WOęµ)" "F@’~Băq2˙e˙nł·ŕËzô“˘÷Á› źőŁ‘śČúánlPŇúÇH?ţ‹€€”#6ŕ–ÓŢśÜüŔŹšcnvKáWKvDŽK˛çę|ĘO€Ĺ×bc,ÄX‘“<Ţk×[=€  " &4ęţ9N¬VjĹ9›ß¶h}żgáäb­w´ßC»UMQ*ED@ÚO ë÷Ěů!šNLFŘ”á+żÝˇ“hů~}ˇ&#ĺ!J€ tyB2'•=‚0ş° źyeĎ•±ŁşŕŻaŹ';„] ë•:č<®Ţ˛ák _ljĄóźÇmśI`1Sç{B<€OŁťÜ­ş¸BÂĐddzóľ)˛´‰ĆÔ·I0Üҿ䆀8M kú{Î6ď;]+Oó ŚbůÉă.†mčżÖď"ů," učÚkż'â¤ójÝĐ]-l¶¦m¸ŤÓöo—< 7W‡żť˙1+Wۢěč.­ü' Ç»WĹů='®–|&N§sěKżĽ°2ţk2âtuÉ8®čĘ Éßpşµk•[Ć_đúňóŁjŹŕ˙JetŐ”÷”»<üxݦňU¬€@]X!y'Ą?ĺ`˘¤`·2vËüÔ|@›őÍÂ^?,Š MF¬#W" "`†@Ű'$/â¤tŞTÝŐ†Sx–o:FáuŘ3?móÂŃŽŮ'sD@D@2hó„ä]ś¤~š‘’e žżć‰IßĘÜV’źÓ/Ě‹˙ăm$˝" " Őhë3$áDőťę0v«$°ť Ď–ĚŻ«xci"ĘYeŽëey+" Ý"ĐĆ’qňÚŻ[ŐX˝·`<ÂŐ’ł-”ÎߊńĂ,ŘĐdÄd©—đ„Ň€«ňe`ě÷ qßÉŕďÓěއZd(ęće¸ł@A—Xźk˘îî+_ŮD@D@N Q+$8a= ŮĚßđđ~ŕoÓđŐ^MF|"˙ű!śŕrRňß ĹźÁô^˙5ÉMID@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@ţ‚)@IDATD@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@ÚE`Ú´iź„\ů2ňgČšíň˛Ţ ^flY2Ľ^É p‹ŔP·Ěi·58™Ť‚‡·BÖHńô6Äo6tčĐÉ)ém™ęě˙PĢ˝˘fÄ˙GQ7'zűú'" "`€Ŕ tHE8±]Ťd i“jŰňňü€; ő˙źˇä… ţd„†L…,‡¸osGAD@DŔ MHĚpŚŐÂd|>6Q|Ä1Čz]|´bl÷9 {ý«"ŤV)JD@ňĐ„$­iq˛ú„Wֿȑ-*ég ç̨łJŕ;ĐţQB ¬Űâ%" "€&$9`eIŠÉĂHČ3H{Äß˝ˇłČ K“•&D¬GŕĐ"ˇĂQ»¦ę7J·Ž‰€@§h@5XÝ8‘]u!Ł ŞőU] ýóű;úo•ŔĐÎgED@D@*"  ‰Đ(ěás";P—¤â•¤HĹ#°Š1MR$" "‰_aT(HsĄ‘őaČČ‚*rgC™oŕ•ÓąsgT†LŔw'$ś’)±‰€€# ’(qŇšr˛> ©l2â™:Ęľľ€ŮĘ’ŤŔ¦Ů’)•€€Išä¤‰É?Ĺ7,˛|O$§öĚÉ·€ßĚśZ 3SNF´:’‰–‰€€Yšd䉓Őg!|NäŕŚYl'űĚŃk§f)ͬ:iČJ@ϤÂI>$yââsŹÂľńLIđK˘)):Š8®Šăzł& ŽŽ‰€@´B’'©ý*ÄĹÉoů$C˙KŘŻTne(E@’|üÂŰ3›DD»vhFú kF5ÉđăďŐhµ°I•&[E@ZG@’@•âÄÄź—çD„?ŞÖ¤ŔßU)ű‰ú&ůkÚV~&žő® " "PMH'óQç°yGMő`˘XţßF&uIÍ çě’ĎňUD@\$Đů NH—˘b&@u±‚rÚt üáŻÔ*d'ŔŐ=śť—RŠ€€ťťŕÄͬă2ýVČÖ§ô­úŠnVɨţa°xtł¬–µ" "ĐNť{'ˇP•@ř‹®­ đńUĽ ¬âKŻÝ˝‘DBKç¤" "`ť@gVHx5 y D)­ťŚx-f>řúgë­§ů|˘ů.ČhNLHprţŞ‹˝âęHW¶đ{Ď®8›×O°Ůy´:’śŇ‹€€%­žŕ¤ó%źéęďľś ÷—´Ôvš®ö Mw@ö‹€@›´ňś„F%= Ń'C†< ĂđLÉGmj¸e|Źő‘_ź‰/QyE@DŔ0Ö­ŕdóO0z˘ÉHcyŻS[ °«(€€¸E 5LD~ áí™őÜBě„5#ć^',©ŮpX&°ť(€€8D ńś`6‚đs¸C\]4ĺăŔÔ´OâŰŕx ”jBb¬tŠ€@ Ťžŕű|żĄ„˙]ËĘ \»kNűţÂ÷y°=Ňß×w4öˇVś\&ăpwP6Ć’;Ánf<ä:©1›3”ź‰×Ă˝ćxJ“€#ĐČśPßMFŠ7‰Ĺł63'Ú WFh¦ő˛ZD@ÚO qśXŽBµč×YK¶MpäŻw)| ÎęUß.Ő¸|hĆMH@÷°Fv×ŘE1)ąŘ]óĚY?‡BŰňć4J“€€iŤšŕÄň=Ŕăř„?’§PśŔN`ş}ńěŤÉą,ŐgâS]2TD ‹xĺŘ€“ç{„?ď.ĂŻéěŰ#>˙ĹC®/”ČďtV´›sa é űÎŻŔía§ť—q" "ĐŤZ!Óë ÁÉ1óMˇ!§C‚(ä'đ|ţ,ÍČÉłĆôd¤ÎËJh¦MHŢH`ˉʝ3 ˙MH§¨ŢęSDLăńW}D@D@'Đ´ IśôéČ™Ö^ůĂ7Óa&%˙4­´N}đgM”Ż7kꬕ-"  ´qBâ»Î{ü…ś yÝ?¨˙‰ÖĂIüĐÄÍŠÜ«YćĘZč.6OHX«ś”đËś„\áC± ɎƤdőä$îLJĹaeŰŰ·ű! E@D #® Řś|ůť'“2ňéj˛űqBŃpç‚ýú˝†W˘Ě辡ҥŔ‰É»ó!óC¶teRWsNÚÉ“©9`ű(~·&W•+qŰ /Ě ź6…| •Ď% 3A’Zâ5?Ŕ7o…܇WÜŰF€'čĆt.>¨j2|eŁ!ź5©´EşžÂ ´LÓüA;ů)l^вÝě;ťü ř. ßy4o†öô±Ľ™ŞN˙>Ź2Ź.Z.|¬ő–'ěß¶˙„·-mţ°éÝs WÁ_N^j đ•ź|¨r%ÔÓs,Ęy·:ÇĂ‹řŻP‚@×VH¨řŞđs~Ădȧ! ý–F‡?mźţCnoÁ^¶éE!z»Ć^Uń‡ W+˘ősÚß~r9đ·˛ ůW—SŕşĘľ˛t6đvîzž AŮ,’ăčo g ~Çó@EaŐŠĘI-ĆăŔtr/ärČÁă üWČ@ ‘KňüĘ›„“˙ANü;o斧ߍWŚM ߀ˇšŚ¸[[k =íí®yͲ ,W€Ľ«T1‰´"Ž€Ľ {n…|".qËŹső”“îźAďŃ@á˙é%Zî{)÷4!ŹW×÷C¸b˘O‚÷łą‰÷˘›j].o l<í‰Ďp)” †˙AöÇ ł”Pc+ë†PüoŘČđHŁVś,@aí Ű#2mÚřż°…r­R’čęăŠÉ~őőÉč$ť;Zĺ2l!¸čŕ_CF}&ľ˝Ę3˝\y‰-)í|yžÔŕŽë·ľ|â´óÚŚp.„·üş¶€Ŕb „Ďü(€€&$ÉÍ€|n‚đaÚÎ?°„ŽóF2®Úc7«Ý•ŔP´'®F*ä f»"ůă9˛¸–”'߉đăEČÚ®W=\•ç$Ťá5”ďT‘šd«ŢĽ §ĘßĚ–Ą•©ćB§ąÖEĎ`×&°K«#.VNĽM«ŁŢŽŹVLXqÉ˙üŕ±o/Ű5!XÇ Ž¸ŇŰÉ  Iöjç¤„Ż ˙r„ß3ébŘć@ďl'v°.ňt"ÚON ŔhKDóٶÖĽ}ňËÖ8c֑ߢľß†ĚaV­űÚ4!É_GśL„\ ą2ҵp2:Ëň®8 [V„-úš+’ߎÎßMB†ö= ńN®L&Ůť÷PJ|ףg€·P÷ßëMHŠ×6ŮM€ś ů ¤k'DľÎ6~»€|ČOˇˇĐ–šü\„męmüqЯ؆Öýǡo<Ö_RÝĐ„$Qj2|Â_ŻOMÝ®µß¶Bg]H]™µ«v«ő†oŽü¸Ú"Ý/ Lľ+G¸oi. ůĹŢ'rĺčvb~kf*„Ŕ¶:hBb®zůŞđ8Čé[Í©uZÓt’şgď°µ:ât3ÉlÜhOŁ3§îFÂZčć-ôɶK<żđaż9cĚwMHڎěSĆĂŮ?żúzwßŃönpö~Rîyťsî:ĘV™ÖŚË¸=6c:%‹'Ŕź ŕË­ šŘŻR®ürdsČR6†0XÍÁěť*śCYěKBô»5UݶŚ%Pż?C[úQµĹşSüźÖ8éü·5ĺtM‚®«=é©…­źĂĆĎ ďHţcĚ–äb2Ĺî‡T\1ĘxÎäë¸Ë@V÷„oΩ,€ůDÔĹĚ•XQA„«P .\Aŕó_„,i[x™Dłpى4ÉBŞ™i~A÷b ş]}űĆÄëžGßmW?ʸePřËż<9źáĹ× €´÷:Xß§aĎ‹ż9*ü_Ç‚ě±y~‰˛nýDŮŃÔcz†¤úšă ű _ć ĽUťäĄŠúTEĺ¨úÔýŔt}ž w™đNVÖ'#aQć- çV†ÜHó«Ŕv+7áö˝1ápç×#-:ş>ĆŰ/XÔ_ąjMH*GŢ+ť•W÷—B.‚đž`[‚č$ü.‹µýŰAą>oŤ°;ŠQ×/şcMĄ–ĚU˛´Ź—Ě_:;NĘŹBÖ…pĽŰbbŐ§´]U)€Ű|˝ůpĎ˙O˘Ü÷-”=ŕ ú+U© IĄ¸Ǝʧ×/†ly҆đEśHö°čH«® ,rję…Đ–~ŃG*ôámśťš°ĂžË TČŔ©˘ŕűÝYaÔgL†ţŃš·95!1Ý:Šé†Ćz„K­iĂW_ĎAGYŞŽř\Đą6bťlă­UŚ!ßF˝·ů-µŕëLäßą2娂ĆřżAx!Ľ•U¶čµĐf.«Ä…üš ¬ľBJá§U†óýÂĐVo‡đÍ.q6=vŢDŚńż„Ť Xăăb†tŐ¦F’~ôöoöŢ)ß ű|®ŁěŕPąů×ČŁŢA4Ú3!śŘ|Z;É„˛q3ŁŁÜSV‰—˙[řo»> ™*5̶t¶˝®©,{1´ŽkÉžhÚoE żk"Ü`BIť:4!é§µĚ9Ńű@6€đVŽé0 ňOY”"ť˙´vä5p"9*‹źqinĵîC@qţęx,=ŃÖŠŤmGÄK%ÝX´d~eŻĆvľ)s˘"ů•ĽÝßŘ  IŐ=ŠÍ¸·\VDoĺ|2b*Ü•Wď^^A]ž7oÍéCg)sĺvěoĂĂľ5WC+Šż»éoJ-LN‰OŤź/¦&Rg`H˙.Ś1qKň0gś*`&$ýĐČ‚Żß&Ýŕ»ýűCřÄى ?śs¤P@ćs.ü É§µ Ů’#Ó(GĺHßKŠ<#°1Ţ|Jßjo´Ő;ôm«±VżÔVö5űUöafšxÍ>”*^’řx‚?gŕˇČ˝őq”“%!Eţ€X©+~\>­='ä)H„FzP E~ĚlČ̸%WN`Lí˙Ę**›Ť~7obÂO×> .üZáü_˙y´nM-íđŘ~®űG˘ý\g@Ź*ŔĺňŻšŚ ONô€yMQ ŘĄ ä©=‹&$Ů«€·:¸„jęuÚź`ŕdŕíśZ˝­a—şłľęlËŢźÇ PΉ‰VGlQvT/Úáž0ÍÄçł?v´•Łnć6 \ÖA¦Ľ×ç.'%''·pŔBŕ›:+Ą¤WtyüüDŃŔG4!ÉWeĽjż0_–ÔÔgöşxÍż=Ao „OŕĎ ›jµ˝ŹAő¬öÔKłăL ¤W˘_ńÁͶ„‘9ÂqâoÜ:É!»ÚfĘ˙ÚćPš?š¤ĎďŤ}óf°¶ţ#Aź 1u/˝_sŽ-LJŢ„đy—ŃWsd5™t(«űŠĐ¤?Ň•‘ÚWĆVÎ<-Y‘ź)HÓYK<¸|‚]ś`äML8Aá­Vsž2§Şš4!)VOL|?!\:ż[ňOtěw Ë„#«ÜÇ8«ŐU!&^ËĚc>ŰĺN˝e“‡ZKҢÝ= WŽ7ŕÎpôŁ čqB¸L†đÖń[N4ĐŢÂyĽ_†đ‚FˇĂoí´6€Őĺ śśqéáHţҰnÁfk}KdKÖžTš­ËÇ nśY•™´éML¸ŠP[Ŕř7 ň9Ŕ§ëmĽÄ+Sߨ¨Ť“ .L`ŢÂ9f´ů úŔ’jŢC<2ÄźśđíŔşL!ťŔ˛éIbSŘ~®1¶ŕ2š”ˇ78/;ý5‰Ł*9r®71á§ŕk űř˝„5`O Ď6„ĎŃÔúĆ‘a¤.#´©7t׌ɓ’ E?ą?)AăŔŹ““ §ř˙˝5ů9#řź_SŮM*¶Ě›a|öŞqAóU6ý}ójsiĽž_}];W.ÉÁáu——‚Ľ*ĺw%L,ßöXęl@{şeüÓ@9«Łěo@O#U€#_ă_ÂÉÉJ[·Zăřě ţúNI °a˝” O–É\W^MHĚ“żÝSÉ{Ő†Łđ;Ѱ߂,Y§!óžĚ>1őÝ„˝ KąÖY±5•Ť¶´Šžb řSŃ74 §Ń*Ŕó1Čç < ކ\W‘C7UTN‹áď• /“ą®Ľš%ĎIŔyT‰ľÍ‡\«ţş)‹NŚřĺıN j `r?„ßMŕ·EĘ¶Ý ŤĽWZÖyĺbjÂ˙’Xö@˙ů,„““ő ăúcŤo­k\c{~ż¤+|t qAłUö?ôăľ$¶o„ú_š-˘°6Ţ:y“’‡ ü|m\®GáCţQŇľ-ÁźfWč´!>§µ• ·ŃLĽRl§t€ńŃ0Š—Cڰß͸Ňv(ܦ¤–Ě_KvMHĚaU&čĐü˘),Ě•° yÁÍu„˛yőE;‡śů7¤hX*šYůšK}ëjXĄVF›üž=­TΓ ŰAŘoo5ěäцő5^Ú"/´Čşp@Uő]VRCFMHĚA Ť€WmŽóUŐ©"ę=°1>ĂĹ5±K€ÇŚŘć§CŠ^©ňJ™·Ë:F}ë‹pů}n‡ľ°¨=­VŢĂA^L şL˛wŰđáĚGʜұ„š©r<)E—=] ;ő¦%Ó¦ý˘Bă6Ž(‹+Lü´7'&ĎDħÚ \›ôĄŮ¬x3ć4ŁfČsžž· ékĄLJcĽ00ţÓeÄ ú•l]Ň„ăJćŻ-»&$fĐó»Ż&©BÜ•BĚŮĎfII–5šoß)€Úź‰ Ăß7¦&$fj.ÓoĘ ó™‰o›)Ňš–cĽ‰ÉK%lźQď4¤» r„ÄĘ8@rÂĂĽ "€ľĹŐµ˛KÝ$¶4dn($sޢÎ4ö%kň±”řNDcÜĺů¸ěůa"ꥱ+Ĺš”oęĂĽ‰F&MH{2ţ=Sâz]čML>gĘ č㕯fł>ŘĹ+±Ë B˛<+°$Ň-Qčô­=ಉđ}Ącč » ćÎÜźqŮţÍNo™xöăČ&Ô„¤|íĺ~(ťxsűNů˘+ŃđWL$&AÖ2PÚľupb2 ÂI —#?€$…O#˛ÖW›“ŚSśUó[Ő.ĺQĘ^‘/Ą´KÇ0ľîW2ŕóńtÔ¦B’rč‡crqKČ7G‘|5ĺá'žďF§áχ/QÄ/'eŰëŰ.Í_IzµŤ\·nˇKýŠuηÚŞ#đTɢʎ %‹Ż7;ĆĆEaAî Ű«ź@űçŠrc&$ĺŞîÚrه4íjn.řË/ľňËŻóäôý`¤75A`»9r=$.ŚA„©2ăĘĐqÇ`P~&ýÜ1łÚlÎË%ťëě„ăčě`çżÝUŁ‘/`—µˇT~MHŠăď˛âŮ{ź—çIu›2:jĘ»$Ę} ťé~Č,i6 WRÓĄé‰ç9ă §An‹‰cšD€iű!ôÍďÁÇg›ě'úÍn^đ ÚĺP¶Ź±w. ^€Ó\ń5řC¦cM(ŞS‡&$ĹéßSéöJJöÔh~Çŕ1'&˙¤&[µń.m˘o-ŃpĎýôá9ô±— +8ęOهRźvÔ/kfˇ.·…ň˛+KAű>Üię¶ëb5ÇŕŲÎ…sO-{v°âęŽl†Ćp~¸H#«EÂÇ-íł¬ű!§{Â(…nXĽ‰îŁßě˛{Aě?†ăĽŕCń.…˛ýűA—ś±m ęďv”ńgĺđŮ‘VLę4!)Ö*ơ”}˛|@ÉĐ· Ő9 €jvvEgcŢżßżżx+‡˘ĐqčWĎÁw«#Q·>˙6˝›M;6*A•Ç`‡‰Ź=Ym®Ňď"eŐ¬7ä5ý+Ç«±ÇĹ<šäŻ2űEţl™rĚ–)•ű‰ľËއŔÉß˝pßsYčLJN„QE'©rĐoř†X–đý^/›6íqüŻëăbÁ[¤Yl”ő“ö˙ žôţ©ä!X”ĂŰŁrÚNnâCvaťµďÍVŢbc›;Ň’AăĐ®iIw-j5!ɇťŻ§ť”/KľÔh`÷ Çaůr9źzSX¸„÷š51qľşZk`ŢWŐ+óvä8S4l‡Ś|–ájČjE%ĺ^~Şź¶– uŢv22Ĺ21!˝(WB¬>„ŚsĹh”ŃŞP¦áW5ÍďNÔ¦ˇě[…đő6”ł~eU\ź“áŰ/|ŕ´Éböť_ˇ=4ćVě5Đ6ąÚPřAD0«mÜíc`ű…F@Ä()ăěăŰh6řĽ˝P`ß1¦§†}‡ Ńń© ł'öžŔž2«^\ťáŞtÖŔçwFBřżî0/¸˝^·¦Ë·ŃđMŰاmŻî Ééh|‹Ł’ßEAłVRXő…p ř#„ż¬Ú¨v衢͚x0ňüC޵ľŃŻţ{7Čcsž´Eý]Ű ~¸Şđ( ú'„<đÍ“ś_?óc{4d{Č—!óAL†—Ájˇ2 Á¬Ě„¤LŃućý¸•~v§NâĘćk’ ŮđGô*›ŚĐ$”7ŞĹŽW;Cކđ^ôd?bSAě@żÚýŠím¸ť ke?¨2¬„Â({WYh ,×^_ćěćçŰ:!ń&/™WÝbx5_GX¬ŽB+,“_qÝÂ{ßšTľăEÍé’˙ ńäÜĄö˙&N¬ť»ÝY˛Í­ f×”ÔátvMH˛U?]¶¤fSˇÜçˇń«fµ:©ŤËÁ|#gKďŁ+€5čWďCůVÖ ČŻ¸–ń%ż™Ćr,mLS7ń™‘»ÚîŞ&$ŮjřćlÉě¤BCĽšoG»sZůeÍ}!ĽÇ_řa7缒AÎ@żşFńmÂڍȆŔţÍŠĘjz1/Cë`ŤŞMH˘¨ <ĆűĚQ?2äUđ8 ˛ëaE+Żš[mE”kBMŤ ç©č(玎r΢ú âŰĽbÜÂZÁVłEßŘN°ÎžVŘ}„_ódýp’ľ+„·l‡ (ŕ –‹Ŕ‰Č¶ tP?ߌąr„ŕóy† ߀‚˘ţf°ČÎNH 2”*G`üX¦Ě áCâÁŔ7@¸âń"ĆEľá§ Öđ~»Â@W ÜmĆ‹s1¨đÍŢ®PH€W”{ ĽÇ®v "ŕŔřń¶) "P.˝*ôŕ}żFNHčlß˙Ć÷»Ł­5±ĎŹ«­ŃW_Cp´+" uĐ„d ýĆ<72Đěţ=LJśm±ßÚÚ¶6@Éś,ů°6+T°€@-]÷ˇÂoZ´ĺ >¬öVżkÚŠ!°%ŽóŁjWAř-MĐAAD@ę  ¸źú“X]hĹŐ2üxnmŢďš¶°đ_÷€p"Ç JÖ ţ“•”҉€@  ¨Óńí‹“SX5*“ţîĹ)Ť2ş^cG ří!»@řJkÚ람çFAD@DŔMH¦C|'đֽҟ„{Źh']R1 śĺ¤„“NTă&&<®·AAD@LĐwH¦ŃópśĽ_6ÔExx2ěâ32 ů đŮ>c |Cg ÚĚěÁÚ(N@µâ-‹6OFĽ¦1+ţsR˘źŔBȲ7„~ţ™“ţ†Đ+C4!2ä׆X:«®)X%á‡ÁřĹR…b81ˇřá3ţ†ţ‹€€”'ĐőgH†ád݉“4üäł$ß*ßd¤Ćç"!" "`Ž@×'$›Céľ&śD+ŻwßRç- ®”8o¬ &čň„„ź‰żĄ •dŇFřĚŹńDzŠX [ń˝šbî+—€Ř!ĐĺgH:»R€ęC“×˙j`Ů©"ÁxM|^žżĚW«m„Ç ôc(‡e(€€´ś@'$絼Î\ro$ŚůаAś€¬˘IĄaŞR'" ŽhÚ-ŢŽI üL|[©6ÉďZâŔšßxYĘ`á{CçLšŚ$*U" "ĐM›¤]Ť_Ýî­1“‡gŕĚĆ%ş z~SRʞ‹€€4”@ÚŠSná™^Ť‰š Ç m§ î1¨›Ĺá.?Źô+ ŢŢË™OÉE@D@ZF Q+$8q= ţgAf‚ř“)úŔ[ű@j"€şyÂ:á8ia<¬Šä‹A4IŁĄxw pµ˛dw­ě®e¨—ů Bî…Üů+dÓî‘ç" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " Žę=2GŚ6mÚ¬PşdGȧ Ë@f€¤…)HđäČ!w:t2ţ+€xĐżfĂć†ö­ů!Ă! <ż|yr;DýD@D@D@D@Ü% wëF–$€ ¶aČúUČÁŹT“”í:DţKîJJ¤8h3ôłeáß~9!\LL #ŕČič;ŻĄ%VĽ€€€€TM@ $UWyVŕbmQ(>˛dHUáô-\đ˝]U*Gę&€ţ¶lŘ Rä‰*>ar6úĚuűˇňE@D@D@D@D H@ $AÚn\¤m YĂĂŻ… _ÁEß{Ř"DŔô»-ˇü+© áëmě'GŁżĽZP‡˛‰€€€€€qYľĂ`ĽP)"pa¶0äç· Ó ăr ‹#tçłwaÖ·ąŁ m$€öÍoŤ”Y!ö]>ĺĹď•(€€€€€3´@âLUČ(¸ Űr+„U/@ľ ™#*­#Ç~S_€¬ě=2CŚ@›ţŤ}rÄR"" " " " ¶hÄYé-DaóB‡Ś‡pQäo޵nRXĆ> ó/…ĚŘ$Ăe«D@;^Ç÷…|Żc" " " " "ĐZ iC-6Ü\|mąÂ‘ńźBćm¸[4ČD¸µs |‘ %€ö»\?˘óEGۀܮЄ·+5íź¸ŕš r(ä%En…|Ć!MšÂ'H.‚›ŹBxˇ© Ť!€6;ŚĺĎeĎa_UÖĐIk«Ö-Çpˇµä /˛Ţ YĐ-+­Zł"´? ÷Očף¬˘–rĐNgžC Ł zµĆTépš€Hś®žć‡‹«Y @ĆA¸(r7dëćzdĚň i´ő‰c ¤¨>hź3Łôď@ćhq¤ľŞPÉ" " " " ĐI…°Ű^.ŞVüÂ_ąxr dń¶ű]ŔżY‘‡ß\ą2wüĘ"Ö Mňµ0~s„Ż„ék¬‘–b×hĵi=¸Ů ň_źyň5ȰąQ§©kŁđ×îÇuˇ˛EŔ'€¶Č׿ö‡,ŃâF˙E@D@D@D@:A@ $ť¨fsNâjČY‰Đúä<ȲćJ褦#Ŕ“?kü‰Nz/§ť €öÇĹ‘Ý L(€€€€@§h¤SŐťßY\4 ěy§DţŮ 22ż6ĺH Ŕź5ţ7_ ŰPОF€?K˝D‹#ÖK±€€€€Ë´@âríÔd.Đđ×V&Ŕ>f dµšĚéZ±ź‡ĂďýŢ]s\ţÖGíí (} Gę«•," " " "P3-Ô\®Ź ¤­ wCř”ČłţÚ ŢSˇzě—g˘*ž,W}ń*±KĐĆ6‚żŰB´8ŇĄŠ—Ż" " " " hd’nŔEŃ‚ă!oB¸(r%d­nxß/GĂŇ'P=çAÔWSmÍ1íŠ}~g>ČÚśj“Ą" " " " –č˘ËXŐâbh3Č­.Ľ92§‹¶Ę¦vĂŢDTŰvŽjGJ@{Z Ůů=ˇŹJ¨QVh -´¦*;‚  y!‡C^…pQäȆSęHŚ€ŤB5ŢY öĘD‡   -óľá/×(€€€€€€€HZÖ páł.äDĆC~ ™ŻenvŮţë˨Ţc» Aľ'€¶Ă¶ď@†C8N(€€€€€€€HŢ p±3äČ ^ěÜůlĂÝ’ů龏ę~ ˛~zRĄéĐ^ćŔGf…hqd:ý-4°!ŕ"g-Čĺ~;ŕ-Čń…čŠL.G€»·ˇÜ™­ś*ĺn;´‘™á#Gć†č»#mŻpů'" " " "›€Hr#«>/l @ĆBx×÷nČ6}? úęp±ÄOèwĐ4rŃ8ŮT?´ ľNómČ"ë·H€€€€€{´@â^ťô,ÂÍ !Spŕ}Č)%z‘ú#ŃNB{y˛Jt´Žv‘ÚÇů ËBôsľ]lňYD@D@D@D -dÂd?.bf‚ěy§DŚĚhżt•Đ"|Bŕ!4ˇßCřÔ€‚ě«B¸ŘŞ " " " " "C@ $1`Ş8Ś Ř §Bř„Č$ČyĺŞ([e´žŔöđđ}´­ť[社%€ú˙"×hq$–’"D@D@D@D@D`:-ÔĐpŃ2ňŠ~˛?„OTÓřôŃEhkŹA7­\úÜ&€:ßn™ě¶Ą˛ND@D@D@D@Ü  ’ ë,ŰCx±r!Dż:R!ű޵ü‡¶÷k>ěŰĆ€zŢn~˘'G:PßrQD@D@D@DŔ -á¨+sA@˘ßCô]DZŠ´HŕĐýÚâ–Ëęš  ~?řjŤ>ČZs]¨xfЉĺúÂĹĘĘ(âČj–‹’zČB€Żs]‹vy'd®,”¦9P§üŁ=!ZiNµÉR˙oď<ŕ­(Î7c콡`ˇŮkě%±aě5v,¨ŘMblŃż1{D±ĆŢk,`Á‚ A R”*"üź—Ü€÷^NŮ2»ű~żßËážł;óÍ3sfvżť™c&Hb¬nVV'ů×ŃR1fă¤M [qŇÚčŐśěsÂ#@]¶Â«ĂóĚ™€ € € € @6x?‚ꉛ-Ąyé$ú˘÷Ń4»éç|őDż5Ú9[âF“ănóÍ7_ŻÄsv†‘ żiJBç …‘ú•­4î\G›ë˛ŁöÍLŔLŔLŔL Xô+¶xč$VF‘n¤ůŃܦM?AýĐŹhI´ŇĆš‹!› ÄM`92x‡›ě§yÝź›Ö)qgčôŁ#@˝)°zR°uzt);%0000(Ň“Ľb•:ŇrÓňŮ EŐ2ÖŤŽž/‹´‰–ëxW Řb% 6wA’[bÍʼnGB€~FATÍY )Ŕš+ő‰žA’…Ú˛Ź&`&`&`&P Ą Ő9™˘răň9iéBTŚuóŁ=c4•^“ć(Ş´IĘfsČ_»(ůlŽwýG0čc0=µDYÚ”µÔo9@Lk˛#&`&`&`&`"ŕ%6ńµ1$]ş"—Ňňś$&)`˘÷(Ů5A6Š€nş?ĺ&Ľ+ŻÇ(ńŇŤ¨ČFő˘`é)Hłj™žÍLŔLŔLŔLŔL FÔ0ĹÓK“/ńaRŔD{h)Îhid3Z M‡qCŢ– Éõ&ćók'@](đzŇ÷ÜÁ‘Ú‘:0000IŔ’|4Ý0©.uł¤Í^?F ,ÖCÚđuQd3j,ČIqcţŻúµ›Ż«IÄçDFŕRÚ98R'd&`&`&`&`^b“×6P L¦€úéÖ·‘6ßô†Ż@°UMŕל9‚@ÉeI´÷…-a°ßź,Ű © gíěLŔLŔ2B€±BżN§™Äú•ł%ë^őžl¤ešő™öÎŹôů4 )?±N“xťŔ5€Ž±™€ @. čFÚ§N1$U’Ą _›‘ ¦é{ĂרČ'ťo)ę>\$ő(N‘Ó-)}Ę.xp(Ęú̑ҸăMZÓmR‰ćNűŐ × f:ţI l ţ4Ku!¤‡-Išú‹©ÔeÖű˝HQşnÓ¬ŕß mQKÔ…2#\“‘uÂk_Ô DC¨G}fu©ŮąÚl=éďTüý˝M‚˛óŤ€°-t|!Hć.±&\(цŻ+ › ”CŕeR ä»rö1Ő ?ن3Ű#}WłnĄqÇ’¬×dţÓ†őëkšŃäĎŐŹ#żťéź”Ż­Ôß‘śŢ­†$j9µuř÷ZČÚąđÖĆűżCmŃ–(Ź×eúőµhz˝úS×CyÍ˝QÇ·SČŁs_Đň ¨Kc‘úm˝~‰>EjŃ4”öá`) lń%âo)ťúĽhĂ×hŇ`Ą›0íY˛:Ň MŃ´™@}väÍ ôg0h]Yß~Ż6°ŐҦŁQ‚#µÁđŮY& 1f*J2@˘%ďđşŤ×ăčŁük\€¨ŇŇd—űľŹ6Ş}ĄNFű µŰ"îAÖ¨ÓžĄâô_˝~Žŕ|˝Íwřc^ób Ů~"°˙•Vűé­ź˙o®ö1†#ˇĐ«č=¤ Ű^m&P5HŞF—ŰőtWíB˛4=R'K˘őĐZČľÁ6+´NçmâÚ{ŽOüGŐ`Úš“ŹŻ:źh& Ǣř>íJ˙¤=ąl&*Ú˘<ť†NAĄ˝ARő)ĐĚ5J‡Č?¸éE¦YşÖx=Ť>ŕ»­ëV[±,KqĄMfŮδŮÚÉpŢx=ŠzĐFpł™Ŕ< 8@2OD…? 0™ u2o!ŤPĐ7D«#·# Ř~Ń20=Čëa DžYCŁ€c3N˙3šÍş*¬!IźjE& §ňoń˝Ň2‘öôOąź•Päʱ촽Ĺđëô'”ä~ÉëôM`ĆMŃuŕąČös{P/ýüíäߡÎ5\7ĄVč×H3ô ł9R€:¦`Ńő”÷,^w‡ß<*Żep€$Ż5ër©#’ ­“"ĺ Ý|«ó]ŮÂ& ‹Đ¶ &mHŰŐňĽŁ, Řť‚Ľs€¤ĘB" ‹uýĘÍËĽîIßäŮ$!ŐNŚľPçę·/@zMÓî"s=<ČÝt}ʤ™ ďŐéĘŮ!Ă_v@Zšş%Z5d_ń™ązŔŇPa«x?ű?ęč[ü—´‘nOt7ú™Q˙ŞoµÎvF#íK5ÓŰ>”Gł›4cÚ ´;ů‘ŘĄśPŔDĺçčAtŇ uĆ-LşyäC´R.–çţ/Ď‘E*“#ĺaóQ&*=áÖĎ:ęfÍV m(ćf)U㆖x‰r™WĘü ęvAKˇů8G3N¶FWˇ¨d ŽŚ.ýá×ě >ÇŁ·Q´-Z© ,öEŹŁI(+văG?¤™3¶Ŕ8@X…ŘťD¨CUô\O*>BŠV+`ręŤüDنř3śäňŔü*ËüÖ~:ŇGʢćL xš•¨îkhńཱུµŘ•JłSkM«šó˙Ŕýŕ#Őś×sŕ1˝‰NGkˇ’˝‘×2»\s ÂżCŹŁ}ŃbH×ř[ ]Ó‡ľĎ›fÄ eüĐŚ[@ ¨2ěJjô=(LşĐ·.Z×Áj)Îť(Së{SŁLĆg0č©íöÉdW{.řŞ'\g &HK˝l&`ů"đŠ3–ďzŰ|ËĄ) nŮ®ôw ŻŻ’g·ňu–&9\ĂżG bëŐßи@ "ź§Ź95P˙ é–$…¬vş hz¦f’Ě4:ÖQ;´RDZëź˙ß§ţ7Eš…ń ÉËH_°†jW§!í=ú“Ś`9Ú1Č}×ďá;˙Z:ţÚĹĘhŻć•ťéŃ˝¸ ń)R'V|o4ĂäßhĘ«ľąS ĺľŽ±ŁC ľÎ-H Wĺe¸´@z2¶-j‰ôEOŔKźóß\Ę5]GÚŕş^>{éçg,YµCZ’cK‡Ŕd;žEł3‚3üR;9 ­‰|a\ Ů!…€öCĹ÷˙¨XRw˘iĐĆîš –-śVĆÎ×ňB€Ë÷oŃ u×ńR®±•í|I¨H¨‡ĽP¤:i˝­~nm¤őqǢŃŢh5¤@IÖ— č;0]N‡9‰×˛ŚcżGw˘Ťn„µ|âL4¸¬|P”.g@Ńţ$D™hiµ' -Ój0čANÂL < şwĄOz驥Íj%°mIł”l&`ŕŇý!´,ImŹFFdTI(Hâ_·‰Šf•é8@R%¸ꦛýŐçQľf|®ĺ&Çש ŻÚ…Yż#eĹÔţ'˘+é$ż­ĹiΉ®@Í‘¶B× Qµ¤ësË& _¸éÍ ˘ SżÄíE ŮWŽ”]…>ĐrG@?EŞŮ$Ě]ÉŠW őĺi^ßhâäTrw¦5`ěÖĂŤ÷jJ¤ö“7% ý¤ôbµ'ĺLŔć&Ŕ÷|2ŇuÜźćţ,…żő=×RÍESČ»đY:@Rř&Đ -S†nC6xÔĽ?ĐŻŚhšq;¤ +Bšq˘›Ř´f¨Ýw¦ěÇkâFľ3ĐÓh¤€”:żŁQd‹ŽŔZ$ő%ËŤŃ%ŮpJäłźŽB™˘Ů°łţÄŠE`t@ĹŐ,€–ĄÚ˛Eŕ•ÜU míçřbL —¸4żž‚i6üä” ¨}ěÎOهBfďI!«˝˘B«ŤôDÝP™šbÜ‹4Ăd/´*JjĂWýŢř]t~˝x ÂđEë;ĐHí§q6ú*łďÄI\LNB»ÇUŇ^‡´Ő¦Ó\ŁWńś® dťŔÍ` 4<‚hVĺ×ô§âŹÝ(Ź€f}N(ďĐXŹŇ¬Î´-'= é“ÍL B\ŽëŢgc46Âd«IęTľă3l p€$AŘÎJíä{ô¤ ÍüĘV&!ݸ_'Mm[)ʍo6Ń®ŐÝy ÖđďktZ)`Ň]‡˘P[î[„ôźfŃŻJ,e^¤×‚ôtŁŁş e ®ŘLŔę4ˇ+ý 5ăďKˇ˘ţâzúŹľ¨i >ŮŤFĐ~úóń#Ť’ôG ‘áżŃ4ÚĐPtŇXg3€@Ýw~'’Ň:¤eZjsnZ™5_HŠZóŐ•[O-ľ@·ˇŐ%ŃčYjŹzʧ=NDÇ ­ŃâH“Zn>yžÎî)^3eřüú3Zé˘ZSlďCS3U0śÝ74=ůoQ¸C:Úůü/Hí«–ö…;NĂL ~łľ›tˇşĐl…Öhâď®KŽĂčKÔŹŘÂ' €DÚÓîëŁÔŚ7;!Í–śŽžGű!LęŁĺ÷L LŚďsčQe×aűň]Öµż-!$:GŮč]öŇMzśÓMőtdtRŔDŻ"˝_É†Żşy} ýeŢč¬ßEm‘8hjíŢHőa+źŔ% 6#¦OVeś»'žÝźuVUb>ÉL N-gOśľSż2¦ Éyłżźň˙ݦOéŹVIŮgßÚÍÇ||~#‡„đ‘®ÓvFší˘€‰lş mŽ|íB-هĚŕ{˙Î^›˘ĂşŢ?9Ĺü —µ;ÉÂUydVŰŹîDŻ˘$nuCşR$WľVG h†I}¦ŕ˘ż]éŕ’đ±>b{Ź2MGO˘ť.Štł~,ŇEś­q+ňń{\,>‚ôëBeÇë©ÜYH{ęL/űDh&zű~şĚ‹q¦9ú4 §ęÉsMŢB˙˘ľĹ(ÚÍ•¸ö` î5ä–Úůičmô#mL¦}pîE"oÜ9żo˙#Đ—4ÇŠ]řž®ćĘH†€$ÉpÎs.ZvŁ›q-»’pA—#ż6HÍ0Ůéé›nX0‘oPG.h qK9'ˇ.h=¤€‰6|= E¶ú ěÇŰxÚ×˙ńśďrś‚nşĐÔ”ć†ssžäżLŔ‚$@79)0ˇŮ`ˇŘżég>C-BqČ~üŚ@[ŢŃĚÔ,[ś?=€ľˇ˝•¬˙ąµAZâl3Â`ś„KRˇkÎíRĚżPY;@R¨ęŽ­°şWâI¤)ťßŁ4LľîN@ÇŁMQ:µx-¤Qvmřz)Z©žÖ@7 uô¶ź¨/ĽŤ‹ÁĎQëźŢžó|&†ÚUÇh™—ÍL č5+@7ŚRő1ésÎÄ»1Ú‹ú˙íŃÓł˝ť—˙®MAţ„^Dh%ű˙h™ÎČ“ĽÔ¶ËQ ‡9¸_%'D|¬îql p€$ČĘb~Ę:ÝŽŢMąÜjۡ×ëFö‘Ľ^VMŮŻTłç˘Nżäp*Zéfst?*li® iĹßzr«źPT{žŰţŔ"Gć&ăżM ăčG"}ż`eÖaú"őIę›l ­h‰«f®j©Vl} ©Ů“/Łą'WŇF·Gśˇ%´Ś|ßżĄčzś–mÂwl™´2/Rľ©¶“+«n,ßAw LB°ĺqât4ÎE¦™g ˝_XŁłď…A Aő¶/zÝѲ›˝K řż6 ŢM-˝çW0ü ?Ľ…RiOíׂµĆ ŤY…ŕŚ}“íĺ<ŢŮŤ™ó“ÂüĄŔÉ_Ń+höŔIoÚěĹhK¤M&m&ŹR´–W· ď–y€z ˝†˛ëźÚÖôzĄŐ™u˝¦§q—#Í,‘iłÎCQE›uÖ›rFßä"OOĂG;"Í.Y ýĄ9ť0Mšş {ś6ń&RŔdGäŕHš5âĽM !tcĐ–d×…2›ä<ú"ý‰&¶€ĐVŢGÚíďą•¶+ŕŔąčMô=íV6=‰GZŇf3¬ř‡?OÉi]—jĎ,[Ě ‰°“źąQę`8ÜŠ>ÇĆřv/šĚ ý#zí°ż±»ĆĹž6|˝­‹0i†t±3,öĚĂĘ@7Iť‘ö´ -Đ){c9#@×§%ŁKˇ×)ZsüĐ’›KńÇnĚF€öŇ?uÓi¶·ýßźč»´'ş éWtdşîzµEK˙t¨˙gáŕ;>ŻĄčŮoSĚ»0Y;@RŞN˝ şÁîîAăR÷¦qô˝Ř=Ď`-ÓŕÝmÔřiůţ”Aa8ş­ŚTźkˇ›ĐŘ|—|VéD;­(™…Ĺ˙1| »űé˘ô@4-ŇžÍ4ůib Rr¶2ťŔß "-‹ňxQ‚S˙«fîţéúp,mZ¦ĺĐú5§–őźâwM USĚ}µó.LÖ¦Ş(¨ÚŰwHŕ+hĘ‚iđ>} QÓĎáiC˛U˛ŕ|\>r8ťŚ–E h¦Ĺ(”8Š® Ţ}‘ö&™eĄ ăŞÍL tsqţčąZ҉đ\ÍęëŻń(Â4ťTDh/?  ĐŻHr[Ô7˘¤‹ĚŞň,ôí[6]€ô€Âfip€$í9Hběäë% ‹…ţčV”f'SŻseĽ©Íű´!ŮŤÚ6Ďű+*ú†Żos!xZ6Şăߣî(ʦŕf“l€üt0Ź5ě2™@=čßľG»ńŃ^(­ź´źŰ3Ť?ş\wîüwh3Ż!mfŞëîvčË0<ËŚ Śü©ťË´$g«ĚxoGóF@m9&ŕIŽ+7đ˘©sŃÓwmŕŞYQV­Žë ^iĂ×÷¸µá«Ö!Ҹü=Šv@ŞëĹŃńH±<Ů6ćH¤uÓ”ä©f]h„ÝÚS|¬ďýcŤ–äGşě˸s ňĹ{’ä+Č‹v3݉Z ŐSôrIřĐ˙Đ’śž´uYw¤=Âl&`& H"ÁčDj  e úiĽn¨g é„tęŻqć^¤]۵áëSHyaŤëŔ‰č´6ŇEáĘč<4<Pü9iS_•M?› @Î Đ•MAűQĚťP(łIţŚ/Úü˛Đ{feĄéŃ~^FmĆŤ%ǡ÷łâ ~n‡˝hóÓѵh‘@ü˛ů% ďkZ–fŢi•9ń| Ią3l€€%˝Q”‡›ćR1őŰi:¨LľŢ†´4ٰõŕ0t1j†ÔŮŻŤ:˘q†˛:ľkŮŤ^óĽK†«Č®›@ôčÂ^"Ő%ă!–jϬ‘/¦C¨‘2| éABg´ R˝iĎ+]?<‚& [ăÄěOhí^łJ´GŹÍâ Đ<ŽDËLóĂ2Źóa5p€¤x>5rÜtců(zý€ňfÚđµ=ęÍŕ-Ó“ľËfTÖ¸ěŹNDË µ­‘. łhPźŞ§ÉmѢh:˛™€ äśÝÖ4tĹÔľßRÜ“đCK?7 Ä»QÚ“6y}폖DüŇŻ)=„F"[ý4«Dżňô*ZŞţCü® TN€ö¤ďˇ„ĄeŇʸHů:@R¤ÚÎNY5›DłHnCyŹ”6ˇŚg˘Żčteźˇż ĺxݰĆuŕ›H…ÚđU:˝š! Ëŕëč·ČKn2TqvŐj!@źőç«˙ľµ–t"m *ôlݢV~Äĺ^‹ôZDśfąÉMŕŔÁĺěăŞ' P› „L@mt*ę„N¨ű?/…1MŤľMa`ź†žD;¦ôő”«ľďPG´–®9dtQĎá!ĽĄ0{˘ý‘ţď%@°™@Ţ Đ=ő˘Śš%xc eŐ̶·Cî@ľţ ¤Rât6řşµCk ™FžZî«ë‹ł‘öĐ eY®Äf-Hym×ŘrpÂE  %niŮ@2–l1đ3`'_3ÝOF72Ş+H˛ꆊhóShÝhżÄ/ÓFdťŃzE„Q*3íb(ş5Ej/ë˘Î(´ >MË<é˘ÔłI€`3Ľ KŇĎşžB9ŐO¤Ľíđc,cÇřc7&@›Ô/0˝Ź.C;ˇĄŃLĂíŻpŇ>'ˇ´Y\‰Ä~E*ĎĐöµl×f Ý(ŕ­ëđ´ě]ľ¤“ŇĘĽHů:@R¤ÚÎfY§ăöutĂä>ŻZnq˙Ő·ÁzŻŔ¦ź˛űęC§-.EM ĚDm¤:ÍĽŕĹoĐc(” „¦¸+P˛|@>áŠÍL .ôGŁf¤i\yTî’˙ăĹ˝HÁw› Ě$@;ýÝŤ´ĎÉĚ_šăUÖAg 7Q(ă)®Tl*Ëý´űť+>Ó'ť€6ŕo™"„ÇSĚ»PY;@R¨ęÎ\a5Ý̸üłułĽ75çs=™›‘ą’Ĺă°f(hşě0~Ůt*Z6žě˛‘*íä ´Ň“#-qŃrś1){ŻéÍűŁÝ‘ÚąŰ0l&wôCçPFí 10˛ŠÚÄrŰ@ü± í~‚®D[Ł_!Ť] ú‡zęvCnéţç?´űU:Ŕď›Ŕěh++ń·„i™ĆŚ7ŇĘĽhů:@R´ĎNyu3Ű…ń÷ĂĆ\ćs­í^=ŰŘqýl Ę}MÇ.{€ »á+,4óh5ô ş uApĆŁ4¬™jžĚeů‰îŰLŔĘ!Ŕ¸Ą}!Zqě…ĺźŔ1C{06č†QAd› ”E€v<uFŰ ™Ć‰Űˇ‡‘öŹ Ů–Áą+CvĐľEŕźxŁ=ďҲÇů‚}“VćEË×’˘Őx6Ę« ´űé4ŤsžĆq“žÄo…Šňk7óäRĎ›ńžÚđőô8ÚˇžărůeŐ´ČSPi¶†‚pÓPt/şÝŤŢCߣ¤LOátA©5ßú…žéČf&sŚ[˙ ÍŃĎfI¦TôÉW{“´I)g›´ëWŃh!Šł:…zc÷ű"]ĺ yĄRÚö¬iźJć˙Ët"/z gK€$ v6ePpä ÖçĘ>Łî@Îy -Ďźşč´5N@Á˝ŃËtü˛‰¨Ň§ą3ĘĄ}YNCZk_ Ě^N)ô™ˇ^¨+Ň ”úŁPܦŕH[´#ŞĎǸówú&` `ĚŚÖ ŰłÎşˇětCű"}ćHăDÉÔGÚL "´m=Ŕşi °Ć¸[*J ţŐĆŹŹ?çUôâű(Í>đ!ľC˝łĘ0‹~;@’ĹZËŻĎ ŽĽH'đH-Eäü 9ôN-éěÜE)ŻÖ÷e0 G˙BZs™iŁ ËR€3Ń"¨ÜŔúF]8iŻ’îčVÔ =ކ 8MË€ţVC^v'i§m`ÜşWš Íh Áĉ ôź»Ô93‚×rűĎü· Ť‡ŽGşŃÔPlgÚą86í˘9oĽ€8NËĆ‘ńĹie^Ô| )j͇Wn틡€Ć=Q¸Ćř; mAZ{˘$—KDá~i(0rR Dö :iÍnf řů+ZŐ˛tEłKtQ§›„§‘–ă(hň"Šcę°úćÝĐAhaT‹ďśn3ťcÖH´~ž€BF¨ďyŽ~ô~^¬Mb&ŮŘňN€v~2eÜM ¬z˛e~Ř…€Đďio¸×iÚ|_¤é@óv€¤µ^™ő¤ţ#t ť@¤…¤§›YE~oB¶ę hVĂ h †L?ąҬź ß´ţYËjš˘(gb(P˘€‰‚ź#ÍxRűş˝ĆٍLKĆÚ!]ĽEY†¨üs:&``ÜŇl5]”ką_¦@íKH2l& Úůű$¤±í»H¬>ŤékVşĎĚ®÷˘L˘ĄS.Ű[äYĘ>2{H YíAZÁ‘/ĐŤ –±Ü’ît¤§«ˇO­v[„SH¤GĐvµ'M ř˘†ęĽ5šMŞ ¦˘‹+µc=]íîEša˘ŮPşŚbÓƤs,ZĹň=!]› @ ł4 rsÜiʦâ–Ý0H ĐĆű‘`‡H­.±UŞ;Ígĺ‰×Žóˇë)Ó(퀚]u,ßĎÜKˇ‘9@’tg9‹€nb‡Łkč¦Ěz7¦˙Ǥ)sGˇ¸ošc*EÉjŮug`‘}‡nBk§č­‚ ëŁ4–Ň ={uEša˘ _5M˛Ú¶§§·ű"m®«€L¤ł­HĎf&Ć,ÍLÓÁ7sÍî@Tş‘Đ·Q%Ve:ZVl+0®Y7Ąř#Ń)`řýß@|)ś®Ę)°ÚŢX¤µu“ôŠü4/†tĂj‹ž€Řžú1ŕȆˇ‹‘f?Änäs™lŤŇŽÔW>µu4´áë+¨3Ňz=ˇŚ*5=éjŹÖCžMR)=o# 1ý·µÔĄÚkĆJmw D@căG*Ż‹®—DĎăR/´\ ®ťGźŻ˝źl)Đ…»Í’& v7 ]M Ý™7ňťŠt±© ń†%î@±2lJqĎE#„d śś"_ŰIššÉ˛šŠB5ÍśŇ,ÍžzÝŚ4y U˛áë6ß 9H› äťc–‚úšMň|ŢËzůk–@A+‡îküÓlȴDZ´g°d šňĺ"ß]F§TŞűť*ÝuôőäO!]q€¤Őžjˇucřş– őŔ>ôAşŔ9=U*ĹĘ\Ko´äd,“¬'Úi–EŐĆůżăä}PČÁ‘ąËWZŽŁ ÄĎöuM«×”ú ¨!ÓTĐQH› @0^MF»RT-·‹}ijV\DĆÍ’|]ŤľâoŮ`ô/Ô‚÷l•нȂ•ťůŃ©_ŹF^"'X/ľŁ ÍQ`DK–C2Gţ’CEőĹ’˘Ö|şĺľŕ‹t]3wüąŠwôd®űśźřŻlEʎ´¦ ‡Đo+ɗ㵤¦­Ň¨äĽŹUŔD"•CľŢ4ĂDżę‚ü=ô*ş)’öS7\°™€ $M€1KO>—BO%ťw‘óc¬QpDÁkÍ>ťÝVĺŹsĐ@Ž‘éß:˘Íf?Č˙Ż—ŔĽ»I˝ź$÷¦Ć[[N đ=Ôl0µi~o´i€EíŕŕH8µâI8uQOô¤» ŔÇ!ż& đMjěÉ=Űb" §HűŁWČdĐ h­†ň㳍ř¬=Ęc° 4ĂDí±/ŇSŹ~h"r˙ › •ăŐ´ĺß EńkYEEYVąkJÁ‘ Ë8aŽ9˝Ăy%{˙´G+”q~‘é@aJ±ŔZę­±Ő–#|Ďš˘Ë‘®ź4[DĚ4ŰYCtő+eíčË˙ŢĐ~?yľŔNžyQsÔSń{čŢ >vGšMrEčľŔżĹ)ăÉč9ŮPtj˘˛óÚšm«%*’ÍLŔ E€ńJű-î+TÁ,,cM%Á‘†<ÓLÇŰĐ7¤'ŹAűˇe:)ĎďSOEŇ´˙ňú2MśwíôB§ Ź‘®µlę ¤ëČPm Žýšöwg¨Ő/HŠZóÉ–{˛{´î".ŮśkČ Ďätm‚é©—5pŚřTŐÇyčëşPO}ÖE Ŕé×$‚ÍL Xݦ!-3ÜĄ˛ůy^‰3Öhf㳨ś™#•`PPK‹kąähŤiŘdô":µ¬$±,KŮ–Gďáłf٤işfč–¦λr´ťeö®»•®G“ŇőhťĘSL匧ȵýöG©äîL% › › ÄI@Á‘éž3“¸ŇĆď᤭ ťâUű>¨<¶p,Ť+ŰÖI^}ŤŢG‘–ÜĚŹl&`&PŚYÚôzy {+:ş…ޱ°TpäETŃľX5¸´0ç¶©“fI–’Â^CÚŻëmęy`é,˝R-=şß/ŕÇ“řb7f#@[Y‰?[ˇ­ĐöHË©›Ł¬ŰT p`Vż\˙ )—”Ź«†€‚ o {Ş99¤sčČ łÖSMŹm’oöe+ň×nuďh]§¦ÍjC®auď9`RÂ/&`ů$ŔxĄŕđ1ŚY7ňú RŔÄV!ř%iĚĂUůP3„¤Ů'“řSűşuGŻ ŢÔżcpÔ’XÍů i)Ńdü9^ł˘Pü][zŃ/8ÎCĹSKŇAúż®»´l]÷ z¬€š"ĺżJÝßęŁô~ŢíA x8mNA[Ŕ ¸r2îš:‘6eÍĹŕC9´„ă(•ńŞ‹ÎÜNĄly°_RŐQ©žôË0¦3ŽEş0Đ160ČĆ,-AÔŤ%'宀1f!G+é˘|¸YťN×ř®—’iŹ/Чčm¤ńď+4śö1ž×HŤĽ[“ŕ¦HK‡Ú =´ŐNAźPť‹ŮŻ»bNßÉĎI ?îE{űlηýW¨ µf˛í—Ú•ă›é ô?WF™ÔѵâB@ś×#ßdgن´[ŻNňř;ô ę‹&"=ĺPĐÄf&`ą!Ŕu2ă•‚$˙Ezrkk„¬˛i¤ł>ŇŚ IA”¶łŢĺ?”sö?K˙˙ž˙h<Ôě I3TćµwŠf,U÷ĘKćě*ľť2çµÎopxÚÚ[YsĽčţ:@Rô}ůu“9]K‡ë)d”ď&.0şRÖ‡PiY˙µe„€v6/=y“ËÚŕKO×ô´M‰Áf&}ŚWZ†ŃŚ1ë^˙–ýĹSř(®@ŇoăÉ!řTµŠ”g»•ďĂéy. Ë–:ÁxpíěÍÔ=±Uđ“練ů¤¨=ŤBŠĚë©CîMĺD»SĐ­ĐČÜ8ß\Žâí€Ú#ÍÚ­‚dZÓo30L`Ľ:‡¬Ťgş 18OpD×0ÚuŰ’w’a¸ďŔĂpĹ^ä€fЬIkŽÉp{I†+/0×uaˇi™WÓ)Ś Ě·ŘݡĚę›puŻĹžˇ3H‚€¦˘K˛ihŇ “Čű—Áf&=ŚWýńş9ăŐ…Ľţ={%Í㤬¶üĐŚć=hű/ćŻh.QĘt}xşöĄŮǶĐM­Íj% ›E >×Đ9|]kbY>źň˙˙5A[~(Ľ:ú=:µGš5¤µŘš]’»˝v(“ÍL ÇŻ.¤x«ˇĎs\̲‹Źó®gôS´šE¨ĺ–¶ěčN–ŁjÉ~]†T‚çqf]ÚŐč˙#!ŐNŤľ8@R#@ź>“€vúş‘Îay0µ`ľůĆ Ý<ëI”69łĺŹ€6ń۵E 6F !=M¨w÷;Ţ·™€ @0«† Ď Ć©”Ç8¤Mć[#L4“đ4ٲC@ł™w  %mĘn3Z ĽD[«_ŔvEýjMĐç‡IŔ’0ë%K^éÉzg: mg›ŤLžĺOýü ł˝í˙ć“€6|Ý…ôäń@´&Ň÷C3L0‚ÍL LŚWWŕŮJ¨O¦çlF KQKTšar ˝žžWÎą †ěOU-4{ÄfŐP[ę„Z黏턼·Hµ43tž$ެ]ŐnďÝč,zč[.Áf:g4ŤąNى$Ěľá«fěŤVF ”(`b30 0V}Ť6Ŕ)yÔm v`¤&]ŃoŃLăĐŤĐż‘—+5Ŕ-·‡‘ÇîTČč‘ňsů#0ť"i)–Ú‘Lmé40Eu‰# §›6¨†€‚#Ói8:_=8 á°µŮŻŻ·#'Ëŕ–ŁCšQIVÚđµ7˙˙鉤Űl&`é`Ľş™±ę~<ŃűMŇ÷(|`¦ţ\ú[É[ŠÝ!h_´Vé}żFN +)žAŚŽ+ůGžŁ3yň§·üżrŔ¬M÷qěÝčŔrÎń1ą# ~wő:©pSĐ'¨/ú)X˘ ‰ÍLŔR!Pwłą)ăŐ18p+r·Âš€á{ś"ť]:ž«đ˙ߡШ ˛UF@OůďEÂřłĘNőŃ& ¶˘Ąď ţľEŰ™Z`.ú<8@2@ţřgy ©±UA ®S> %Me~5­"ź’ÚŘUÓł%™ÖĽjOiš9`› @˛Żng¬z\uc±M˛ąç/7x~E©şÖiVaÜś?¶F{ˇ­Pkdű‰@ţ{ş†zŰ˙39Śĺ/mśú Ň ¸i/Ú¬×fp€¤"\…?XÁ‘÷Ńít8^ź\cs€áG$ŃŚ #ýzŔe5&çÓóC`qОEťTŞQHmĺ ¤'ža› @2«&Óo«âőäkÇŃĂřK’”4Ăt–Á\ý˝–çl†v@Z¶łŇđy5Ýäj;ô ›Éy-¨ËUá­}f ^H×EźÓ>tmd3H x‹g®S[Ń2€ŽtFŽDXŐ𼜋 [Hňq´]„I;©|XžběX'•h(ú}…4ŐX3Ll&:ďq°Z$G¦gî˛d¬z€±ę) vZ%u- ˝š i0WŻ'âŇťsC >tmÖ)h˘ ŠÔ 5CË M7¶š)ů4ęúŐ•—˙Â4†ë&?©ďQZP$c-–)Ř:ŤŻ{Éë7Hßq˝§ŮciĄăůÓfÉ/ů,‹‘#V§•T7`CĐetZŽäÇX±´›íI^’%cĚĆIç‡Ŕ4Š˘›?]deeĂ×Ҹsý‰nm&`&`1ŕúbY˛h‚V@«ˇ¨9Ňľ( ¦čşc ¤ ć˘Hł†ĄĆL?'ŐI7¶’6żÔŘô)úér(}ľŽł™€ @Đy¶™@c4˝S;_ăŕHc˘ů ĆÝIi).d´äFKol&Đőázr(ɦ Íôę‹t‘Şďo) Ám&`&`E$Ŕő…žÜK#l&`&` đ…s`j};'3HtsĄép—0°jś-A´!M‘}i3W› TC@ßߏë¤Ů_š –vż_Ęß3H¨ › € € € @8<$śşÍÝÄhÚäŐޤS5p×fT(9WmŚ7Ż©®é8ę\C& éŇ[ÖI~*Đ©ĺ8šú<y† l&`&`&`&`& ¸4FŕznҵnÔ–"ęŕA‚$ŹâBgttŠ®8ëěĐÚó6łc(˙×/SéUkÉ5ĂÄf&`&`&`&`…$ŕI!«}ž…ÖS囸10Ď#}@"¨ mĆy ’‹y}µL$cg’w+S@I¦6¦_Đ í*ŻYdę l&`&`&`&`&P˘š+*¤ÚDWnČőTŮęĺ3\jE äD^o@ľ ¬Ž2쎾űkÖIĹІŻÚżD?/©źŢ‹j˙’¤µZŮLŔLŔLŔLŔL ĄÍň‚q(/Žp›ĹźůŐ÷s®ŤAm Ťé§řB»îŞÝËmřŞ_ÇQŔ¤Ö _ős’ékşój30000 8@S5d0@˛ (žä†E7ܶ  ­mŠ» j-ź!·íjö hŽ–ă BÚđµśýK´ŚgU´ ÚŚţFűžŘLŔLŔLŔLŔL ^bD5¤î„fŽčIîĂ©{b*&ŔM滜´’óyíPq>ÁŞ#Đ„ÓvšíÔŻřż–ć G „”đZRŁl ´Ňě‘Ă‚ÍLŔLŔLŔL (Ą Ř śĘ3šA˘ŕH/¤éî~š›ńĆG»[–"h6Éć/ŠÝĎ/.ô5Çć·x.™ € € € @V xǬÖ\4~+8˘=:98 Đ´SˇÇ =Ąß }ź¶?Îßć"p»#sńź&`&`&`&`Áp€$ŞHÜí0ÝČ ËŹ‰çî c%@ť>‡´‰ëM±fäÄM |'Ó&Ű—¸Ź40000d 8@’,ďPrSpäkt57,žeJ­Äŕő{2ɶ@źĆĽ“4rĽĆAKÓ¬+‡–Ź1000HŤ€$©ˇO-cŐů8t7,úŮN[Î PĎ_˘5)ćQČűĚ伾*Ţ“řŇ„¶·-ú6 żěŠ € € € € ÔKŔ’z±äöMmĘ;ićČčÜ–Ň«—uŢŤ´ěćÁzđ›&P;HbÚšlo4˛ö$ť‚ € € € € $CŔ’d8‡‹‚#ÚkäZnZ††ŕ}Hžu?DΡaÉ{ŕsF@Kô:ˇ´+ŮĆ虜•ŃĹ1000(H RŃS’›ąyń^Ĺ©óKJ;čŤVć€3<Č@ýđv;´ mhtú˛ţCý® € € € € d‡€$Ů©«Z<ý'wá&¦w-‰řÜü M\A©–BÝóW:—("ÓHç.´>íE¶şýQúNĆLŔLŔLŔLŔ‚ ŕIŐ« ú}ÜĚôŚ5'žY´Ťńh °=Ňľ6‚“Đb´ŤĐ‘¨Ż±€ € € € @ž 8@’çÚe <Ĺ{ś›ň]L—. ´“hŇş$ŠôśF¦ĚŔۇŃ&´YK¤%y“2U ;k&`&`&`&`5p€¤xźŞŕČ‹Üŕ<¸źv/0´™sq©)ú00×ěN´†“Ühięü—čô~´Y850000ČH˛SW•xŞe5oˇ»+9ÉÇš@‰7Ę#ĐŻůű4µôľ_3O@ż0ł u+k†®DßfľT.€ € € € € D@Ŕ’ –„‚#}Pgn|4mŢfU  iŮިKŐ‰řÄ4 Ś"ó˙CËQ—˛=÷#JłFś· € € € @° ¶jŞrLżVóş› «JÁ'™Ŕ\ԖбĽ˝:4×Çţ3<=piWęL¶úž›öČLŔLŔLŔLŔÂ"ŕIXőQ‹7ós˛ö¸š›!/‰¨…¤Ď­—íęsÔ’O¬÷ż™ýňĐĄ¨)ő#Ű=ź–3Î×LŔLŔLŔLŔ˛JŔ’¬ÖÜś~«u“¤ý&Îů‘˙2h ĐĆ:’˘–Ý<mĘN­osěŢÔ…ltQÁů>ÔLŔLŔLŔLŔL`.Ě$ŞőSś ŽŚÍ ˙v9hk“Ń^¸ľ9ťÁ"dÍĺďpř´Üe[˘'łVűk&`&`&`&`!p€$äÚ™·oóqČčn–´ĽĆf‰ ÝőB˓酉f\ŚĚ>˘‡˘`Ľ: )FŃ]J0000Hž€$É3Ź:Ç›¸iu˘NĎ*!@üÇŻ€´ôĂV)śv jOنč?hZuÉů,00000J8@R ­°ŽŐ¦¬]¸yŇOúÚL u´ĹQhKŮMNݡl807ŹB Ânat9źi&`&`&`&`&4H’&^]~ ŽôFÚ”uFuIř,H—m÷t^¬‡†¦ëM$ą?G*ŰR&ŮĘčJ4>’”ť € € € € @â IyĹţŠ3>Eú9ßéźíL 0´ăŹŃ*¸ĄY˛‘8{>Z˙e»ˇ×˛Tűj&`&`&`&`&Đ0HfSë'óŐšçë§|ő¤ý:nĦFž“0`ЦŻÄ™%QČ+˛+ľĘš ˘1Á@´#&`&`&`&`&`‘p€$2”?K¨'ď(ŔQ­©nt#¦iű«MÄç™@ČhŰP|Ü}€ŻßâĂĺhEü’i ÍóřeLŔLŔLŔLŔLŔb&Ĺ,‡]Ěfň3fĚPpD?íąúˇÂR(82ý‹›łQžëĂM łřŢl…󷣵,Ä;äĄďÚŁ ćé¬LŔLŔLŔLŔLŔ#ŕIĚ ßvdq8RŔd^?sŞúІ¬ÝŃ]ܰMăŐf…#Ŕ÷F{ď…ÎA­#0–ôş˘«řŽ}qÚNÎLŔLŔLŔLŔL Ł I¨â¸á[ž¬´”@3JôÝĘô«4şaű˝Â Ű'ĽÚLŔf#Ŕ÷gYţÔ÷ç ´)j‰4Ój^¦e;}Ńcč)ľ_úžŮLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔLŔţć,ei„ňIEND®B`‚nsd-4.12.0/doc/manual/resources/favicon.ico0000644000175000017500000003535615002373054020166 0ustar mozziemozzie00 ¨%6  ¨Ţ% h†6(0` $˙˙˙˙˙˙=˙˙˙“˙˙˙Ő˙˙˙÷˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř˙˙˙Ř˙˙˙—˙˙˙A˙˙˙˙˙˙&˙˙˙™˙˙˙ë˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙í˙˙˙ź˙˙˙+˙˙˙G˙˙˙Ő˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ú˙˙˙M˙˙˙F˙˙˙ă˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ç˙˙˙N˙˙˙%˙˙˙Ň˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ů˙˙˙+˙˙˙˙˙˙•˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ž˙˙˙˙˙˙8˙˙˙ç˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ě˙˙˙B˙˙˙‹˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙—˙˙˙Ě˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙×˙˙˙đ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙őňň˙ŕÖÔ˙üűű˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţýö˙őńÍ˙öóŐ˙ţţú˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙°­˙e70˙ÓĆÄ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţý÷˙ćÜ„˙ÔĂ/˙ŐĹ6˙ăŘ{˙÷óŮ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙¸Ł ˙O˙’rm˙üűű˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙ëâ›˙ÓÁ)˙ŇŔ$˙ŇŔ%˙Ňż#˙×Ç?˙éŕ–˙úůę˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙¸Ł ˙O˙_1*˙ŰĐĎ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ńë·˙ŐÄ3˙ŇŔ$˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ$˙ŇŔ%˙ÚĚQ˙îč±˙ýüő˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙·Ł ˙N˙M˙›{˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙öňŃ˙ŘČB˙ŇŔ#˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ#˙ÓÁ+˙ßŇh˙óďĘ˙˙ţü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙¶˘ ˙L˙L˙a71˙ăŰÚ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙úřä˙ÝĎW˙Ňż#˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ%˙ŇŔ#˙ÖĹ4˙çŢŤ˙ýýö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙µ˘ź˙J˙K˙J˙ĄŤŠ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ýüň˙âÖq˙ŇŔ$˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ÔÂ&˙Ńż&˙¶ˇ ˙Źu ˙ŰÓż˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙´ˇź˙H˙I˙G˙f>9˙ęäă˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţű˙čŢŽ˙ÓÁ'˙ŇŔ%˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ÓÁ&˙ŇŔ&˙˝¨"˙Śr˙bC˙V6˙Ă·¨˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙´ˇž˙F˙G˙G˙H˙Ż›™˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙îç«˙ÔĂ.˙ŇŔ%˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ÓÁ&˙ÓÁ&˙Á­#˙”{˙jL˙\<˙]=˙^?˙Ĺą¨˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ł ž˙D˙E˙F˙C˙lGC˙đěě˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ôďĆ˙×Ć:˙ŇŔ$˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ÓÁ%˙ÓÁ&˙ű#˙ś˙rT˙bC˙bC˙cD˙cD˙cD˙ÇĽ¨˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˛ ž˙C˙D˙D˙C˙F˙ş©§˙˙˙˙˙˙˙˙˙˙˙˙˙řőÜ˙ÚĚM˙Ňż#˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ$˙ŇŔ$˙Ěş*˙ŁŚ˙z]˙hI˙gI˙hJ˙hJ˙iJ˙hJ˙iJ˙Éľ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙±źť˙A˙B˙B˙B˙?˙sRO˙őóó˙˙˙˙˙üúí˙ßÓe˙Ňż#˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ%˙Ňż#˙ÖĹ7˙ćÜ‚˙ŰѨ˙y\#˙lN˙nP˙pN˙wI˙qM˙nP˙nP˙oP˙ËŔ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙±źť˙?˙@˙@˙@˙?˙F˙Ĺ·¶˙˙˙ű˙ĺŰ€˙ŇŔ%˙ŇŔ%˙ŇŔ&˙ŇŔ%˙Ňż#˙ŐÄ2˙ăŘv˙öňĎ˙˙˙ý˙üüú˙Ą’f˙sR˙{M˙†B"˙…F ˙vT˙tV˙tU˙tV˙Í©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙°žť˙=˙>˙>˙>˙>˙; ˙{^[˙ćÜ—˙ÔÂ+˙ŇŔ%˙ŇŔ%˙Ňż#˙ÔĂ/˙áŐm˙ôďČ˙ţţú˙˙˙˙˙˙˙˙˙ýűű˙ħ’˙‡E!˙Ś=&˙ŠC#˙|W˙y\˙y[˙y[˙z\˙ĎÄ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Żžś˙; ˙<˙<˙<˙<˙:˙pO˙ÎĽ+˙ŇŔ$˙Ňż#˙ÔÂ,˙ßŇd˙ňíż˙ţýř˙˙˙˙˙˙˙˙˙ýűű˙ăĎĘ˙´~p˙“G2˙Ť<'˙ŚA$˙Y˙b˙a˙a˙a˙b˙ŃĆ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙®ťś˙9 ˙:˙:˙:˙8 ˙Y4˙˝¨"˙ŐĂ%˙ÔĂ+˙ŢĐ\˙đę·˙ýüő˙˙˙˙˙˙˙˙˙ţýü˙çÖŇ˙¸†y˙”I4˙‹:$˙Ś;%˙Ž@(˙‰Z˙„h˙„g˙„g˙„g˙„g˙…h˙ÓČ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙®ťś˙7 ˙8 ˙8 ˙7 ˙J#˙°™ ˙ÓÁ&˙łť#˙×Ë‘˙ţýó˙˙˙˙˙˙˙˙˙˙ţţ˙ëÝŮ˙˝Ź‚˙—M9˙Ś:$˙Ť<&˙Ť<&˙Ź?*˙Ŕ—†˙¤ŤG˙l˙Šm˙Šm˙Šm˙Šm˙Šn˙ŐĘ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙­ś›˙5 ˙6 ˙6 ˙@ ˙›˙·ˇ!˙wX˙A ˙’{|˙˙˙˙˙˙˙˙˙îâß˙—‹˙™Q=˙Ś:$˙Ś<%˙Ť='˙Ť='˙Ś;%˙¸†x˙űřř˙ŃĆź˙t˙Źs˙Źs˙Źs˙Źs˙t˙×Ě©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙¬ś›˙3 ˙5 ˙3 ˙M(˙wX˙E ˙3 ˙1 ˙N,*˙ÖĆĂ˙ɢ—˙śVC˙Ś;%˙Ś;%˙Ť='˙Ť='˙Ť='˙Ś:$˙Şn]˙óëč˙˙˙˙˙ôńć˙§<˙”x˙•y˙•y˙•y˙•y˙ŮĎ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙«›š˙2 ˙3 ˙3 ˙3 ˙1 ˙1 ˙2 ˙< ˙]#˙ŽG4˙Ž='˙Ś;%˙Ť='˙Ť='˙Ť='˙Ť='˙Ś;$˙žZG˙éÚÖ˙˙˙˙˙˙˙˙˙˙˙˙˙ĎÂŹ˙š~˙›˙›˙›˙›˙ŰŃŞ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Şšš˙0 ˙1 ˙1 ˙0 ˙0 ˙8 ˙W˙|3!˙Ť=&˙Ť<&˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ś;%˙–K7˙ÝÄľ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ńíÝ˙¬”2˙ź„˙ …˙ …˙ …˙ÝÓŞ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Şšš˙.˙/ ˙.˙4 ˙R˙x1 ˙Ś<&˙Ž='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť<&˙B,˙ά˘˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Íľ˙˘‡˙Ł˙Ł˙¤˙ŢÔ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙¨™™˙*˙1 ˙L˙t/˙‹<&˙Ž='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť<&˙Ť<&˙ż‘…˙üúů˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙îéŇ˙­”)˙Ą‰˙ĄŠ˙¦Š˙ßŐ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ľ«©˙L˙p,˙Š;&˙Ž='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ś:$˙°xi˙÷đď˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţţü˙ɸo˙¦Š˙§Ś˙¨Ś˙ßŐ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ôíë˙±|m˙@*˙Ś;$˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ś:$˙ŁbP˙îâß˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ęăĹ˙®”!˙©Ť˙ŞŽ˙ŕÖ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ůőô˙Óµ¬˙ˇ`N˙Ś<&˙Ś;%˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ť='˙Ś;%˙™Q=˙ăĎÉ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ýüř˙Ćł_˙ŞŽ˙¬Ź˙áÖ©˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ňęç˙Ĺś‘˙Q=˙Ś:$˙Ť<&˙Ť='˙Ť='˙Ť='˙Ś<&˙’E0˙Ő·Ż˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ćŢ·˙°•˙­‘˙âש˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţţ˙éÚÖ˙·„w˙’E0˙Ś:$˙Ť<&˙Ť<&˙Ž>(˙Ćť’˙ţüü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙űúó˙ÄŻP˙®‘˙âب˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙üúú˙ÝĆż˙Şn^˙Ź@+˙Ž>(˙¸‡y˙ůőô˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ăŮ©˙´™˙ĺŰŻ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙î˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙÷ňđ˙ŰÁş˙Ůľ·˙řňđ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙üúó˙éŕą˙ů÷ě˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙÷˙˙˙Ę˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ő˙˙˙‡˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙“˙˙˙5˙˙˙ĺ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ę˙˙˙>˙˙˙˙˙˙Ź˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙™˙˙˙˙˙˙!˙˙˙Í˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ô˙˙˙'˙˙˙?˙˙˙Ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ă˙˙˙G˙˙˙?˙˙˙Î˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ó˙˙˙F˙˙˙!˙˙˙Ź˙˙˙ć˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙č˙˙˙•˙˙˙$˙˙˙˙˙˙4˙˙˙‡˙˙˙Ë˙˙˙ď˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ý˙˙˙đ˙˙˙Í˙˙˙‹˙˙˙8˙˙˙ţřđŕŔ€€€€Ŕŕđřţ( @ ˙˙˙(˙˙˙Ť˙˙˙Ü˙˙˙ü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ü˙˙˙Ý˙˙˙˙˙˙*˙˙˙˙˙˙R˙˙˙Ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ř˙˙˙W˙˙˙˙˙˙Q˙˙˙ë˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙î˙˙˙W˙˙˙&˙˙˙Ó˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙×˙˙˙+˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ő˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ü˙˙˙÷˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙×ĘČ˙ßŐÔ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙ôďĆ˙ěäˇ˙ůöŕ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙zu˙Šhc˙űúú˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ôďĆ˙×Ç;˙Ňż#˙ŘÉF˙ëă˘˙üúď˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙zv˙Y*#˙ÖËÉ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙řőÜ˙ÚĚM˙Ňż#˙ŇŔ&˙ŇŔ$˙ŇÁ'˙ÝĎZ˙ńëĽ˙ţýů˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙—zw˙H˙•xt˙ţýý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙üúí˙ßÓe˙Ňż#˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ŇŔ%˙Ňż#˙ŐÄ.˙â×t˙řőă˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙•yv˙F˙\1,˙ŢÖŐ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţýř˙ĺŰ˙ŇŔ%˙ŇŔ%˙ŇŔ&˙ŇŔ&˙ŇŔ&˙ÓÁ&˙ÓÁ&˙®"˙’x˙ş«Š˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙“xu˙E˙F˙ž…‚˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙ëăž˙ÓÂ*˙ŇŔ%˙ŇŔ&˙ŇŔ&˙ÓÁ&˙ÔÂ&˙Ćł$˙ť…˙nQ˙X8 ˙¤’z˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙’wt˙B˙C˙_73˙ćŕß˙˙˙˙˙˙˙˙˙ńëş˙ŐÄ4˙ŇŔ$˙ŇŔ&˙ŇŔ%˙Ňż#˙ɶ#˙¦Ž˙y\˙dE˙cD˙bB˙Ş{˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙vs˙? ˙B˙B˙§“‘˙˙˙˙˙öóÓ˙ŮÉD˙ŇŔ#˙ŇŔ%˙Ňż#˙ŐÄ3˙áŐs˙žB˙lN˙mK˙rJ˙mN˙jK˙®ť{˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Žus˙< ˙?˙= ˙b?=˙çŕÎ˙ŢŃ[˙Ňż"˙Ňż#˙ÔĂ/˙áŐo˙ôđĘ˙˙˙ţ˙Ŷś˙|N˙…D ˙~N˙uW˙sT˙ł˘|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ťtr˙9 ˙=˙<˙H˙ą¤@˙ÔÂ$˙ÔÂ,˙ŕÓf˙óîÁ˙˙ţú˙ýűű˙áĚĆ˙­ud˙Ś>%˙‡M˙~_˙}`˙{]˙·§|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙‹sq˙6 ˙9 ˙<˙‰l˙λ$˙ÜÎ[˙ńëą˙ţţ÷˙ţüý˙ĺÓÎ˙¶‚t˙“G2˙Ś:%˙—[8˙h˙†i˙†i˙„f˙Ľ¬|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Šrp˙3 ˙7 ˙oN˙©‘˙sS˙ľ±§˙˙˙˙˙éŮŐ˙şŠ}˙•K6˙‹:$˙‹9#˙§hW˙ŕŃÁ˙ž†4˙Ťp˙Žr˙Śo˙Á±|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙po˙0˙7 ˙Y6˙A ˙0˙tOK˙ľ„˙O;˙Ś:$˙Ś<&˙Ś;%˙›TA˙ĺÓÎ˙˙˙˙˙Ć·€˙•y˙–{˙•x˙Ŷ|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙†oo˙.˙1 ˙/ ˙= ˙a%˙‚6#˙Ś;$˙Ś<%˙Ť='˙Ś<%˙“G2˙ŘĽµ˙˙˙˙˙˙˙˙˙íčÓ˙¨Ź*˙ž‚˙ť˙Ęş}˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙mm˙*˙9 ˙\"˙€5"˙Ž='˙Ž='˙Ť='˙Ť='˙Ť<&˙Ź?*˙ÉŁ˙ţýý˙˙˙˙˙˙˙˙˙ţţý˙Č·q˙ه˙˘‡˙Í˝|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙•{y˙R˙|3!˙Ť='˙Ž='˙Ť='˙Ť='˙Ť='˙Ť=&˙Ś<%˙ş{˙ű÷ö˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ęăÇ˙¬’"˙Ą‰˙Îż|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙çŮÖ˙«p`˙Ź@*˙Ś;$˙Ť='˙Ť='˙Ť='˙Ť='˙Ś:$˙«p`˙ôěę˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ýüů˙Ćła˙§Š ˙ĐŔ|˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙řóň˙Ѱ§˙ ]J˙Ś;%˙Ś;%˙Ť='˙Ś;$˙ź\I˙ëÜŘ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙çŢą˙Ż“˙ŃÁ{˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ńçä˙ÂŚ˙—N:˙‹9"˙–M8˙ŢÇÁ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙űúô˙Ä®M˙ŇÁw˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙÷˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţţý˙çÖŃ˙Ă™Ť˙ÜĂĽ˙˙ţţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ěäÂ˙ęâľ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ű˙˙˙Ô˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ű˙˙˙…˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ť˙˙˙$˙˙˙Đ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ô˙˙˙(˙˙˙M˙˙˙č˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ë˙˙˙R˙˙˙˙˙˙M˙˙˙Ń˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙Ô˙˙˙Q˙˙˙˙˙˙#˙˙˙…˙˙˙Ő˙˙˙÷˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř˙˙˙Ö˙˙˙˙˙˙&đŕŔ€€Ŕŕđ(  ˙˙˙˙˙˙d˙˙˙Ü˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ý˙˙˙g˙˙˙˙˙˙d˙˙˙ď˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙đ˙˙˙g˙˙˙Ů˙˙˙˙˙˙˙˙˙ţţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Ü˙˙˙ý˙˙˙˙úřř˙òŻ˙÷őô˙˙˙˙˙˙˙˙˙˙˙˙˙úřć˙ĺÚ˙îç«˙ýüô˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙˙˙˙˙˙řöö˙a\˙ĎÂŔ˙˙˙˙˙˙˙˙˙ýüô˙ă×t˙Ńż"˙ÔÂ*˙ŕÓd˙ňíĚ˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ů÷÷˙tPL˙Šlh˙ýüü˙˙˙ü˙éß‘˙ŇŔ&˙ŇŔ#˙˸$˙˘‹˙ ŚZ˙űúú˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ů÷÷˙qOL˙P&"˙ŮĎĎ˙ńę°˙ÔÂ,˙ÖĹ2˙Ç·F˙†h˙iG˙ŹxP˙űúř˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř÷÷˙nNK˙9 ˙T˙ÜÍH˙áŐi˙ńęľ˙É­š˙K!˙zU˙ś‡Q˙űúř˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř÷÷˙iJI˙G ˙Źt˙ŮÍ™˙âÎÂ˙ł}p˙źZI˙¦‚O˙k˙©”Q˙üűř˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ř÷ö˙dGF˙;˙S$˙‘WK˙–J6˙A,˙Ôµ­˙çáČ˙ź… ˙µ Q˙üüř˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ůřř˙vSO˙a!˙…8$˙Ś;$˙Ť='˙ÄšŽ˙ýüü˙ýýú˙ÂŻ_˙Ľ§N˙ýüř˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ÝČĂ˙©l[˙Ž>(˙‹9#˙µ€r˙ůôó˙˙˙˙˙˙˙˙˙ĺÝ·˙ıY˙ýü÷˙˙˙˙˙˙˙˙˙˙˙˙ü˙˙˙˙˙˙˙˙˙˙˙˙÷ńđ˙Í«ˇ˙¸†x˙ńçä˙˙˙˙˙˙˙˙˙˙˙˙˙űůń˙âצ˙ýüř˙˙˙˙˙˙˙˙ţ˙˙˙×˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţüü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙Ű˙˙˙a˙˙˙í˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ď˙˙˙e˙˙˙˙˙˙a˙˙˙Ů˙˙˙ý˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ţ˙˙˙Ú˙˙˙c˙˙˙Ŕ€€Ŕnsd-4.12.0/doc/manual/resources/css/0000755000175000017500000000000015002373054016621 5ustar mozziemozziensd-4.12.0/doc/manual/resources/css/light.css0000644000175000017500000000034015002373054020437 0ustar mozziemozzie@media (prefers-color-scheme: light) { .wy-menu-vertical li.toctree-l2.current a, .wy-menu-vertical li.toctree-l3.current a { background-color: #c9c9c9; } pre.man { font-size: 0.9em; } } nsd-4.12.0/doc/manual/resources/css/dark.css0000644000175000017500000037054315002373054020270 0ustar mozziemozzie@media (prefers-color-scheme: dark) { /* _______ / \ .==. .==. (( ))==(( )) / "==" "=="\ /____|| || ||___\ ________ ____ ________ ___ ___ | ___ \ / \ | ___ \ | | / / | | \ \ / /\ \ | | \ \| |_/ / | | ) / /__\ \ | |__/ /| ___ \ | |__/ / ______ \| ____ \| | \ \ _______|_______/__/ ____ \__\__|___\__\__|___\__\____ | ___ \ | ____/ / \ | ___ \ | ____| ___ \ | | \ \| |___ / /\ \ | | \ \| |___| | \ \ | |__/ /| ____/ /__\ \ | | ) | ____| |__/ / | ____ \| |__/ ______ \| |__/ /| |___| ____ \ |__| \__\____/__/ \__\_______/ |______|__| \__\ https://darkreader.org */ /*! Dark reader generated CSS | Licensed under MIT https://github.com/darkreader/darkreader/blob/master/LICENSE */ /* User-Agent Style */ html { background-color: #181a1b !important; } html, body, input, textarea, select, button { background-color: #181a1b; } html, body, input, textarea, select, button { border-color: #736b5e; color: #e8e6e3; } a { color: #3391ff; } table { border-color: #545b5e; } ::placeholder { color: #b2aba1; } input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill { background-color: #555b00 !important; color: #e8e6e3 !important; } ::selection { background-color: #004daa !important; color: #e8e6e3 !important; } ::-moz-selection { background-color: #004daa !important; color: #e8e6e3 !important; } pre.man { font-size: 0.9em; } /* Invert Style */ .jfk-bubble.gtx-bubble, .captcheck_answer_label > input + img, span#closed_text > img[src^="https://www.gstatic.com/images/branding/googlelogo"], span[data-href^="https://www.hcaptcha.com/"] > #icon, #bit-notification-bar-iframe, ::-webkit-calendar-picker-indicator { filter: invert(100%) hue-rotate(180deg) contrast(90%) !important; } /* Variables Style */ :root { --darkreader-neutral-background: #131516; --darkreader-neutral-text: #d8d4cf; --darkreader-selection-background: #004daa; --darkreader-selection-text: #e8e6e3; } /* Modified CSS */ a:active, a:hover { outline-color: initial; } abbr[title] { border-bottom-color: initial; } ins { background-image: initial; background-color: rgb(112, 112, 0); text-decoration-color: initial; } ins, mark { color: rgb(232, 230, 227); } mark { background-image: initial; background-color: rgb(204, 204, 0); } dl, ol, ul { list-style-image: none; } li { list-style-image: initial; } img { border-color: initial; } .chromeframe { background-image: initial; background-color: rgb(53, 57, 59); color: rgb(232, 230, 227); } .ir { border-color: initial; background-color: transparent; } .visuallyhidden { border-color: initial; } .fa-border { border-color: rgb(53, 57, 59); } .fa-inverse { color: rgb(232, 230, 227); } .sr-only { border-color: initial; } .fa::before, .icon::before, .rst-content .admonition-title::before, .rst-content .code-block-caption .headerlink::before, .rst-content .eqno .headerlink::before, .rst-content code.download span:first-child::before, .rst-content dl dt .headerlink::before, .rst-content h1 .headerlink::before, .rst-content h2 .headerlink::before, .rst-content h3 .headerlink::before, .rst-content h4 .headerlink::before, .rst-content h5 .headerlink::before, .rst-content h6 .headerlink::before, .rst-content p.caption .headerlink::before, .rst-content p .headerlink::before, .rst-content table > caption .headerlink::before, .rst-content tt.download span:first-child::before, .wy-dropdown .caret::before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context::before, .wy-inline-validate.wy-inline-validate-info .wy-input-context::before, .wy-inline-validate.wy-inline-validate-success .wy-input-context::before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context::before, .wy-menu-vertical li.current > a button.toctree-expand::before, .wy-menu-vertical li.on a button.toctree-expand::before, .wy-menu-vertical li button.toctree-expand::before { text-decoration-color: inherit; } .rst-content .code-block-caption a .headerlink, .rst-content .eqno a .headerlink, .rst-content a .admonition-title, .rst-content code.download a span:first-child, .rst-content dl dt a .headerlink, .rst-content h1 a .headerlink, .rst-content h2 a .headerlink, .rst-content h3 a .headerlink, .rst-content h4 a .headerlink, .rst-content h5 a .headerlink, .rst-content h6 a .headerlink, .rst-content p.caption a .headerlink, .rst-content p a .headerlink, .rst-content table > caption a .headerlink, .rst-content tt.download a span:first-child, .wy-menu-vertical li.current > a button.toctree-expand, .wy-menu-vertical li.on a button.toctree-expand, .wy-menu-vertical li a button.toctree-expand, a .fa, a .icon, a .rst-content .admonition-title, a .rst-content .code-block-caption .headerlink, a .rst-content .eqno .headerlink, a .rst-content code.download span:first-child, a .rst-content dl dt .headerlink, a .rst-content h1 .headerlink, a .rst-content h2 .headerlink, a .rst-content h3 .headerlink, a .rst-content h4 .headerlink, a .rst-content h5 .headerlink, a .rst-content h6 .headerlink, a .rst-content p.caption .headerlink, a .rst-content p .headerlink, a .rst-content table > caption .headerlink, a .rst-content tt.download span:first-child, a .wy-menu-vertical li button.toctree-expand { text-decoration-color: inherit; } .rst-content .admonition, .rst-content .admonition-todo, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .note, .rst-content .seealso, .rst-content .tip, .rst-content .warning, .wy-alert { background-image: initial; background-color: rgb(32, 35, 36); } .rst-content .admonition-title, .wy-alert-title { color: rgb(232, 230, 227); background-image: initial; background-color: rgb(29, 91, 131); } .rst-content .danger, .rst-content .error, .rst-content .wy-alert-danger.admonition, .rst-content .wy-alert-danger.admonition-todo, .rst-content .wy-alert-danger.attention, .rst-content .wy-alert-danger.caution, .rst-content .wy-alert-danger.hint, .rst-content .wy-alert-danger.important, .rst-content .wy-alert-danger.note, .rst-content .wy-alert-danger.seealso, .rst-content .wy-alert-danger.tip, .rst-content .wy-alert-danger.warning, .wy-alert.wy-alert-danger { background-image: initial; background-color: rgb(52, 12, 8); } .rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { background-image: initial; background-color: rgb(108, 22, 13); } .rst-content .admonition-todo, .rst-content .attention, .rst-content .caution, .rst-content .warning, .rst-content .wy-alert-warning.admonition, .rst-content .wy-alert-warning.danger, .rst-content .wy-alert-warning.error, .rst-content .wy-alert-warning.hint, .rst-content .wy-alert-warning.important, .rst-content .wy-alert-warning.note, .rst-content .wy-alert-warning.seealso, .rst-content .wy-alert-warning.tip, .wy-alert.wy-alert-warning { background-image: initial; background-color: rgb(82, 53, 0); } .rst-content .admonition-todo .admonition-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .attention .admonition-title, .rst-content .attention .wy-alert-title, .rst-content .caution .admonition-title, .rst-content .caution .wy-alert-title, .rst-content .warning .admonition-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.admonition .admonition-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .wy-alert.wy-alert-warning .wy-alert-title { background-image: initial; background-color: rgb(123, 65, 14); } .rst-content .note, .rst-content .seealso, .rst-content .wy-alert-info.admonition, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .wy-alert.wy-alert-info { background-image: initial; background-color: rgb(32, 35, 36); } .rst-content .note .admonition-title, .rst-content .note .wy-alert-title, .rst-content .seealso .admonition-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .admonition-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .wy-alert.wy-alert-info .wy-alert-title { background-image: initial; background-color: rgb(29, 91, 131); } .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .wy-alert-success.admonition, .rst-content .wy-alert-success.admonition-todo, .rst-content .wy-alert-success.attention, .rst-content .wy-alert-success.caution, .rst-content .wy-alert-success.danger, .rst-content .wy-alert-success.error, .rst-content .wy-alert-success.note, .rst-content .wy-alert-success.seealso, .rst-content .wy-alert-success.warning, .wy-alert.wy-alert-success { background-image: initial; background-color: rgb(9, 66, 58); } .rst-content .hint .admonition-title, .rst-content .hint .wy-alert-title, .rst-content .important .admonition-title, .rst-content .important .wy-alert-title, .rst-content .tip .admonition-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .admonition-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .wy-alert.wy-alert-success .wy-alert-title { background-image: initial; background-color: rgb(21, 150, 125); } .rst-content .wy-alert-neutral.admonition, .rst-content .wy-alert-neutral.admonition-todo, .rst-content .wy-alert-neutral.attention, .rst-content .wy-alert-neutral.caution, .rst-content .wy-alert-neutral.danger, .rst-content .wy-alert-neutral.error, .rst-content .wy-alert-neutral.hint, .rst-content .wy-alert-neutral.important, .rst-content .wy-alert-neutral.note, .rst-content .wy-alert-neutral.seealso, .rst-content .wy-alert-neutral.tip, .rst-content .wy-alert-neutral.warning, .wy-alert.wy-alert-neutral { background-image: initial; background-color: rgb(27, 36, 36); } .rst-content .wy-alert-neutral.admonition-todo .admonition-title, .rst-content .wy-alert-neutral.admonition-todo .wy-alert-title, .rst-content .wy-alert-neutral.admonition .admonition-title, .rst-content .wy-alert-neutral.admonition .wy-alert-title, .rst-content .wy-alert-neutral.attention .admonition-title, .rst-content .wy-alert-neutral.attention .wy-alert-title, .rst-content .wy-alert-neutral.caution .admonition-title, .rst-content .wy-alert-neutral.caution .wy-alert-title, .rst-content .wy-alert-neutral.danger .admonition-title, .rst-content .wy-alert-neutral.danger .wy-alert-title, .rst-content .wy-alert-neutral.error .admonition-title, .rst-content .wy-alert-neutral.error .wy-alert-title, .rst-content .wy-alert-neutral.hint .admonition-title, .rst-content .wy-alert-neutral.hint .wy-alert-title, .rst-content .wy-alert-neutral.important .admonition-title, .rst-content .wy-alert-neutral.important .wy-alert-title, .rst-content .wy-alert-neutral.note .admonition-title, .rst-content .wy-alert-neutral.note .wy-alert-title, .rst-content .wy-alert-neutral.seealso .admonition-title, .rst-content .wy-alert-neutral.seealso .wy-alert-title, .rst-content .wy-alert-neutral.tip .admonition-title, .rst-content .wy-alert-neutral.tip .wy-alert-title, .rst-content .wy-alert-neutral.warning .admonition-title, .rst-content .wy-alert-neutral.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-neutral .admonition-title, .wy-alert.wy-alert-neutral .rst-content .admonition-title, .wy-alert.wy-alert-neutral .wy-alert-title { color: rgb(192, 186, 178); background-image: initial; background-color: rgb(40, 43, 45); } .rst-content .wy-alert-neutral.admonition-todo a, .rst-content .wy-alert-neutral.admonition a, .rst-content .wy-alert-neutral.attention a, .rst-content .wy-alert-neutral.caution a, .rst-content .wy-alert-neutral.danger a, .rst-content .wy-alert-neutral.error a, .rst-content .wy-alert-neutral.hint a, .rst-content .wy-alert-neutral.important a, .rst-content .wy-alert-neutral.note a, .rst-content .wy-alert-neutral.seealso a, .rst-content .wy-alert-neutral.tip a, .rst-content .wy-alert-neutral.warning a, .wy-alert.wy-alert-neutral a { color: rgb(84, 164, 217); } .wy-tray-container li { background-image: initial; background-color: transparent; color: rgb(232, 230, 227); box-shadow: rgba(0, 0, 0, 0.1) 0px 5px 5px 0px; } .wy-tray-container li.wy-tray-item-success { background-image: initial; background-color: rgb(31, 139, 77); } .wy-tray-container li.wy-tray-item-info { background-image: initial; background-color: rgb(33, 102, 148); } .wy-tray-container li.wy-tray-item-warning { background-image: initial; background-color: rgb(178, 94, 20); } .wy-tray-container li.wy-tray-item-danger { background-image: initial; background-color: rgb(162, 33, 20); } .btn { color: rgb(232, 230, 227); border-color: rgba(140, 130, 115, 0.1); background-color: rgb(31, 139, 77); text-decoration-color: initial; box-shadow: rgba(24, 26, 27, 0.5) 0px 1px 2px -1px inset, rgba(0, 0, 0, 0.1) 0px -2px 0px 0px inset; } .btn-hover { background-image: initial; background-color: rgb(37, 114, 165); color: rgb(232, 230, 227); } .btn:hover { background-image: initial; background-color: rgb(35, 156, 86); color: rgb(232, 230, 227); } .btn:focus { background-image: initial; background-color: rgb(35, 156, 86); outline-color: initial; } .btn:active { box-shadow: rgba(0, 0, 0, 0.05) 0px -1px 0px 0px inset, rgba(0, 0, 0, 0.1) 0px 2px 0px 0px inset; } .btn:visited { color: rgb(232, 230, 227); } .btn-disabled, .btn-disabled:active, .btn-disabled:focus, .btn-disabled:hover, .btn:disabled { background-image: none; box-shadow: none; } .btn-info { background-color: rgb(33, 102, 148) !important; } .btn-info:hover { background-color: rgb(37, 114, 165) !important; } .btn-neutral { background-color: rgb(27, 36, 36) !important; color: rgb(192, 186, 178) !important; } .btn-neutral:hover { color: rgb(192, 186, 178); background-color: rgb(34, 44, 44) !important; } .btn-neutral:visited { color: rgb(192, 186, 178) !important; } .btn-success { background-color: rgb(31, 139, 77) !important; } .btn-success:hover { background-color: rgb(27, 122, 68) !important; } .btn-danger { background-color: rgb(162, 33, 20) !important; } .btn-danger:hover { background-color: rgb(149, 30, 18) !important; } .btn-warning { background-color: rgb(178, 94, 20) !important; } .btn-warning:hover { background-color: rgb(165, 87, 18) !important; } .btn-invert { background-color: rgb(26, 28, 29); } .btn-invert:hover { background-color: rgb(35, 38, 40) !important; } .btn-link { color: rgb(84, 164, 217); box-shadow: none; background-color: transparent !important; border-color: transparent !important; } .btn-link:active, .btn-link:hover { box-shadow: none; background-color: transparent !important; color: rgb(79, 162, 216) !important; } .btn-link:visited { color: rgb(164, 103, 188); } .wy-dropdown-menu { background-image: initial; background-color: rgb(26, 28, 29); border-color: rgb(60, 65, 67); box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 2px 0px; } .wy-dropdown-menu > dd > a { color: rgb(192, 186, 178); } .wy-dropdown-menu > dd > a:hover { background-image: initial; background-color: rgb(33, 102, 148); color: rgb(232, 230, 227); } .wy-dropdown-menu > dd.divider { border-top-color: rgb(60, 65, 67); } .wy-dropdown-menu > dd.call-to-action { background-image: initial; background-color: rgb(40, 43, 45); } .wy-dropdown-menu > dd.call-to-action:hover { background-image: initial; background-color: rgb(40, 43, 45); } .wy-dropdown-menu > dd.call-to-action .btn { color: rgb(232, 230, 227); } .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu { background-image: initial; background-color: rgb(26, 28, 29); } .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { background-image: initial; background-color: rgb(33, 102, 148); color: rgb(232, 230, 227); } .wy-dropdown-arrow::before { border-bottom-color: rgb(51, 55, 57); border-left-color: transparent; border-right-color: transparent; } fieldset, legend { border-color: initial; } label { color: rgb(200, 195, 188); } .wy-control-group.wy-control-group-required > label::after { color: rgb(233, 88, 73); } .wy-form-message-inline { color: rgb(168, 160, 149); } .wy-form-message { color: rgb(168, 160, 149); } input[type="color"], input[type="date"], input[type="datetime-local"], input[type="datetime"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] { border-color: rgb(62, 68, 70); box-shadow: rgb(43, 47, 49) 0px 1px 3px inset; } input[type="color"]:focus, input[type="date"]:focus, input[type="datetime-local"]:focus, input[type="datetime"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus { outline-color: initial; border-color: rgb(123, 114, 101); } input.no-focus:focus { border-color: rgb(62, 68, 70) !important; } input[type="checkbox"]:focus, input[type="file"]:focus, input[type="radio"]:focus { outline-color: rgb(13, 113, 167); } input[type="color"][disabled], input[type="date"][disabled], input[type="datetime-local"][disabled], input[type="datetime"][disabled], input[type="email"][disabled], input[type="month"][disabled], input[type="number"][disabled], input[type="password"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="text"][disabled], input[type="time"][disabled], input[type="url"][disabled], input[type="week"][disabled] { background-color: rgb(27, 29, 30); } input:focus:invalid, select:focus:invalid, textarea:focus:invalid { color: rgb(233, 88, 73); border-color: rgb(149, 31, 18); } input:focus:invalid:focus, select:focus:invalid:focus, textarea:focus:invalid:focus { border-color: rgb(149, 31, 18); } input[type="checkbox"]:focus:invalid:focus, input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus { outline-color: rgb(149, 31, 18); } select, textarea { border-color: rgb(62, 68, 70); box-shadow: rgb(43, 47, 49) 0px 1px 3px inset; } select { border-color: rgb(62, 68, 70); background-color: rgb(24, 26, 27); } select:focus, textarea:focus { outline-color: initial; } input[readonly], select[disabled], select[readonly], textarea[disabled], textarea[readonly] { background-color: rgb(27, 29, 30); } .wy-checkbox, .wy-radio { color: rgb(192, 186, 178); } .wy-input-prefix .wy-input-context, .wy-input-suffix .wy-input-context { background-color: rgb(27, 36, 36); border-color: rgb(62, 68, 70); color: rgb(168, 160, 149); } .wy-input-suffix .wy-input-context { border-left-color: initial; } .wy-input-prefix .wy-input-context { border-right-color: initial; } .wy-switch::before { background-image: initial; background-color: rgb(53, 57, 59); } .wy-switch::after { background-image: initial; background-color: rgb(82, 88, 92); } .wy-switch span { color: rgb(200, 195, 188); } .wy-switch.active::before { background-image: initial; background-color: rgb(24, 106, 58); } .wy-switch.active::after { background-image: initial; background-color: rgb(31, 139, 77); } .wy-control-group.wy-control-group-error .wy-form-message, .wy-control-group.wy-control-group-error > label { color: rgb(233, 88, 73); } .wy-control-group.wy-control-group-error input[type="color"], .wy-control-group.wy-control-group-error input[type="date"], .wy-control-group.wy-control-group-error input[type="datetime-local"], .wy-control-group.wy-control-group-error input[type="datetime"], .wy-control-group.wy-control-group-error input[type="email"], .wy-control-group.wy-control-group-error input[type="month"], .wy-control-group.wy-control-group-error input[type="number"], .wy-control-group.wy-control-group-error input[type="password"], .wy-control-group.wy-control-group-error input[type="search"], .wy-control-group.wy-control-group-error input[type="tel"], .wy-control-group.wy-control-group-error input[type="text"], .wy-control-group.wy-control-group-error input[type="time"], .wy-control-group.wy-control-group-error input[type="url"], .wy-control-group.wy-control-group-error input[type="week"], .wy-control-group.wy-control-group-error textarea { border-color: rgb(149, 31, 18); } .wy-inline-validate.wy-inline-validate-success .wy-input-context { color: rgb(92, 218, 145); } .wy-inline-validate.wy-inline-validate-danger .wy-input-context { color: rgb(233, 88, 73); } .wy-inline-validate.wy-inline-validate-warning .wy-input-context { color: rgb(232, 138, 54); } .wy-inline-validate.wy-inline-validate-info .wy-input-context { color: rgb(84, 164, 217); } .rst-content table.docutils caption, .rst-content table.field-list caption, .wy-table caption { color: rgb(232, 230, 227); } .rst-content table.docutils thead, .rst-content table.field-list thead, .wy-table thead { color: rgb(232, 230, 227); } .rst-content table.docutils thead th, .rst-content table.field-list thead th, .wy-table thead th { border-bottom-color: rgb(56, 61, 63); } .rst-content table.docutils td, .rst-content table.field-list td, .wy-table td { background-color: transparent; } .wy-table-secondary { color: rgb(152, 143, 129); } .wy-table-tertiary { color: rgb(152, 143, 129); } .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td, .wy-table-backed, .wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td { background-color: rgb(27, 36, 36); } .rst-content table.docutils, .wy-table-bordered-all { border-color: rgb(56, 61, 63); } .rst-content table.docutils td, .wy-table-bordered-all td { border-bottom-color: rgb(56, 61, 63); border-left-color: rgb(56, 61, 63); } .wy-table-bordered { border-color: rgb(56, 61, 63); } .wy-table-bordered-rows td { border-bottom-color: rgb(56, 61, 63); } .wy-table-horizontal td, .wy-table-horizontal th { border-bottom-color: rgb(56, 61, 63); } a { color: rgb(84, 164, 217); text-decoration-color: initial; } a:hover { color: rgb(68, 156, 214); } a:visited { color: rgb(164, 103, 188); } body { color: rgb(192, 186, 178); background-image: initial; background-color: rgb(33, 35, 37); } .wy-text-strike { text-decoration-color: initial; } .wy-text-warning { color: rgb(232, 138, 54) !important; } a.wy-text-warning:hover { color: rgb(236, 157, 87) !important; } .wy-text-info { color: rgb(84, 164, 217) !important; } a.wy-text-info:hover { color: rgb(79, 162, 216) !important; } .wy-text-success { color: rgb(92, 218, 145) !important; } a.wy-text-success:hover { color: rgb(73, 214, 133) !important; } .wy-text-danger { color: rgb(233, 88, 73) !important; } a.wy-text-danger:hover { color: rgb(237, 118, 104) !important; } .wy-text-neutral { color: rgb(192, 186, 178) !important; } a.wy-text-neutral:hover { color: rgb(176, 169, 159) !important; } hr { border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-top-color: rgb(56, 61, 63); } .rst-content code, .rst-content tt, code { background-image: initial; background-color: rgb(24, 26, 27); border-color: rgb(56, 61, 63); color: rgb(233, 88, 73); } .rst-content .section ul, .rst-content .toctree-wrapper ul, .rst-content section ul, .wy-plain-list-disc, article ul { list-style-image: initial; } .rst-content .section ul li, .rst-content .toctree-wrapper ul li, .rst-content section ul li, .wy-plain-list-disc li, article ul li { list-style-image: initial; } .rst-content .section ul li li, .rst-content .toctree-wrapper ul li li, .rst-content section ul li li, .wy-plain-list-disc li li, article ul li li { list-style-image: initial; } .rst-content .section ul li li li, .rst-content .toctree-wrapper ul li li li, .rst-content section ul li li li, .wy-plain-list-disc li li li, article ul li li li { list-style-image: initial; } .rst-content .section ul li ol li, .rst-content .toctree-wrapper ul li ol li, .rst-content section ul li ol li, .wy-plain-list-disc li ol li, article ul li ol li { list-style-image: initial; } .rst-content .section ol, .rst-content .section ol.arabic, .rst-content .toctree-wrapper ol, .rst-content .toctree-wrapper ol.arabic, .rst-content section ol, .rst-content section ol.arabic, .wy-plain-list-decimal, article ol { list-style-image: initial; } .rst-content .section ol.arabic li, .rst-content .section ol li, .rst-content .toctree-wrapper ol.arabic li, .rst-content .toctree-wrapper ol li, .rst-content section ol.arabic li, .rst-content section ol li, .wy-plain-list-decimal li, article ol li { list-style-image: initial; } .rst-content .section ol.arabic li ul li, .rst-content .section ol li ul li, .rst-content .toctree-wrapper ol.arabic li ul li, .rst-content .toctree-wrapper ol li ul li, .rst-content section ol.arabic li ul li, .rst-content section ol li ul li, .wy-plain-list-decimal li ul li, article ol li ul li { list-style-image: initial; } .rst-content .wy-breadcrumbs li tt, .wy-breadcrumbs li .rst-content tt, .wy-breadcrumbs li code { border-color: initial; background-image: none; background-color: initial; } .rst-content .wy-breadcrumbs li tt.literal, .wy-breadcrumbs li .rst-content tt.literal, .wy-breadcrumbs li code.literal { color: rgb(192, 186, 178); } .wy-breadcrumbs-extra { color: rgb(184, 178, 169); } .wy-menu a:hover { text-decoration-color: initial; } .wy-menu-horiz li:hover { background-image: initial; background-color: rgba(24, 26, 27, 0.1); } .wy-menu-horiz li.divide-left { border-left-color: rgb(119, 110, 98); } .wy-menu-horiz li.divide-right { border-right-color: rgb(119, 110, 98); } .wy-menu-vertical header, .wy-menu-vertical p.caption { color: rgb(94, 170, 219); } .wy-menu-vertical li.divide-top { border-top-color: rgb(119, 110, 98); } .wy-menu-vertical li.divide-bottom { border-bottom-color: rgb(119, 110, 98); } .wy-menu-vertical li.current { background-image: initial; background-color: rgb(40, 43, 45); } .wy-menu-vertical li.current a { color: rgb(152, 143, 129); border-right-color: rgb(63, 69, 71); } .wy-menu-vertical li.current a:hover { background-image: initial; background-color: rgb(47, 51, 53); } .rst-content .wy-menu-vertical li tt, .wy-menu-vertical li .rst-content tt, .wy-menu-vertical li code { border-color: initial; background-image: inherit; background-color: inherit; color: inherit; } .wy-menu-vertical li button.toctree-expand { color: rgb(183, 177, 168); border-color: initial; background-image: none; background-color: initial; } .wy-menu-vertical li.current > a, .wy-menu-vertical li.on a { color: rgb(192, 186, 178); background-image: initial; background-color: rgb(26, 28, 29); border-color: initial; } .wy-menu-vertical li.current > a:hover, .wy-menu-vertical li.on a:hover { background-image: initial; background-color: rgb(26, 28, 29); } .wy-menu-vertical li.current > a:hover button.toctree-expand, .wy-menu-vertical li.on a:hover button.toctree-expand { color: rgb(152, 143, 129); } .wy-menu-vertical li.current > a button.toctree-expand, .wy-menu-vertical li.on a button.toctree-expand { color: rgb(200, 195, 188); } .wy-menu-vertical li.toctree-l1.current > a { border-bottom-color: rgb(63, 69, 71); border-top-color: rgb(63, 69, 71); } .wy-menu-vertical li.toctree-l2 a, .wy-menu-vertical li.toctree-l3 a, .wy-menu-vertical li.toctree-l4 a, .wy-menu-vertical li.toctree-l5 a, .wy-menu-vertical li.toctree-l6 a, .wy-menu-vertical li.toctree-l7 a, .wy-menu-vertical li.toctree-l8 a, .wy-menu-vertical li.toctree-l9 a, .wy-menu-vertical li.toctree-l10 a { color: rgb(192, 186, 178); } .wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand, .wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand { color: rgb(152, 143, 129); } .wy-menu-vertical li.toctree-l2.current > a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { background-image: initial; background-color: rgb(54, 59, 61); } .wy-menu-vertical li.toctree-l2 button.toctree-expand { color: rgb(174, 167, 156); } .wy-menu-vertical li.toctree-l3.current > a, .wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a { background-image: initial; background-color: rgb(61, 66, 69); } .wy-menu-vertical li.toctree-l3 button.toctree-expand { color: rgb(166, 158, 146); } .wy-menu-vertical li ul li a { color: rgb(208, 204, 198); } .wy-menu-vertical a { color: rgb(208, 204, 198); } .wy-menu-vertical a:hover { background-color: rgb(57, 62, 64); } .wy-menu-vertical a:hover button.toctree-expand { color: rgb(208, 204, 198); } .wy-menu-vertical a:active { background-color: rgb(33, 102, 148); color: rgb(232, 230, 227); } .wy-menu-vertical a:active button.toctree-expand { color: rgb(232, 230, 227); } .wy-side-nav-search { background-color: rgb(33, 102, 148); color: rgb(230, 228, 225); } .wy-side-nav-search input[type="text"] { border-color: rgb(35, 111, 160); } .wy-side-nav-search img { background-color: rgb(33, 102, 148); } .wy-side-nav-search .wy-dropdown > a, .wy-side-nav-search > a { color: rgb(230, 228, 225); } .wy-side-nav-search .wy-dropdown > a:hover, .wy-side-nav-search > a:hover { background-image: initial; background-color: rgba(24, 26, 27, 0.1); } .wy-side-nav-search .wy-dropdown > a img.logo, .wy-side-nav-search > a img.logo { background-image: initial; background-color: transparent; } .wy-side-nav-search > div.version { color: rgba(232, 230, 227, 0.3); } .wy-nav .wy-menu-vertical header { color: rgb(84, 164, 217); } .wy-nav .wy-menu-vertical a { color: rgb(184, 178, 169); } .wy-nav .wy-menu-vertical a:hover { background-color: rgb(33, 102, 148); color: rgb(232, 230, 227); } .wy-body-for-nav { background-image: initial; background-color: rgb(26, 28, 29); } .wy-nav-side { color: rgb(169, 161, 150); background-image: initial; background-color: rgb(38, 41, 43); } .wy-nav-top { background-image: initial; background-color: rgb(33, 102, 148); color: rgb(232, 230, 227); } .wy-nav-top a { color: rgb(232, 230, 227); } .wy-nav-top img { background-color: rgb(33, 102, 148); } .wy-nav-content-wrap { background-image: initial; background-color: rgb(26, 28, 29); } .wy-body-mask { background-image: initial; background-color: rgba(0, 0, 0, 0.2); } footer { color: rgb(152, 143, 129); } .rst-content footer span.commit tt, footer span.commit .rst-content tt, footer span.commit code { background-image: none; background-color: initial; border-color: initial; color: rgb(152, 143, 129); } #search-results .search li { border-bottom-color: rgb(56, 61, 63); } #search-results .search li:first-child { border-top-color: rgb(56, 61, 63); } #search-results .context { color: rgb(152, 143, 129); } @media screen and (max-width: 768px) { .wy-body-for-nav { background-image: initial; background-color: rgb(26, 28, 29); } } @media screen and (min-width: 1100px) { .wy-nav-content-wrap { background-image: initial; background-color: rgba(0, 0, 0, 0.05); } .wy-nav-content { background-image: initial; background-color: rgb(26, 28, 29); } } .rst-versions { color: rgb(230, 228, 225); background-image: initial; background-color: rgb(23, 24, 25); } .rst-versions a { color: rgb(84, 164, 217); text-decoration-color: initial; } .rst-versions .rst-current-version { background-color: rgb(29, 31, 32); color: rgb(92, 218, 145); } .rst-content .code-block-caption .rst-versions .rst-current-version .headerlink, .rst-content .eqno .rst-versions .rst-current-version .headerlink, .rst-content .rst-versions .rst-current-version .admonition-title, .rst-content code.download .rst-versions .rst-current-version span:first-child, .rst-content dl dt .rst-versions .rst-current-version .headerlink, .rst-content h1 .rst-versions .rst-current-version .headerlink, .rst-content h2 .rst-versions .rst-current-version .headerlink, .rst-content h3 .rst-versions .rst-current-version .headerlink, .rst-content h4 .rst-versions .rst-current-version .headerlink, .rst-content h5 .rst-versions .rst-current-version .headerlink, .rst-content h6 .rst-versions .rst-current-version .headerlink, .rst-content p .rst-versions .rst-current-version .headerlink, .rst-content table > caption .rst-versions .rst-current-version .headerlink, .rst-content tt.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .fa, .rst-versions .rst-current-version .icon, .rst-versions .rst-current-version .rst-content .admonition-title, .rst-versions .rst-current-version .rst-content .code-block-caption .headerlink, .rst-versions .rst-current-version .rst-content .eqno .headerlink, .rst-versions .rst-current-version .rst-content code.download span:first-child, .rst-versions .rst-current-version .rst-content dl dt .headerlink, .rst-versions .rst-current-version .rst-content h1 .headerlink, .rst-versions .rst-current-version .rst-content h2 .headerlink, .rst-versions .rst-current-version .rst-content h3 .headerlink, .rst-versions .rst-current-version .rst-content h4 .headerlink, .rst-versions .rst-current-version .rst-content h5 .headerlink, .rst-versions .rst-current-version .rst-content h6 .headerlink, .rst-versions .rst-current-version .rst-content p .headerlink, .rst-versions .rst-current-version .rst-content table > caption .headerlink, .rst-versions .rst-current-version .rst-content tt.download span:first-child, .rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand, .wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand { color: rgb(230, 228, 225); } .rst-versions .rst-current-version.rst-out-of-date { background-color: rgb(162, 33, 20); color: rgb(232, 230, 227); } .rst-versions .rst-current-version.rst-active-old-version { background-color: rgb(192, 156, 11); color: rgb(232, 230, 227); } .rst-versions .rst-other-versions { color: rgb(152, 143, 129); } .rst-versions .rst-other-versions hr { border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-top-color: rgb(119, 111, 98); } .rst-versions .rst-other-versions dd a { color: rgb(230, 228, 225); } .rst-versions.rst-badge { border-color: initial; } .rst-content abbr[title] { text-decoration-color: initial; } .rst-content.style-external-links a.reference.external::after { color: rgb(184, 178, 169); } .rst-content div[class^="highlight"], .rst-content pre.literal-block { border-color: rgb(56, 61, 63); } .rst-content div[class^="highlight"] div[class^="highlight"], .rst-content pre.literal-block div[class^="highlight"] { border-color: initial; } .rst-content .linenodiv pre { border-right-color: rgb(54, 59, 61); } .rst-content div.highlight span.linenos { border-right-color: rgb(54, 59, 61); } .rst-content .admonition table { border-color: rgba(140, 130, 115, 0.1); } .rst-content .admonition table td, .rst-content .admonition table th { background-image: initial !important; background-color: transparent !important; border-color: rgba(140, 130, 115, 0.1) !important; } .rst-content .section ol.loweralpha, .rst-content .section ol.loweralpha > li, .rst-content .toctree-wrapper ol.loweralpha, .rst-content .toctree-wrapper ol.loweralpha > li, .rst-content section ol.loweralpha, .rst-content section ol.loweralpha > li { list-style-image: initial; } .rst-content .section ol.upperalpha, .rst-content .section ol.upperalpha > li, .rst-content .toctree-wrapper ol.upperalpha, .rst-content .toctree-wrapper ol.upperalpha > li, .rst-content section ol.upperalpha, .rst-content section ol.upperalpha > li { list-style-image: initial; } .rst-content .toc-backref { color: rgb(192, 186, 178); } .rst-content .btn:focus { outline-color: initial; } .rst-content .sidebar { background-image: initial; background-color: rgb(27, 36, 36); border-color: rgb(56, 61, 63); } .rst-content .sidebar .sidebar-title { background-image: initial; background-color: rgb(40, 43, 45); } .rst-content .highlighted { background-image: initial; background-color: rgb(192, 156, 11); box-shadow: rgb(192, 156, 11) 0px 0px 0px 2px; } html.writer-html4 .rst-content table.docutils.citation, html.writer-html4 .rst-content table.docutils.footnote { background-image: none; background-color: initial; border-color: initial; } html.writer-html4 .rst-content table.docutils.citation td, html.writer-html4 .rst-content table.docutils.citation tr, html.writer-html4 .rst-content table.docutils.footnote td, html.writer-html4 .rst-content table.docutils.footnote tr { border-color: initial; background-color: transparent !important; } .rst-content table.docutils.footnote, html.writer-html4 .rst-content table.docutils.citation, html.writer-html5 .rst-content dl.footnote { color: rgb(152, 143, 129); } .rst-content table.docutils.footnote code, .rst-content table.docutils.footnote tt, html.writer-html4 .rst-content table.docutils.citation code, html.writer-html4 .rst-content table.docutils.citation tt, html.writer-html5 .rst-content dl.footnote code, html.writer-html5 .rst-content dl.footnote tt { color: rgb(178, 172, 162); } .rst-content table.docutils th { border-color: rgb(56, 61, 63); } html.writer-html5 .rst-content table.docutils th { border-color: rgb(56, 61, 63); } .rst-content table.field-list, .rst-content table.field-list td { border-color: initial; } .rst-content code, .rst-content tt { color: rgb(232, 230, 227); } .rst-content code.literal, .rst-content tt.literal { color: rgb(233, 88, 73); } .rst-content code.xref, .rst-content tt.xref, a .rst-content code, a .rst-content tt { color: rgb(192, 186, 178); } .rst-content a code, .rst-content a tt { color: rgb(84, 164, 217); } html.writer-html4 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt { background-image: initial; background-color: rgb(32, 35, 36); color: rgb(84, 164, 217); border-top-color: rgb(28, 89, 128); } html.writer-html4 .rst-content dl:not(.docutils) > dt::before, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt::before { color: rgb(109, 178, 223); } html.writer-html4 .rst-content dl:not(.docutils) > dt .headerlink, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt .headerlink { color: rgb(192, 186, 178); } html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { border-top-color: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: rgb(62, 68, 70); background-image: initial; background-color: rgb(32, 35, 37); color: rgb(178, 172, 162); } html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt .headerlink, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt .headerlink { color: rgb(192, 186, 178); } html.writer-html4 .rst-content dl:not(.docutils) code.descclassname, html.writer-html4 .rst-content dl:not(.docutils) code.descname, html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname, html.writer-html4 .rst-content dl:not(.docutils) tt.descname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname { background-color: transparent; border-color: initial; } html.writer-html4 .rst-content dl:not(.docutils) .optional, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { color: rgb(232, 230, 227); } html.writer-html4 .rst-content dl:not(.docutils) .descclassname, html.writer-html4 .rst-content dl:not(.docutils) .descname, html.writer-html4 .rst-content dl:not(.docutils) .sig-name, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descclassname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name { color: rgb(232, 230, 227); } .rst-content .viewcode-back, .rst-content .viewcode-link { color: rgb(92, 218, 145); } .rst-content code.download, .rst-content tt.download { background-image: inherit; background-color: inherit; color: inherit; border-color: inherit; } .rst-content .guilabel { border-color: rgb(27, 84, 122); background-image: initial; background-color: rgb(32, 35, 36); } span[id*="MathJax-Span"] { color: rgb(192, 186, 178); } td.linenos .normal { color: inherit; background-color: transparent; } span.linenos { color: inherit; background-color: transparent; } td.linenos .special { color: rgb(232, 230, 227); background-color: rgb(89, 89, 0); } span.linenos.special { color: rgb(232, 230, 227); background-color: rgb(89, 89, 0); } .highlight .hll { background-color: rgb(82, 82, 0); } .highlight { background-image: initial; background-color: rgb(61, 82, 0); } .highlight .c { color: rgb(119, 179, 195); } .highlight .err { border-color: rgb(179, 0, 0); } .highlight .k { color: rgb(126, 255, 163); } .highlight .o { color: rgb(168, 160, 149); } .highlight .ch { color: rgb(119, 179, 195); } .highlight .cm { color: rgb(119, 179, 195); } .highlight .cp { color: rgb(126, 255, 163); } .highlight .cpf { color: rgb(119, 179, 195); } .highlight .c1 { color: rgb(119, 179, 195); } .highlight .cs { color: rgb(119, 179, 195); background-color: rgb(60, 0, 0); } .highlight .gd { color: rgb(255, 92, 92); } .highlight .gr { color: rgb(255, 26, 26); } .highlight .gh { color: rgb(127, 174, 255); } .highlight .gi { color: rgb(92, 255, 92); } .highlight .go { color: rgb(200, 195, 188); } .highlight .gp { color: rgb(246, 147, 68); } .highlight .gu { color: rgb(255, 114, 255); } .highlight .gt { color: rgb(71, 160, 255); } .highlight .kc { color: rgb(126, 255, 163); } .highlight .kd { color: rgb(126, 255, 163); } .highlight .kn { color: rgb(126, 255, 163); } .highlight .kp { color: rgb(126, 255, 163); } .highlight .kr { color: rgb(126, 255, 163); } .highlight .kt { color: rgb(255, 137, 103); } .highlight .m { color: rgb(125, 222, 174); } .highlight .s { color: rgb(123, 166, 202); } .highlight .na { color: rgb(123, 166, 202); } .highlight .nb { color: rgb(126, 255, 163); } .highlight .nc { color: rgb(81, 194, 242); } .highlight .no { color: rgb(103, 177, 215); } .highlight .nd { color: rgb(178, 172, 162); } .highlight .ni { color: rgb(217, 100, 73); } .highlight .ne { color: rgb(126, 255, 163); } .highlight .nf { color: rgb(131, 186, 249); } .highlight .nl { color: rgb(137, 193, 255); } .highlight .nn { color: rgb(81, 194, 242); } .highlight .nt { color: rgb(138, 191, 249); } .highlight .nv { color: rgb(190, 103, 215); } .highlight .ow { color: rgb(126, 255, 163); } .highlight .w { color: rgb(189, 183, 175); } .highlight .mb { color: rgb(125, 222, 174); } .highlight .mf { color: rgb(125, 222, 174); } .highlight .mh { color: rgb(125, 222, 174); } .highlight .mi { color: rgb(125, 222, 174); } .highlight .mo { color: rgb(125, 222, 174); } .highlight .sa { color: rgb(123, 166, 202); } .highlight .sb { color: rgb(123, 166, 202); } .highlight .sc { color: rgb(123, 166, 202); } .highlight .dl { color: rgb(123, 166, 202); } .highlight .sd { color: rgb(123, 166, 202); } .highlight .s2 { color: rgb(123, 166, 202); } .highlight .se { color: rgb(123, 166, 202); } .highlight .sh { color: rgb(123, 166, 202); } .highlight .si { color: rgb(117, 168, 209); } .highlight .sx { color: rgb(246, 147, 68); } .highlight .sr { color: rgb(133, 182, 224); } .highlight .s1 { color: rgb(123, 166, 202); } .highlight .ss { color: rgb(188, 230, 128); } .highlight .bp { color: rgb(126, 255, 163); } .highlight .fm { color: rgb(131, 186, 249); } .highlight .vc { color: rgb(190, 103, 215); } .highlight .vg { color: rgb(190, 103, 215); } .highlight .vi { color: rgb(190, 103, 215); } .highlight .vm { color: rgb(190, 103, 215); } .highlight .il { color: rgb(125, 222, 174); } [role="tablist"] { border-bottom-color: rgb(70, 76, 79); } .sphinx-tabs-tab { color: rgb(119, 182, 226); background-color: rgba(24, 26, 27, 0); border-color: initial; } .sphinx-tabs-tab[aria-selected="true"] { border-color: rgb(70, 76, 79) rgb(70, 76, 79) rgb(48, 52, 54); background-color: rgb(24, 26, 27); } .sphinx-tabs-panel { border-right-color: rgb(70, 76, 79); border-bottom-color: rgb(70, 76, 79); border-left-color: rgb(70, 76, 79); border-top-color: initial; background-image: initial; background-color: rgb(24, 26, 27); } a.copybtn { border-color: initial; } .o-tooltip--left::after { background-image: initial; background-color: rgb(96, 104, 108); color: rgb(232, 230, 227); } @media (prefers-color-scheme: dark) { html { background-color: rgb(19, 21, 22) !important; } html, body, input, textarea, select, button { background-color: rgb(19, 21, 22); } html, body, input, textarea, select, button { border-color: rgb(106, 98, 87); color: rgb(216, 212, 207); } a { color: rgb(61, 165, 255); } table { border-color: rgb(111, 103, 91); } ::placeholder { color: rgb(178, 171, 161); } input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill { background-color: rgb(68, 73, 0) !important; color: rgb(216, 212, 207) !important; } ::selection { background-color: rgb(0, 62, 136) !important; color: rgb(216, 212, 207) !important; } :root { --darkreader-neutral-background: #131516; --darkreader-text--darkreader-neutral-text: #cdc8c2; --darkreader-selection-background: #004daa; --darkreader-selection-text: #e8e6e3; } a:active, a:hover { outline-color: initial; } abbr[title] { border-bottom-color: initial; } ins { background-image: initial; background-color: rgb(90, 90, 0); text-decoration-color: initial; } ins, mark { color: rgb(216, 212, 207); } mark { background-image: initial; background-color: rgb(163, 163, 0); } dl, ol, ul { list-style-image: none; } li { list-style-image: initial; } img { border-color: initial; } .chromeframe { background-image: initial; background-color: rgb(42, 46, 47); color: rgb(216, 212, 207); } .ir { border-color: initial; background-color: transparent; } .visuallyhidden { border-color: initial; } .fa-border { border-color: rgb(122, 113, 100); } .fa-inverse { color: rgb(216, 212, 207); } .sr-only { border-color: initial; } .fa::before, .icon::before, .rst-content .admonition-title::before, .rst-content .code-block-caption .headerlink::before, .rst-content code.download span:first-child::before, .rst-content dl dt .headerlink::before, .rst-content h1 .headerlink::before, .rst-content h2 .headerlink::before, .rst-content h3 .headerlink::before, .rst-content h4 .headerlink::before, .rst-content h5 .headerlink::before, .rst-content h6 .headerlink::before, .rst-content p.caption .headerlink::before, .rst-content table > caption .headerlink::before, .rst-content tt.download span:first-child::before, .wy-dropdown .caret::before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context::before, .wy-inline-validate.wy-inline-validate-info .wy-input-context::before, .wy-inline-validate.wy-inline-validate-success .wy-input-context::before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context::before, .wy-menu-vertical li.current > a span.toctree-expand::before, .wy-menu-vertical li.on a span.toctree-expand::before, .wy-menu-vertical li span.toctree-expand::before { text-decoration-color: inherit; } .rst-content .code-block-caption a .headerlink, .rst-content a .admonition-title, .rst-content code.download a span:first-child, .rst-content dl dt a .headerlink, .rst-content h1 a .headerlink, .rst-content h2 a .headerlink, .rst-content h3 a .headerlink, .rst-content h4 a .headerlink, .rst-content h5 a .headerlink, .rst-content h6 a .headerlink, .rst-content p.caption a .headerlink, .rst-content table > caption a .headerlink, .rst-content tt.download a span:first-child, .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li a span.toctree-expand, a .fa, a .icon, a .rst-content .admonition-title, a .rst-content .code-block-caption .headerlink, a .rst-content code.download span:first-child, a .rst-content dl dt .headerlink, a .rst-content h1 .headerlink, a .rst-content h2 .headerlink, a .rst-content h3 .headerlink, a .rst-content h4 .headerlink, a .rst-content h5 .headerlink, a .rst-content h6 .headerlink, a .rst-content p.caption .headerlink, a .rst-content table > caption .headerlink, a .rst-content tt.download span:first-child, a .wy-menu-vertical li span.toctree-expand { text-decoration-color: inherit; } .rst-content .admonition, .rst-content .admonition-todo, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .note, .rst-content .seealso, .rst-content .tip, .rst-content .warning, .wy-alert { background-image: initial; background-color: rgb(26, 28, 29); } .rst-content .admonition-title, .wy-alert-title { color: rgb(216, 212, 207); background-image: initial; background-color: rgb(23, 73, 105); } .rst-content .danger, .rst-content .error, .rst-content .wy-alert-danger.admonition, .rst-content .wy-alert-danger.admonition-todo, .rst-content .wy-alert-danger.attention, .rst-content .wy-alert-danger.caution, .rst-content .wy-alert-danger.hint, .rst-content .wy-alert-danger.important, .rst-content .wy-alert-danger.note, .rst-content .wy-alert-danger.seealso, .rst-content .wy-alert-danger.tip, .rst-content .wy-alert-danger.warning, .wy-alert.wy-alert-danger { background-image: initial; background-color: rgb(42, 10, 6); } .rst-content .danger .admonition-title, .rst-content .danger .wy-alert-title, .rst-content .error .admonition-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .admonition-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .wy-alert.wy-alert-danger .wy-alert-title { background-image: initial; background-color: rgb(86, 18, 10); } .rst-content .admonition-todo, .rst-content .attention, .rst-content .caution, .rst-content .warning, .rst-content .wy-alert-warning.admonition, .rst-content .wy-alert-warning.danger, .rst-content .wy-alert-warning.error, .rst-content .wy-alert-warning.hint, .rst-content .wy-alert-warning.important, .rst-content .wy-alert-warning.note, .rst-content .wy-alert-warning.seealso, .rst-content .wy-alert-warning.tip, .wy-alert.wy-alert-warning { background-image: initial; background-color: rgb(66, 42, 0); } .rst-content .admonition-todo .admonition-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .attention .admonition-title, .rst-content .attention .wy-alert-title, .rst-content .caution .admonition-title, .rst-content .caution .wy-alert-title, .rst-content .warning .admonition-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.admonition .admonition-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .wy-alert.wy-alert-warning .wy-alert-title { background-image: initial; background-color: rgb(98, 52, 11); } .rst-content .note, .rst-content .seealso, .rst-content .wy-alert-info.admonition, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .wy-alert.wy-alert-info { background-image: initial; background-color: rgb(26, 28, 29); } .rst-content .note .admonition-title, .rst-content .note .wy-alert-title, .rst-content .seealso .admonition-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .admonition-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .wy-alert.wy-alert-info .wy-alert-title { background-image: initial; background-color: rgb(23, 73, 105); } .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .wy-alert-success.admonition, .rst-content .wy-alert-success.admonition-todo, .rst-content .wy-alert-success.attention, .rst-content .wy-alert-success.caution, .rst-content .wy-alert-success.danger, .rst-content .wy-alert-success.error, .rst-content .wy-alert-success.note, .rst-content .wy-alert-success.seealso, .rst-content .wy-alert-success.warning, .wy-alert.wy-alert-success { background-image: initial; background-color: rgb(7, 53, 46); } .rst-content .hint .admonition-title, .rst-content .hint .wy-alert-title, .rst-content .important .admonition-title, .rst-content .important .wy-alert-title, .rst-content .tip .admonition-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .admonition-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .wy-alert.wy-alert-success .wy-alert-title { background-image: initial; background-color: rgb(17, 120, 100); } .rst-content .wy-alert-neutral.admonition, .rst-content .wy-alert-neutral.admonition-todo, .rst-content .wy-alert-neutral.attention, .rst-content .wy-alert-neutral.caution, .rst-content .wy-alert-neutral.danger, .rst-content .wy-alert-neutral.error, .rst-content .wy-alert-neutral.hint, .rst-content .wy-alert-neutral.important, .rst-content .wy-alert-neutral.note, .rst-content .wy-alert-neutral.seealso, .rst-content .wy-alert-neutral.tip, .rst-content .wy-alert-neutral.warning, .wy-alert.wy-alert-neutral { background-image: initial; background-color: rgb(22, 29, 29); } .rst-content .wy-alert-neutral.admonition-todo .admonition-title, .rst-content .wy-alert-neutral.admonition-todo .wy-alert-title, .rst-content .wy-alert-neutral.admonition .admonition-title, .rst-content .wy-alert-neutral.admonition .wy-alert-title, .rst-content .wy-alert-neutral.attention .admonition-title, .rst-content .wy-alert-neutral.attention .wy-alert-title, .rst-content .wy-alert-neutral.caution .admonition-title, .rst-content .wy-alert-neutral.caution .wy-alert-title, .rst-content .wy-alert-neutral.danger .admonition-title, .rst-content .wy-alert-neutral.danger .wy-alert-title, .rst-content .wy-alert-neutral.error .admonition-title, .rst-content .wy-alert-neutral.error .wy-alert-title, .rst-content .wy-alert-neutral.hint .admonition-title, .rst-content .wy-alert-neutral.hint .wy-alert-title, .rst-content .wy-alert-neutral.important .admonition-title, .rst-content .wy-alert-neutral.important .wy-alert-title, .rst-content .wy-alert-neutral.note .admonition-title, .rst-content .wy-alert-neutral.note .wy-alert-title, .rst-content .wy-alert-neutral.seealso .admonition-title, .rst-content .wy-alert-neutral.seealso .wy-alert-title, .rst-content .wy-alert-neutral.tip .admonition-title, .rst-content .wy-alert-neutral.tip .wy-alert-title, .rst-content .wy-alert-neutral.warning .admonition-title, .rst-content .wy-alert-neutral.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-neutral .admonition-title, .wy-alert.wy-alert-neutral .rst-content .admonition-title, .wy-alert.wy-alert-neutral .wy-alert-title { color: rgb(188, 182, 173); background-image: initial; background-color: rgb(32, 35, 36); } .rst-content .wy-alert-neutral.admonition-todo a, .rst-content .wy-alert-neutral.admonition a, .rst-content .wy-alert-neutral.attention a, .rst-content .wy-alert-neutral.caution a, .rst-content .wy-alert-neutral.danger a, .rst-content .wy-alert-neutral.error a, .rst-content .wy-alert-neutral.hint a, .rst-content .wy-alert-neutral.important a, .rst-content .wy-alert-neutral.note a, .rst-content .wy-alert-neutral.seealso a, .rst-content .wy-alert-neutral.tip a, .rst-content .wy-alert-neutral.warning a, .wy-alert.wy-alert-neutral a { color: rgb(94, 169, 219); } .wy-tray-container li { background-image: initial; background-color: transparent; color: rgb(216, 212, 207); box-shadow: rgba(0, 0, 0, 0.1) 0px 5px 5px 0px; } .wy-tray-container li.wy-tray-item-success { background-image: initial; background-color: rgb(25, 111, 62); } .wy-tray-container li.wy-tray-item-info { background-image: initial; background-color: rgb(26, 82, 118); } .wy-tray-container li.wy-tray-item-warning { background-image: initial; background-color: rgb(142, 75, 16); } .wy-tray-container li.wy-tray-item-danger { background-image: initial; background-color: rgb(130, 26, 16); } .btn { color: rgb(216, 212, 207); border-color: rgba(84, 91, 95, 0.1); background-color: rgb(25, 111, 62); text-decoration-color: initial; box-shadow: rgba(19, 21, 22, 0.5) 0px 1px 2px -1px inset, rgba(0, 0, 0, 0.1) 0px -2px 0px 0px inset; } .btn-hover { background-image: initial; background-color: rgb(30, 91, 132); color: rgb(216, 212, 207); } .btn:hover { background-image: initial; background-color: rgb(28, 125, 69); color: rgb(216, 212, 207); } .btn:focus { background-image: initial; background-color: rgb(28, 125, 69); outline-color: initial; } .btn:active { box-shadow: rgba(0, 0, 0, 0.05) 0px -1px 0px 0px inset, rgba(0, 0, 0, 0.1) 0px 2px 0px 0px inset; } .btn:visited { color: rgb(216, 212, 207); } .btn-disabled, .btn-disabled:active, .btn-disabled:focus, .btn-disabled:hover, .btn:disabled { background-image: none; box-shadow: none; } .btn-info { background-color: rgb(26, 82, 118) !important; } .btn-info:hover { background-color: rgb(30, 91, 132) !important; } .btn-neutral { background-color: rgb(22, 29, 29) !important; color: rgb(188, 182, 173) !important; } .btn-neutral:hover { color: rgb(188, 182, 173); background-color: rgb(27, 35, 35) !important; } .btn-neutral:visited { color: rgb(188, 182, 173) !important; } .btn-success { background-color: rgb(25, 111, 62) !important; } .btn-success:hover { background-color: rgb(22, 98, 54) !important; } .btn-danger { background-color: rgb(130, 26, 16) !important; } .btn-danger:hover { background-color: rgb(119, 24, 14) !important; } .btn-warning { background-color: rgb(142, 75, 16) !important; } .btn-warning:hover { background-color: rgb(132, 70, 14) !important; } .btn-invert { background-color: rgb(21, 22, 23); } .btn-invert:hover { background-color: rgb(28, 31, 32) !important; } .btn-link { color: rgb(94, 169, 219); box-shadow: none; background-color: transparent !important; border-color: transparent !important; } .btn-link:active, .btn-link:hover { box-shadow: none; background-color: transparent !important; color: rgb(90, 168, 218) !important; } .btn-link:visited { color: rgb(170, 113, 192); } .wy-dropdown-menu { background-image: initial; background-color: rgb(21, 22, 23); border-color: rgb(119, 111, 98); box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 2px 0px; } .wy-dropdown-menu > dd > a { color: rgb(188, 182, 173); } .wy-dropdown-menu > dd > a:hover { background-image: initial; background-color: rgb(26, 82, 118); color: rgb(216, 212, 207); } .wy-dropdown-menu > dd.divider { border-top-color: rgb(119, 111, 98); } .wy-dropdown-menu > dd.call-to-action { background-image: initial; background-color: rgb(32, 35, 36); } .wy-dropdown-menu > dd.call-to-action:hover { background-image: initial; background-color: rgb(32, 35, 36); } .wy-dropdown-menu > dd.call-to-action .btn { color: rgb(216, 212, 207); } .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu { background-image: initial; background-color: rgb(21, 22, 23); } .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { background-image: initial; background-color: rgb(26, 82, 118); color: rgb(216, 212, 207); } .wy-dropdown-arrow::before { border-bottom-color: rgb(122, 113, 100); border-left-color: transparent; border-right-color: transparent; } fieldset, legend { border-color: initial; } label { color: rgb(193, 188, 180); } .wy-control-group.wy-control-group-required > label::after { color: rgb(234, 96, 82); } .wy-form-message-inline { color: rgb(171, 164, 153); } .wy-form-message { color: rgb(171, 164, 153); } input[type="color"], input[type="date"], input[type="datetime-local"], input[type="datetime"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] { border-color: rgb(118, 110, 97); box-shadow: rgb(35, 38, 39) 0px 1px 3px inset; } input[type="color"]:focus, input[type="date"]:focus, input[type="datetime-local"]:focus, input[type="datetime"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus { outline-color: initial; border-color: rgb(103, 96, 85); } input.no-focus:focus { border-color: rgb(118, 110, 97) !important; } input[type="checkbox"]:focus, input[type="file"]:focus, input[type="radio"]:focus { outline-color: rgb(15, 126, 186); } input[type="color"][disabled], input[type="date"][disabled], input[type="datetime-local"][disabled], input[type="datetime"][disabled], input[type="email"][disabled], input[type="month"][disabled], input[type="number"][disabled], input[type="password"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="text"][disabled], input[type="time"][disabled], input[type="url"][disabled], input[type="week"][disabled] { background-color: rgb(21, 23, 24); } input:focus:invalid, select:focus:invalid, textarea:focus:invalid { color: rgb(234, 96, 82); border-color: rgb(183, 38, 22); } input:focus:invalid:focus, select:focus:invalid:focus, textarea:focus:invalid:focus { border-color: rgb(183, 38, 22); } input[type="checkbox"]:focus:invalid:focus, input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus { outline-color: rgb(183, 38, 22); } select, textarea { border-color: rgb(118, 110, 97); box-shadow: rgb(35, 38, 39) 0px 1px 3px inset; } select { border-color: rgb(118, 110, 97); background-color: rgb(19, 21, 22); } select:focus, textarea:focus { outline-color: initial; } input[readonly], select[disabled], select[readonly], textarea[disabled], textarea[readonly] { background-color: rgb(21, 23, 24); } .wy-checkbox, .wy-radio { color: rgb(188, 182, 173); } .wy-input-prefix .wy-input-context, .wy-input-suffix .wy-input-context { background-color: rgb(22, 29, 29); border-color: rgb(118, 110, 97); color: rgb(171, 164, 153); } .wy-input-suffix .wy-input-context { border-left-color: initial; } .wy-input-prefix .wy-input-context { border-right-color: initial; } .wy-switch::before { background-image: initial; background-color: rgb(42, 46, 47); } .wy-switch::after { background-image: initial; background-color: rgb(66, 71, 74); } .wy-switch span { color: rgb(193, 188, 180); } .wy-switch.active::before { background-image: initial; background-color: rgb(19, 85, 46); } .wy-switch.active::after { background-image: initial; background-color: rgb(25, 111, 62); } .wy-control-group.wy-control-group-error .wy-form-message, .wy-control-group.wy-control-group-error > label { color: rgb(234, 96, 82); } .wy-control-group.wy-control-group-error input[type="color"], .wy-control-group.wy-control-group-error input[type="date"], .wy-control-group.wy-control-group-error input[type="datetime-local"], .wy-control-group.wy-control-group-error input[type="datetime"], .wy-control-group.wy-control-group-error input[type="email"], .wy-control-group.wy-control-group-error input[type="month"], .wy-control-group.wy-control-group-error input[type="number"], .wy-control-group.wy-control-group-error input[type="password"], .wy-control-group.wy-control-group-error input[type="search"], .wy-control-group.wy-control-group-error input[type="tel"], .wy-control-group.wy-control-group-error input[type="text"], .wy-control-group.wy-control-group-error input[type="time"], .wy-control-group.wy-control-group-error input[type="url"], .wy-control-group.wy-control-group-error input[type="week"], .wy-control-group.wy-control-group-error textarea { border-color: rgb(183, 38, 22); } .wy-inline-validate.wy-inline-validate-success .wy-input-context { color: rgb(99, 220, 150); } .wy-inline-validate.wy-inline-validate-danger .wy-input-context { color: rgb(234, 96, 82); } .wy-inline-validate.wy-inline-validate-warning .wy-input-context { color: rgb(234, 146, 69); } .wy-inline-validate.wy-inline-validate-info .wy-input-context { color: rgb(94, 169, 219); } .rst-content table.docutils caption, .rst-content table.field-list caption, .wy-table caption { color: rgb(216, 212, 207); } .rst-content table.docutils thead, .rst-content table.field-list thead, .wy-table thead { color: rgb(216, 212, 207); } .rst-content table.docutils thead th, .rst-content table.field-list thead th, .wy-table thead th { border-bottom-color: rgb(120, 112, 99); } .rst-content table.docutils td, .rst-content table.field-list td, .wy-table td { background-color: transparent; } .wy-table-secondary { color: rgb(160, 151, 139); } .wy-table-tertiary { color: rgb(160, 151, 139); } .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td, .wy-table-backed, .wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td { background-color: rgb(22, 29, 29); } .rst-content table.docutils, .wy-table-bordered-all { border-color: rgb(120, 112, 99); } .rst-content table.docutils td, .wy-table-bordered-all td { border-bottom-color: rgb(120, 112, 99); border-left-color: rgb(120, 112, 99); } .wy-table-bordered { border-color: rgb(120, 112, 99); } .wy-table-bordered-rows td { border-bottom-color: rgb(120, 112, 99); } .wy-table-horizontal td, .wy-table-horizontal th { border-bottom-color: rgb(120, 112, 99); } a { color: rgb(94, 169, 219); text-decoration-color: initial; } a:hover { color: rgb(82, 164, 217); } a:visited { color: rgb(170, 113, 192); } body { color: rgb(188, 182, 173); background-image: initial; background-color: rgb(26, 29, 30); } .wy-text-strike { text-decoration-color: initial; } .wy-text-warning { color: rgb(234, 146, 69) !important; } a.wy-text-warning:hover { color: rgb(237, 160, 92) !important; } .wy-text-info { color: rgb(94, 169, 219) !important; } a.wy-text-info:hover { color: rgb(90, 168, 218) !important; } .wy-text-success { color: rgb(99, 220, 150) !important; } a.wy-text-success:hover { color: rgb(86, 217, 142) !important; } .wy-text-danger { color: rgb(234, 96, 82) !important; } a.wy-text-danger:hover { color: rgb(237, 118, 104) !important; } .wy-text-neutral { color: rgb(188, 182, 173) !important; } a.wy-text-neutral:hover { color: rgb(177, 170, 160) !important; } hr { border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-top-color: rgb(120, 112, 99); } .rst-content code, .rst-content tt, code { background-image: initial; background-color: rgb(19, 21, 22); border-color: rgb(120, 112, 99); color: rgb(234, 96, 82); } .rst-content .section ul, .rst-content .toctree-wrapper ul, .wy-plain-list-disc, article ul { list-style-image: initial; } .rst-content .section ul li, .rst-content .toctree-wrapper ul li, .wy-plain-list-disc li, article ul li { list-style-image: initial; } .rst-content .section ul li li, .rst-content .toctree-wrapper ul li li, .wy-plain-list-disc li li, article ul li li { list-style-image: initial; } .rst-content .section ul li li li, .rst-content .toctree-wrapper ul li li li, .wy-plain-list-disc li li li, article ul li li li { list-style-image: initial; } .rst-content .section ul li ol li, .rst-content .toctree-wrapper ul li ol li, .wy-plain-list-disc li ol li, article ul li ol li { list-style-image: initial; } .rst-content .section ol, .rst-content ol.arabic, .wy-plain-list-decimal, article ol { list-style-image: initial; } .rst-content .section ol li, .rst-content ol.arabic li, .wy-plain-list-decimal li, article ol li { list-style-image: initial; } .rst-content .section ol li ul li, .rst-content ol.arabic li ul li, .wy-plain-list-decimal li ul li, article ol li ul li { list-style-image: initial; } .rst-content .wy-breadcrumbs li tt, .wy-breadcrumbs li .rst-content tt, .wy-breadcrumbs li code { border-color: initial; background-image: none; background-color: initial; } .rst-content .wy-breadcrumbs li tt.literal, .wy-breadcrumbs li .rst-content tt.literal, .wy-breadcrumbs li code.literal { color: rgb(188, 182, 173); } .wy-breadcrumbs-extra { color: rgb(182, 176, 167); } .wy-menu a:hover { text-decoration-color: initial; } .wy-menu-horiz li:hover { background-image: initial; background-color: rgba(19, 21, 22, 0.1); } .wy-menu-horiz li.divide-left { border-left-color: rgb(104, 97, 86); } .wy-menu-horiz li.divide-right { border-right-color: rgb(104, 97, 86); } .wy-menu-vertical header, .wy-menu-vertical p.caption { color: rgb(101, 173, 220); } .wy-menu-vertical li.divide-top { border-top-color: rgb(104, 97, 86); } .wy-menu-vertical li.divide-bottom { border-bottom-color: rgb(104, 97, 86); } .wy-menu-vertical li.current { background-image: initial; background-color: rgb(32, 35, 36); } .wy-menu-vertical li.current a { color: rgb(160, 151, 139); border-right-color: rgb(118, 110, 97); } .wy-menu-vertical li.current a:hover { background-image: initial; background-color: rgb(38, 41, 42); } .rst-content .wy-menu-vertical li tt, .wy-menu-vertical li .rst-content tt, .wy-menu-vertical li code { border-color: initial; background-image: inherit; background-color: inherit; color: inherit; } .wy-menu-vertical li span.toctree-expand { color: rgb(182, 175, 166); } .wy-menu-vertical li.current > a, .wy-menu-vertical li.on a { color: rgb(188, 182, 173); background-image: initial; background-color: rgb(21, 22, 23); border-color: initial; } .wy-menu-vertical li.current > a:hover, .wy-menu-vertical li.on a:hover { background-image: initial; background-color: rgb(21, 22, 23); } .wy-menu-vertical li.current > a:hover span.toctree-expand, .wy-menu-vertical li.on a:hover span.toctree-expand { color: rgb(160, 151, 139); } .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand { color: rgb(193, 188, 180); } .wy-menu-vertical li.toctree-l1.current > a { border-bottom-color: rgb(118, 110, 97); border-top-color: rgb(118, 110, 97); } .wy-menu-vertical li.toctree-l2 a, .wy-menu-vertical li.toctree-l3 a, .wy-menu-vertical li.toctree-l4 a, .wy-menu-vertical li.toctree-l5 a, .wy-menu-vertical li.toctree-l6 a, .wy-menu-vertical li.toctree-l7 a, .wy-menu-vertical li.toctree-l8 a, .wy-menu-vertical li.toctree-l9 a, .wy-menu-vertical li.toctree-l10 a { color: rgb(188, 182, 173); } .wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l4 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l5 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l6 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l7 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l8 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l9 a:hover span.toctree-expand, .wy-menu-vertical li.toctree-l10 a:hover span.toctree-expand { color: rgb(160, 151, 139); } .wy-menu-vertical li.toctree-l2.current > a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { background-image: initial; background-color: rgb(43, 47, 49); } .wy-menu-vertical li.toctree-l2 span.toctree-expand { color: rgb(175, 168, 158); } .wy-menu-vertical li.toctree-l3.current > a, .wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a { background-image: initial; background-color: rgb(49, 53, 55); } .wy-menu-vertical li.toctree-l3 span.toctree-expand { color: rgb(169, 162, 151); } .wy-menu-vertical li ul li a { color: rgb(199, 194, 187); } .wy-menu-vertical a { color: rgb(199, 194, 187); } .wy-menu-vertical a:hover { background-color: rgb(46, 49, 51); } .wy-menu-vertical a:hover span.toctree-expand { color: rgb(199, 194, 187); } .wy-menu-vertical a:active { background-color: rgb(26, 82, 118); color: rgb(216, 212, 207); } .wy-menu-vertical a:active span.toctree-expand { color: rgb(216, 212, 207); } .wy-side-nav-search { background-color: rgb(26, 82, 118); color: rgb(215, 211, 206); } .wy-side-nav-search input[type="text"] { border-color: rgb(35, 112, 161); } .wy-side-nav-search img { background-color: rgb(26, 82, 118); } .wy-side-nav-search .wy-dropdown > a, .wy-side-nav-search > a { color: rgb(215, 211, 206); } .wy-side-nav-search .wy-dropdown > a:hover, .wy-side-nav-search > a:hover { background-image: initial; background-color: rgba(19, 21, 22, 0.1); } .wy-side-nav-search .wy-dropdown > a img.logo, .wy-side-nav-search > a img.logo { background-image: initial; background-color: transparent; } .wy-side-nav-search > div.version { color: rgba(216, 212, 207, 0.3); } .wy-nav .wy-menu-vertical header { color: rgb(94, 169, 219); } .wy-nav .wy-menu-vertical a { color: rgb(182, 176, 167); } .wy-nav .wy-menu-vertical a:hover { background-color: rgb(26, 82, 118); color: rgb(216, 212, 207); } .wy-body-for-nav { background-image: initial; background-color: rgb(21, 22, 23); } .wy-nav-side { color: rgb(172, 164, 154); background-image: initial; background-color: rgb(30, 33, 34); } .wy-nav-top { background-image: initial; background-color: rgb(26, 82, 118); color: rgb(216, 212, 207); } .wy-nav-top a { color: rgb(216, 212, 207); } .wy-nav-top img { background-color: rgb(26, 82, 118); } .wy-nav-content-wrap { background-image: initial; background-color: rgb(21, 22, 23); } .wy-body-mask { background-image: initial; background-color: rgba(0, 0, 0, 0.2); } footer { color: rgb(160, 151, 139); } .rst-content footer span.commit tt, footer span.commit .rst-content tt, footer span.commit code { background-image: none; background-color: initial; border-color: initial; color: rgb(160, 151, 139); } #search-results .search li { border-bottom-color: rgb(120, 112, 99); } #search-results .search li:first-child { border-top-color: rgb(120, 112, 99); } #search-results .context { color: rgb(160, 151, 139); } .wy-body-for-nav { background-image: initial; background-color: rgb(21, 22, 23); } @media screen and (min-width: 1100px) { .wy-nav-content-wrap { background-image: initial; background-color: rgba(0, 0, 0, 0.05); } .wy-nav-content { background-image: initial; background-color: rgb(21, 22, 23); } } .rst-versions { color: rgb(215, 211, 206); background-image: initial; background-color: rgb(18, 20, 20); } .rst-versions a { color: rgb(94, 169, 219); text-decoration-color: initial; } .rst-versions .rst-current-version { background-color: rgb(23, 25, 26); color: rgb(99, 220, 150); } .rst-content .code-block-caption .rst-versions .rst-current-version .headerlink, .rst-content .rst-versions .rst-current-version .admonition-title, .rst-content code.download .rst-versions .rst-current-version span:first-child, .rst-content dl dt .rst-versions .rst-current-version .headerlink, .rst-content h1 .rst-versions .rst-current-version .headerlink, .rst-content h2 .rst-versions .rst-current-version .headerlink, .rst-content h3 .rst-versions .rst-current-version .headerlink, .rst-content h4 .rst-versions .rst-current-version .headerlink, .rst-content h5 .rst-versions .rst-current-version .headerlink, .rst-content h6 .rst-versions .rst-current-version .headerlink, .rst-content p.caption .rst-versions .rst-current-version .headerlink, .rst-content table > caption .rst-versions .rst-current-version .headerlink, .rst-content tt.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .fa, .rst-versions .rst-current-version .icon, .rst-versions .rst-current-version .rst-content .admonition-title, .rst-versions .rst-current-version .rst-content .code-block-caption .headerlink, .rst-versions .rst-current-version .rst-content code.download span:first-child, .rst-versions .rst-current-version .rst-content dl dt .headerlink, .rst-versions .rst-current-version .rst-content h1 .headerlink, .rst-versions .rst-current-version .rst-content h2 .headerlink, .rst-versions .rst-current-version .rst-content h3 .headerlink, .rst-versions .rst-current-version .rst-content h4 .headerlink, .rst-versions .rst-current-version .rst-content h5 .headerlink, .rst-versions .rst-current-version .rst-content h6 .headerlink, .rst-versions .rst-current-version .rst-content p.caption .headerlink, .rst-versions .rst-current-version .rst-content table > caption .headerlink, .rst-versions .rst-current-version .rst-content tt.download span:first-child, .rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand { color: rgb(215, 211, 206); } .rst-versions .rst-current-version.rst-out-of-date { background-color: rgb(130, 26, 16); color: rgb(216, 212, 207); } .rst-versions .rst-current-version.rst-active-old-version { background-color: rgb(154, 125, 9); color: rgb(216, 212, 207); } .rst-versions .rst-other-versions { color: rgb(160, 151, 139); } .rst-versions .rst-other-versions hr { border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-top-color: rgb(104, 97, 86); } .rst-versions .rst-other-versions dd a { color: rgb(215, 211, 206); } .rst-versions.rst-badge { border-color: initial; } .rst-content abbr[title] { text-decoration-color: initial; } .rst-content.style-external-links a.reference.external::after { color: rgb(182, 176, 167); } .rst-content div[class^="highlight"], .rst-content pre.literal-block { border-color: rgb(120, 112, 99); } .rst-content div[class^="highlight"] div[class^="highlight"], .rst-content pre.literal-block div[class^="highlight"] { border-color: initial; } .rst-content .linenodiv pre { border-right-color: rgb(121, 112, 99); } .rst-content .admonition table { border-color: rgba(84, 91, 95, 0.1); } .rst-content .admonition table td, .rst-content .admonition table th { background-image: initial !important; background-color: transparent !important; border-color: rgba(84, 91, 95, 0.1) !important; } .rst-content .section ol.loweralpha, .rst-content .section ol.loweralpha > li { list-style-image: initial; } .rst-content .section ol.upperalpha, .rst-content .section ol.upperalpha > li { list-style-image: initial; } .rst-content .toc-backref { color: rgb(188, 182, 173); } .rst-content .sidebar { background-image: initial; background-color: rgb(22, 29, 29); border-color: rgb(120, 112, 99); } .rst-content .sidebar .sidebar-title { background-image: initial; background-color: rgb(32, 35, 36); } .rst-content .highlighted { background-image: initial; background-color: rgb(154, 125, 9); box-shadow: rgb(154, 125, 9) 0px 0px 0px 2px; } html.writer-html4 .rst-content table.docutils.citation, html.writer-html4 .rst-content table.docutils.footnote { background-image: none; background-color: initial; border-color: initial; } html.writer-html4 .rst-content table.docutils.citation td, html.writer-html4 .rst-content table.docutils.citation tr, html.writer-html4 .rst-content table.docutils.footnote td, html.writer-html4 .rst-content table.docutils.footnote tr { border-color: initial; background-color: transparent !important; } .rst-content table.docutils.footnote, html.writer-html4 .rst-content table.docutils.citation, html.writer-html5 .rst-content dl.footnote { color: rgb(160, 151, 139); } .rst-content table.docutils.footnote code, .rst-content table.docutils.footnote tt, html.writer-html4 .rst-content table.docutils.citation code, html.writer-html4 .rst-content table.docutils.citation tt, html.writer-html5 .rst-content dl.footnote code, html.writer-html5 .rst-content dl.footnote tt { color: rgb(178, 172, 162); } .rst-content table.docutils th { border-color: rgb(120, 112, 99); } html.writer-html5 .rst-content table.docutils th { border-color: rgb(120, 112, 99); } .rst-content table.field-list, .rst-content table.field-list td { border-color: initial; } .rst-content code, .rst-content tt { color: rgb(216, 212, 207); } .rst-content code.literal, .rst-content tt.literal { color: rgb(234, 96, 82); } .rst-content code.xref, .rst-content tt.xref, a .rst-content code, a .rst-content tt { color: rgb(188, 182, 173); } .rst-content a code, .rst-content a tt { color: rgb(94, 169, 219); } html.writer-html4 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt { background-image: initial; background-color: rgb(26, 28, 29); color: rgb(94, 169, 219); border-top-color: rgb(37, 119, 171); } html.writer-html4 .rst-content dl:not(.docutils) > dt::before, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt::before { color: rgb(111, 179, 223); } html.writer-html4 .rst-content dl:not(.docutils) > dt .headerlink, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt .headerlink { color: rgb(188, 182, 173); } html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { border-top-color: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: rgb(118, 110, 97); background-image: initial; background-color: rgb(26, 28, 29); color: rgb(178, 172, 162); } html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt .headerlink, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt .headerlink { color: rgb(188, 182, 173); } html.writer-html4 .rst-content dl:not(.docutils) code.descclassname, html.writer-html4 .rst-content dl:not(.docutils) code.descname, html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname, html.writer-html4 .rst-content dl:not(.docutils) tt.descname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname { background-color: transparent; border-color: initial; } html.writer-html4 .rst-content dl:not(.docutils) .optional, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional { color: rgb(216, 212, 207); } .rst-content .viewcode-back, .rst-content .viewcode-link { color: rgb(99, 220, 150); } .rst-content code.download, .rst-content tt.download { background-image: inherit; background-color: inherit; color: inherit; border-color: inherit; } .rst-content .guilabel { border-color: rgb(38, 119, 172); background-image: initial; background-color: rgb(26, 28, 29); } span[id*="MathJax-Span"] { color: rgb(188, 182, 173); } td.linenos .normal { color: inherit; background-color: transparent; } span.linenos { color: inherit; background-color: transparent; } td.linenos .special { color: rgb(216, 212, 207); background-color: rgb(71, 71, 0); } span.linenos.special { color: rgb(216, 212, 207); background-color: rgb(71, 71, 0); } .highlight .hll { background-color: rgb(66, 66, 0); } .highlight { background-image: initial; background-color: rgb(49, 66, 0); } .highlight .c { color: rgb(124, 182, 197); } .highlight .err { border-color: rgb(201, 0, 0); } .highlight .k { color: rgb(114, 255, 154); } .highlight .o { color: rgb(171, 164, 153); } .highlight .ch { color: rgb(124, 182, 197); } .highlight .cm { color: rgb(124, 182, 197); } .highlight .cp { color: rgb(114, 255, 154); } .highlight .cpf { color: rgb(124, 182, 197); } .highlight .c1 { color: rgb(124, 182, 197); } .highlight .cs { color: rgb(124, 182, 197); background-color: rgb(48, 0, 0); } .highlight .gd { color: rgb(255, 90, 90); } .highlight .gr { color: rgb(255, 44, 44); } .highlight .gh { color: rgb(114, 185, 255); } .highlight .gi { color: rgb(90, 255, 90); } .highlight .go { color: rgb(193, 188, 180); } .highlight .gp { color: rgb(246, 151, 75); } .highlight .gu { color: rgb(255, 105, 255); } .highlight .gt { color: rgb(75, 173, 255); } .highlight .kc { color: rgb(114, 255, 154); } .highlight .kd { color: rgb(114, 255, 154); } .highlight .kn { color: rgb(114, 255, 154); } .highlight .kp { color: rgb(114, 255, 154); } .highlight .kr { color: rgb(114, 255, 154); } .highlight .kt { color: rgb(255, 133, 98); } .highlight .m { color: rgb(123, 222, 173); } .highlight .s { color: rgb(126, 170, 203); } .highlight .na { color: rgb(126, 170, 203); } .highlight .nb { color: rgb(114, 255, 154); } .highlight .nc { color: rgb(86, 196, 242); } .highlight .no { color: rgb(108, 180, 216); } .highlight .nd { color: rgb(178, 172, 162); } .highlight .ni { color: rgb(220, 111, 85); } .highlight .ne { color: rgb(114, 255, 154); } .highlight .nf { color: rgb(120, 189, 248); } .highlight .nl { color: rgb(121, 194, 255); } .highlight .nn { color: rgb(86, 196, 242); } .highlight .nt { color: rgb(125, 192, 248); } .highlight .nv { color: rgb(192, 108, 216); } .highlight .ow { color: rgb(114, 255, 154); } .highlight .w { color: rgb(186, 180, 171); } .highlight .mb { color: rgb(123, 222, 173); } .highlight .mf { color: rgb(123, 222, 173); } .highlight .mh { color: rgb(123, 222, 173); } .highlight .mi { color: rgb(123, 222, 173); } .highlight .mo { color: rgb(123, 222, 173); } .highlight .sa { color: rgb(126, 170, 203); } .highlight .sb { color: rgb(126, 170, 203); } .highlight .sc { color: rgb(126, 170, 203); } .highlight .dl { color: rgb(126, 170, 203); } .highlight .sd { color: rgb(126, 170, 203); } .highlight .s2 { color: rgb(126, 170, 203); } .highlight .se { color: rgb(126, 170, 203); } .highlight .sh { color: rgb(126, 170, 203); } .highlight .si { color: rgb(120, 172, 210); } .highlight .sx { color: rgb(246, 151, 75); } .highlight .sr { color: rgb(129, 182, 223); } .highlight .s1 { color: rgb(126, 170, 203); } .highlight .ss { color: rgb(186, 229, 123); } .highlight .bp { color: rgb(114, 255, 154); } .highlight .fm { color: rgb(120, 189, 248); } .highlight .vc { color: rgb(192, 108, 216); } .highlight .vg { color: rgb(192, 108, 216); } .highlight .vi { color: rgb(192, 108, 216); } .highlight .vm { color: rgb(192, 108, 216); } .highlight .il { color: rgb(123, 222, 173); } [role="tablist"] { border-bottom-color: rgb(115, 107, 95); } .sphinx-tabs-tab { color: rgb(118, 181, 226); background-color: rgba(19, 21, 22, 0); border-color: initial; } .sphinx-tabs-tab[aria-selected="true"] { border-color: rgb(115, 107, 95) rgb(115, 107, 95) rgb(123, 114, 101); background-color: rgb(19, 21, 22); } .sphinx-tabs-panel { border-right-color: rgb(115, 107, 95); border-bottom-color: rgb(115, 107, 95); border-left-color: rgb(115, 107, 95); border-top-color: initial; background-image: initial; background-color: rgb(19, 21, 22); } .rst-other-versions a { border-color: initial; } .ethical-sidebar .ethical-image-link, .ethical-footer .ethical-image-link { border-color: initial; } .ethical-sidebar, .ethical-footer { background-color: rgb(27, 29, 30); border-color: rgb(118, 110, 97); color: rgb(211, 208, 202); } .ethical-sidebar ul { list-style-image: initial; } .ethical-sidebar ul li { background-color: rgb(4, 62, 97); color: rgb(216, 212, 207); } .ethical-sidebar a, .ethical-sidebar a:visited, .ethical-sidebar a:hover, .ethical-sidebar a:active, .ethical-footer a, .ethical-footer a:visited, .ethical-footer a:hover, .ethical-footer a:active { color: rgb(211, 208, 202); text-decoration-color: initial !important; border-bottom-color: initial !important; } .ethical-callout a { color: rgb(166, 159, 147) !important; text-decoration-color: initial !important; } .ethical-fixedfooter { background-color: rgb(27, 29, 30); border-top-color: rgb(117, 109, 96); color: rgb(188, 182, 173); } .ethical-fixedfooter .ethical-text::before { background-color: rgb(49, 112, 51); color: rgb(216, 212, 207); } .ethical-fixedfooter .ethical-callout { color: rgb(171, 164, 153); } .ethical-fixedfooter a, .ethical-fixedfooter a:hover, .ethical-fixedfooter a:active, .ethical-fixedfooter a:visited { color: rgb(188, 182, 173); text-decoration-color: initial; } .ethical-rtd .ethical-sidebar { color: rgb(182, 176, 167); } .ethical-alabaster a.ethical-image-link { border-color: initial !important; } .ethical-dark-theme .ethical-sidebar { background-color: rgb(46, 50, 52); border-color: rgb(114, 106, 93); color: rgb(189, 183, 174) !important; } .ethical-dark-theme a, .ethical-dark-theme a:visited { color: rgb(205, 200, 194) !important; border-bottom-color: initial !important; } .ethical-dark-theme .ethical-callout a { color: rgb(182, 176, 167) !important; } .keep-us-sustainable { border-color: rgb(104, 158, 45); } .keep-us-sustainable a, .keep-us-sustainable a:hover, .keep-us-sustainable a:visited { text-decoration-color: initial; } .wy-nav-side .keep-us-sustainable { color: rgb(182, 176, 167); } .wy-nav-side .keep-us-sustainable a { color: rgb(209, 205, 199); } [data-ea-publisher].loaded a, [data-ea-type].loaded a { text-decoration-color: initial; } [data-ea-publisher].loaded .ea-content, [data-ea-type].loaded .ea-content { background-image: initial; background-color: rgba(0, 0, 0, 0.03); color: rgb(181, 174, 164); } [data-ea-publisher].loaded .ea-content a:link, [data-ea-type].loaded .ea-content a:link { color: rgb(181, 174, 164); } [data-ea-publisher].loaded .ea-content a:visited, [data-ea-type].loaded .ea-content a:visited { color: rgb(181, 174, 164); } [data-ea-publisher].loaded .ea-content a:hover, [data-ea-type].loaded .ea-content a:hover { color: rgb(192, 186, 178); } [data-ea-publisher].loaded .ea-content a:active, [data-ea-type].loaded .ea-content a:active { color: rgb(192, 186, 178); } [data-ea-publisher].loaded .ea-content a strong, [data-ea-publisher].loaded .ea-content a b, [data-ea-type].loaded .ea-content a strong, [data-ea-type].loaded .ea-content a b { color: rgb(64, 180, 248); } [data-ea-publisher].loaded .ea-callout a:link, [data-ea-type].loaded .ea-callout a:link { color: rgb(169, 162, 151); } [data-ea-publisher].loaded .ea-callout a:visited, [data-ea-type].loaded .ea-callout a:visited { color: rgb(169, 162, 151); } [data-ea-publisher].loaded .ea-callout a:hover, [data-ea-type].loaded .ea-callout a:hover { color: rgb(181, 174, 164); } [data-ea-publisher].loaded .ea-callout a:active, [data-ea-type].loaded .ea-callout a:active { color: rgb(181, 174, 164); } [data-ea-publisher].loaded .ea-callout a strong, [data-ea-publisher].loaded .ea-callout a b, [data-ea-type].loaded .ea-callout a strong, [data-ea-type].loaded .ea-callout a b { color: rgb(64, 180, 248); } [data-ea-publisher].loaded.dark .ea-content, [data-ea-type].loaded.dark .ea-content { background-image: initial; background-color: rgba(19, 21, 22, 0.05); color: rgb(200, 196, 189); } [data-ea-publisher].loaded.dark .ea-content a:link, [data-ea-type].loaded.dark .ea-content a:link { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.dark .ea-content a:visited, [data-ea-type].loaded.dark .ea-content a:visited { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.dark .ea-content a:hover, [data-ea-type].loaded.dark .ea-content a:hover { color: rgb(212, 208, 202); } [data-ea-publisher].loaded.dark .ea-content a:active, [data-ea-type].loaded.dark .ea-content a:active { color: rgb(212, 208, 202); } [data-ea-publisher].loaded.dark .ea-content a strong, [data-ea-publisher].loaded.dark .ea-content a b, [data-ea-type].loaded.dark .ea-content a strong, [data-ea-type].loaded.dark .ea-content a b { color: rgb(85, 188, 249); } [data-ea-publisher].loaded.dark .ea-callout a:link, [data-ea-type].loaded.dark .ea-callout a:link { color: rgb(189, 184, 175); } [data-ea-publisher].loaded.dark .ea-callout a:visited, [data-ea-type].loaded.dark .ea-callout a:visited { color: rgb(189, 184, 175); } [data-ea-publisher].loaded.dark .ea-callout a:hover, [data-ea-type].loaded.dark .ea-callout a:hover { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.dark .ea-callout a:active, [data-ea-type].loaded.dark .ea-callout a:active { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.dark .ea-callout a strong, [data-ea-publisher].loaded.dark .ea-callout a b, [data-ea-type].loaded.dark .ea-callout a strong, [data-ea-type].loaded.dark .ea-callout a b { color: rgb(85, 188, 249); } @media (prefers-color-scheme: dark) { [data-ea-publisher].loaded.adaptive .ea-content, [data-ea-type].loaded.adaptive .ea-content { background-image: initial; background-color: rgba(19, 21, 22, 0.05); color: rgb(200, 196, 189); } [data-ea-publisher].loaded.adaptive .ea-content a:link, [data-ea-type].loaded.adaptive .ea-content a:link { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.adaptive .ea-content a:visited, [data-ea-type].loaded.adaptive .ea-content a:visited { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.adaptive .ea-content a:hover, [data-ea-type].loaded.adaptive .ea-content a:hover { color: rgb(212, 208, 202); } [data-ea-publisher].loaded.adaptive .ea-content a:active, [data-ea-type].loaded.adaptive .ea-content a:active { color: rgb(212, 208, 202); } [data-ea-publisher].loaded.adaptive .ea-content a strong, [data-ea-publisher].loaded.adaptive .ea-content a b, [data-ea-type].loaded.adaptive .ea-content a strong, [data-ea-type].loaded.adaptive .ea-content a b { color: rgb(85, 188, 249); } [data-ea-publisher].loaded.adaptive .ea-callout a:link, [data-ea-type].loaded.adaptive .ea-callout a:link { color: rgb(189, 184, 175); } [data-ea-publisher].loaded.adaptive .ea-callout a:visited, [data-ea-type].loaded.adaptive .ea-callout a:visited { color: rgb(189, 184, 175); } [data-ea-publisher].loaded.adaptive .ea-callout a:hover, [data-ea-type].loaded.adaptive .ea-callout a:hover { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.adaptive .ea-callout a:active, [data-ea-type].loaded.adaptive .ea-callout a:active { color: rgb(200, 196, 189); } [data-ea-publisher].loaded.adaptive .ea-callout a strong, [data-ea-publisher].loaded.adaptive .ea-callout a b, [data-ea-type].loaded.adaptive .ea-callout a strong, [data-ea-type].loaded.adaptive .ea-callout a b { color: rgb(85, 188, 249); } } [data-ea-publisher].loaded .ea-content, [data-ea-type].loaded .ea-content { border-color: initial; box-shadow: rgba(0, 0, 0, 0.15) 0px 2px 3px; } [data-ea-publisher].loaded.raised .ea-content, [data-ea-type].loaded.raised .ea-content { border-color: initial; box-shadow: rgba(0, 0, 0, 0.15) 0px 2px 3px; } [data-ea-publisher].loaded.bordered .ea-content, [data-ea-type].loaded.bordered .ea-content { border-color: rgba(84, 91, 95, 0.04); box-shadow: none; } [data-ea-publisher].loaded.bordered.dark .ea-content, [data-ea-type].loaded.bordered.dark .ea-content { border-color: rgba(123, 114, 101, 0.07); } @media (prefers-color-scheme: dark) { [data-ea-publisher].loaded.bordered.adaptive .ea-content, [data-ea-type].loaded.bordered.adaptive .ea-content { border-color: rgba(123, 114, 101, 0.07); } } [data-ea-publisher].loaded.flat .ea-content, [data-ea-type].loaded.flat .ea-content { border-color: initial; box-shadow: none; } .vimvixen-hint { background-color: rgb(98, 66, 0) !important; border-color: rgb(170, 138, 15) !important; color: rgb(237, 221, 175) !important; } #edge-translate-panel-body { color: var(--darkreader-text--darkreader-neutral-text) !important; } } @media (prefers-color-scheme: light) { .wy-menu-vertical li.toctree-l2.current a, .wy-menu-vertical li.toctree-l3.current a { background-color: rgb(54, 59, 61); } } .rst-other-versions a { border-color: initial; } .ethical-sidebar .ethical-image-link, .ethical-footer .ethical-image-link { border-color: initial; } .ethical-sidebar, .ethical-footer { background-color: rgb(34, 36, 38); border-color: rgb(62, 68, 70); color: rgb(226, 223, 219); } .ethical-sidebar ul { list-style-image: initial; } .ethical-sidebar ul li { background-color: rgb(5, 77, 121); color: rgb(232, 230, 227); } .ethical-sidebar a, .ethical-sidebar a:visited, .ethical-sidebar a:hover, .ethical-sidebar a:active, .ethical-footer a, .ethical-footer a:visited, .ethical-footer a:hover, .ethical-footer a:active { color: rgb(226, 223, 219); text-decoration-color: initial !important; border-bottom-color: initial !important; } .ethical-callout a { color: rgb(161, 153, 141) !important; text-decoration-color: initial !important; } .ethical-fixedfooter { background-color: rgb(34, 36, 38); border-top-color: rgb(66, 72, 74); color: rgb(192, 186, 178); } .ethical-fixedfooter .ethical-text::before { background-color: rgb(61, 140, 64); color: rgb(232, 230, 227); } .ethical-fixedfooter .ethical-callout { color: rgb(168, 160, 149); } .ethical-fixedfooter a, .ethical-fixedfooter a:hover, .ethical-fixedfooter a:active, .ethical-fixedfooter a:visited { color: rgb(192, 186, 178); text-decoration-color: initial; } .ethical-rtd .ethical-sidebar { color: rgb(184, 178, 169); } .ethical-alabaster a.ethical-image-link { border-color: initial !important; } .ethical-dark-theme .ethical-sidebar { background-color: rgb(58, 62, 65); border-color: rgb(75, 81, 84); color: rgb(193, 188, 180) !important; } .ethical-dark-theme a, .ethical-dark-theme a:visited { color: rgb(216, 213, 208) !important; border-bottom-color: initial !important; } .ethical-dark-theme .ethical-callout a { color: rgb(184, 178, 169) !important; } .keep-us-sustainable { border-color: rgb(87, 133, 38); } .keep-us-sustainable a, .keep-us-sustainable a:hover, .keep-us-sustainable a:visited { text-decoration-color: initial; } .wy-nav-side .keep-us-sustainable { color: rgb(184, 178, 169); } .wy-nav-side .keep-us-sustainable a { color: rgb(222, 219, 215); } /* Override Style */ .vimvixen-hint { background-color: #7b5300 !important; border-color: #d8b013 !important; color: #f3e8c8 !important; } ::placeholder { opacity: 0.5 !important; } a[href="https://coinmarketcap.com/"] > svg[width="94"][height="16"] > path { fill: var(--darkreader-neutral-text) !important; } #edge-translate-panel-body, .MuiTypography-body1 { color: var(--darkreader-neutral-text) !important; } gr-main-header { background-color: #0f3a48 !important; } embed[type="application/pdf"] { filter: invert(100%) contrast(90%); } } nsd-4.12.0/doc/manual/requirements.txt0000644000175000017500000000026215002373054017303 0ustar mozziemozzieSphinx==8.1.3 sphinx-version-warning==1.1.2 sphinx-tabs==3.4.7 sphinx-copybutton==0.5.2 sphinx-rtd-theme sphinx-notfound-page requests sphinx-substitution-extensions==2024.10.17 nsd-4.12.0/doc/manual/reference/0000755000175000017500000000000015002373054015755 5ustar mozziemozziensd-4.12.0/doc/manual/reference/rfc-compliance.rst0000644000175000017500000001416415002373054021377 0ustar mozziemozzieRFC Compliance ============== NSD strives to be a reference implementation for emerging standards in the Internet Engineering Task Force (IETF). The aim is to implement well-established Internet Drafts as a compile option and drafts in the final stage of open community review as an optional feature, that is disabled by default. Accepted RFCs are implemented in NSD according to the described standard. The following table provides an extensive overview of all the RFC standards and Internet drafts that have been implemented in NSD. ============== ==== :rfc:`1034` Domain Names – Concepts and Facilities :rfc:`1035` Domain Names – Implementation and Specification :rfc:`1101` DNS Encoding of Network Names and Other Types :rfc:`1521` MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies :rfc:`1706` DNS NSAP Resource Records :rfc:`1712` DNS Encoding of Geographical Location :rfc:`1876` A Means for Expressing Location Information in the Domain Name System :rfc:`1982` Serial Number Arithmetic :rfc:`1995` Incremental Zone Transfer in DNS :rfc:`1996` A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY) :rfc:`2163` Using the Internet DNS to Distribute MIXER Conformant Global Address Mapping (MCGAM) :rfc:`2168` Resolution of Uniform Resource Identifiers using the Domain Name System :rfc:`2181` Clarifications to the DNS Specification :rfc:`2230` Key Exchange Delegation Record for the DNS :rfc:`2253` Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names :rfc:`2308` Negative Caching of DNS Queries (DNS NCACHE) :rfc:`2535` Domain Name System Security Extensions :rfc:`2536` DSA KEYs and SIGs in the Domain Name System (DNS) :rfc:`2537` RSA/MD5 KEYs and SIGs in the Domain Name System (DNS) :rfc:`2538` Storing Certificates in the Domain Name System (DNS) :rfc:`2539` Storage of Diffie-Hellman Keys in the Domain Name System (DNS) :rfc:`2606` Reserved Top Level DNS Names :rfc:`2671` Extension Mechanisms for DNS (EDNS0) :rfc:`2672` Non-Terminal DNS Name Redirection :rfc:`2673` Binary Labels in the Domain Name System :rfc:`2782` A DNS RR for specifying the location of services (DNS SRV) :rfc:`2845` Secret Key Transaction Authentication for DNS (TSIG) :rfc:`2874` DNS Extensions to Support IPv6 Address Aggregation and Renumbering :rfc:`2915` The Naming Authority Pointer (NAPTR) DNS Resource Record :rfc:`2930` Secret Key Establishment for DNS (TKEY RR) :rfc:`3110` RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS) :rfc:`3123` A DNS RR Type for Lists of Address Prefixes (APL RR) :rfc:`3225` Indicating Resolver Support of DNSSEC :rfc:`3597` Handling of Unknown DNS Resource Record (RR) Types :rfc:`3755` Legacy Resolver Compatibility for Delegation Signer (DS) :rfc:`4025` A Method for Storing IPsec Keying Material in DNS :rfc:`4033` DNS Security Introduction and Requirements :rfc:`4034` Resource Records for the DNS Security Extensions :rfc:`4035` Protocol Modifications for the DNS Security Extensions :rfc:`4255` Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints :rfc:`4343` Domain Name System (DNS) Case Insensitivity Clarification :rfc:`4398` Storing Certificates in the Domain Name System (DNS) :rfc:`4431` The DNSSEC Lookaside Validation (DLV) DNS Resource Record :rfc:`4509` Use of SHA-256 in DNSSEC Delegation Signer (DS) Resource Records (RRs) :rfc:`4592` The Role of Wildcards in the Domain Name System :rfc:`4597` Conferencing Scenarios :rfc:`4635` HMAC SHA TSIG Algorithm Identifiers :rfc:`4701` A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol (DHCP) Information (DHCID RR) :rfc:`4892` Requirements for a Mechanism Identifying a Name Server Instance :rfc:`5001` DNS Name Server Identifier (NSID) Option :rfc:`5114` Additional Diffie-Hellman Groups for Use with IETF Standards :rfc:`5155` DNS Security (DNSSEC) Hashed Authenticated Denial of Existence :rfc:`5205` Host Identity Protocol (HIP) Domain Name System (DNS) Extension :rfc:`5702` Use of SHA-2 Algorithms with RSA in DNSKEY and RRSIG Resource Records for DNSSEC :rfc:`5933` Use of GOST Signature Algorithms in DNSKEY and RRSIG Resource Records for DNSSEC :rfc:`5936` DNS Zone Transfer Protocol (AXFR) :rfc:`6604` xNAME RCODE and Status Bits Clarification :rfc:`6605` Elliptic Curve Digital Signature Algorithm (DSA) for DNSSEC :rfc:`6672` DNAME Redirection in the DNS :rfc:`6698` The DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS) Protocol: TLSA :rfc:`6725` DNS Security (DNSSEC) DNSKEY Algorithm IANA Registry Updates :rfc:`6742` DNS Resource Records for the Identifier-Locator Network Protocol (ILNP) :rfc:`6761` Special-Use Domain Names :rfc:`6840` Clarifications and Implementation Notes for DNS Security (DNSSEC) :rfc:`6844` DNS Certification Authority Authorization (CAA) Resource Record :rfc:`6891` Extension Mechanisms for DNS (EDNS(0)) :rfc:`6895` Domain Name System (DNS) IANA Considerations :rfc:`7043` Resource Records for EUI-48 and EUI-64 Addresses in the DNS :rfc:`7344` Automating DNSSEC Delegation Trust Maintenance :rfc:`7477` Child-to-Parent Synchronization in DNS :rfc:`7553` The Uniform Resource Identifier (URI) DNS Resource Record :rfc:`7766` DNS Transport over TCP - Implementation Requirements :rfc:`7873` Domain Name System (DNS) Cookies :rfc:`7929` DNS-Based Authentication of Named Entities (DANE) Bindings for OpenPGP :rfc:`8080` Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC :rfc:`8162` Using Secure DNS to Associate Certificates with Domain Names for S/MIME :rfc:`8482` Providing Minimal-Sized Responses to DNS Queries That Have QTYPE=ANY :rfc:`8914` Extended DNS Errors :rfc:`8945` Secret Key Transaction Authentication for DNS (TSIG) :rfc:`9018` Interoperable Domain Name System (DNS) Server Cookies :rfc:`9103` DNS Zone Transfer over TLS :rfc:`9210` DNS Transport over TCP - Operational Requirements :rfc:`9432` DNS Catalog Zones ============== ==== nsd-4.12.0/doc/manual/reference/log-diagnosis.rst0000644000175000017500000000367215002373054021256 0ustar mozziemozzieDiagnosing NSD Log Entries ========================== NSD will print log messages to the system log (or ``logfile:`` configuration entry). Some of these messages are covered here. Reload process failed with status , continuing with old database This log message indicates the reload process of NSD has failed for some reason. This can be anything from a missing database file to internal errors. snipping off trailing partial part of The file :file:`ixfr.db` contains only part of expected data. The corruption is removed by snipping off the trailing part. memory recyclebin holds bytes This is printed for every reload. NSD allocates and deallocates memory to service IXFR updates. The recycle bin holds deallocated memory ready for future use. If the number grows too large, a restart resets it. xfrd: max number of tcp connections (32) reached This line is printed when more than 32 zones need a zone transfer at the same time. The value is a compile constant (``xfrd-tcp.h``), but if this happens often for you, we could make this a config option. NSD will reuse existing TCP connections to the same primary (determined by IP address) to transfer up to 64k zones from that primary. Thus this error should only happen with more than 32 primaries or more than 64\*32=2M zones that need to be updated at the same time. If this happens, more zones have to wait until a zone transfer completes (or is aborted) before they can have a zone transfer too. This waiting list has no size limit. error: NSEC3PARAM entry has unknown hash algo This error means that the zone has NSEC3 chain(s) with hash algorithms that are not supported by this version of NSD, and thus cannot be served by NSD. If there are also no NSECs or NSEC3 chain(s) with known hash algorithms, NSD will not be able to serve DNSSEC authenticated denials for the zone. nsd-4.12.0/doc/manual/reference/configure-options.rst0000644000175000017500000000617315002373054022170 0ustar mozziemozzieConfigure Options ================= NSD can be configured using GNU autoconf's configure script. In addition to standard configure options, one may use the following: CC=compiler Specify the C compiler. The default is gcc or cc. The compiler must support ANSI C89. CPPFLAGS=flags Specify the C preprocessor flags. Such as ``-I``. CFLAGS=flags Specify the C compiler flags. These include code generation, optimisation, warning, and debugging flags. These flags are also passed to the linker. The default for gcc is ``-g -O2``. LD=linker Specify the linker (defaults to the C compiler). LDFLAGS=flags Specify linker flags. LIBS=libs Specify additional libraries to link with. --enable-root-server Configure NSD as a root server. Unless this option is specified, NSD will refuse to serve the ``.`` zone as a misconfiguration safeguard. --disable-ipv6 Disables IPv6 support in NSD. --enable-checking Enable some internal development checks. Useful if you want to modify NSD. This option enables the standard C "assert" macro and compiler warnings. This will instruct NSD to be stricter when validating its input. This could lead to a reduced service level. --enable-bind8-stats Enables BIND8-like statistics. --enable-ratelimit Enables rate limiting, based on query name, type and source. --enable-draft-rrtypes Enables draft RRtypes. --with-configdir=dir Specified, NSD configuration directory, default :file:`/etc/nsd`. --with-nsd_conf_file=path Pathname to the NSD configuration file, default :file:`/etc/nsd/nsd.conf`. --with-pidfile=path Pathname to the NSD pidfile, default is platform specific, mostly :file:`/var/run/nsd.pid`. --with-zonesdir=dir NSD default location for master zone files, default :file:`/etc/nsd/`. --with-user=username User name or ID to answer the queries with, default is ``nsd``. --with-facility=facility Specify the syslog facility to use. The default is LOG_DAEMON. See the syslog(3) manual page for the available facilities. --with-libevent=path Specity the location of the ``libevent`` library (or libev). ``--with-libevent=no`` uses a builtin portable implementation (select()). --with-ssl=path Specify the location of the OpenSSL libraries. OpenSSL 0.9.7 or higher is required for TSIG support. --with-start_priority=number Startup priority for NSD. --with-kill_priority=number Shutdown priority for NSD. --with-tcp-timeout=number Set the default TCP timeout (in seconds). The default is 120 seconds. --disable-nsec3 Disable NSEC3 support. With NSEC3 support enabled, very large zones, also non-NSEC3 zones, use about 20% more memory. --disable-minimal-responses Disable minimal responses. If disabled, responses are more likely to get truncated, resulting in TCP fallback. When enabled (by default) NSD will leave out RRsets to make responses fit inside one datagram, but for shorter responses the full normal response is carried. --disable-largefile Disable large file support (64 bit file lengths). Makes off_t a 32bit length during compilation. nsd-4.12.0/doc/manual/manpages/0000755000175000017500000000000015002373054015612 5ustar mozziemozziensd-4.12.0/doc/manual/manpages/nsd.rst0000644000175000017500000000006215002373054017126 0ustar mozziemozziensd(8) ====== .. raw:: html :file: nsd.8.html nsd-4.12.0/doc/manual/manpages/nsd.conf.rst0000644000175000017500000000010115002373054020044 0ustar mozziemozziensd.conf(5) =========== .. raw:: html :file: nsd.conf.5.html nsd-4.12.0/doc/manual/manpages/nsd-control.rst0000644000175000017500000000011215002373054020600 0ustar mozziemozziensd-control(8) ============== .. raw:: html :file: nsd-control.8.html nsd-4.12.0/doc/manual/manpages/nsd-checkzone.rst0000644000175000017500000000012015002373054021070 0ustar mozziemozziensd-checkzone(8) ================ .. raw:: html :file: nsd-checkzone.8.html nsd-4.12.0/doc/manual/manpages/nsd-checkconf.rst0000644000175000017500000000012015002373054021042 0ustar mozziemozziensd-checkconf(8) ================ .. raw:: html :file: nsd-checkconf.8.html nsd-4.12.0/doc/manual/installation.rst0000644000175000017500000000742715002373054017264 0ustar mozziemozzieInstallation ------------ To install your own copy of NSD you have two options: use the version provided by your package manager, or download the source and building it yourself. Installing via the `package manager `_ is the easiest option, and on most systems even trivial. The downside is the distributed version can be outdated for some distributions or not have all the compile-time options included that you want. Building and compiling NSD yourself ensures that you have the latest version and all the compile-time options you desire. Introduction ============ NSD can be controlled via ``rc.d`` (SIGTERM, SIGHUP) or :program:`nsd-control`, and uses a simple configuration file ``nsd.conf``. Installing with a package manager ================================= Most distributions maintain a version of NSD, although this version can be outdated if this package has not been updated recently. If you like to upgrade to the latest version, we recommend compiling NSD yourself. Debian/Ubuntu ************* Installing NSD with the built-in package manager should be as easy as: .. code-block:: bash sudo apt update sudo apt install nsd This gives you a compiled and running version of NSD ready to :doc:`be configured`. Building from source ==================== Ubuntu ****** First of all, we need our copy of the NSD code. `On our website `_ you can find the latest version and the changelog. In this example we'll use version |version|. Please note that this may not be the latest version currently. .. code-block:: bash :substitutions: wget https://nlnetlabs.nl/downloads/nsd/nsd-|version|.tar.gz tar xzf nsd-|version|.tar.gz We'll need some tools, such as a compiler and the :command:`make` program. .. code-block:: bash sudo apt update sudo apt install -y build-essential The library components NSD needs are: ``libssl`` and ``libevent``, of which we need the "dev" version. .. code-block:: bash sudo apt install -y libssl-dev sudo apt install -y libevent-dev We'll also need the tools to build the actual program. For this, NSD uses :command:`make` and internally it uses ``flex`` and ``yacc``, which we need to download as well. .. code-block:: bash sudo apt install -y bison sudo apt install -y flex With all the requirements met, we can now start the compilation process in the NSD directory. The first step here is configuring. With :command:`./configure -h` you can look at the extensive list of configurables for NSD. A nice feature is that :command:`configure` will tell you what it's missing during configuration. .. code-block:: bash ./configure If :command:`configure` gives no errors, we can continue to actually try compiling NSD using :command:`make`; compilation might take a while. .. code-block:: bash make -j4 After successfully compiling, we can install NSD to make it available for the machine. .. code-block:: bash sudo make install We now have fully compiled and installed version of NSD, and can continue to testing it. Testing ======= A simple test to determine if the installation was successful is to invoke the :command:`nsd` command with the :option:`-V` option, which is the "version" option. This shows the version and build options used and proves installation was successful. .. code-block:: bash nsd -v If all the previous steps were successful we can continue to configuring our NSD instance. Another handy trick you can use during testing is to run NSD in the foreground using the :option:`-d` option and increase the verbosity level using the :option:`-V` option. This allows you to see steps NSD takes and also where it fails. Now that NSD is installed we can :doc:`continue to configuring it`. nsd-4.12.0/doc/manual/index.rst0000644000175000017500000000434515002373054015666 0ustar mozziemozzieName Server Daemon (NSD) by NLnet Labs ====================================== Welcome to the documentation of the NLnet Labs Name Server Daemon (NSD), an authoritative DNS name server. It has been developed for operations in environments where speed, reliability, stability and security are of high importance. NSD is designed with a pure philosophy that prioritises raw performance. This means that if you serve hundreds of thousands or even millions of queries per second, NSD is the leading implementation in the world. This authoritative DNS name server strives to be a reference implementation for emerging standards of the Internet Engineering Task Force (IETF). NSD is distributed free of charge in open source form under the BSD license. For most platforms, `packages `_ are available. This documentation is an open source project maintained by NLnet Labs. is edited via text files in the `reStructuredText `_ markup language and then compiled into a static website/offline document using the open source `Sphinx `_ and `ReadTheDocs `_ tools. We always appreciate your feedback and improvements. You can submit an issue or pull request on the `GitHub repository `_, or post a message on the `NSD users `_ mailing list. All the contents are under the permissive Creative Commons Attribution 3.0 (`CC-BY 3.0 `_) license, with attribution to NLnet Labs. .. toctree:: :maxdepth: 2 :caption: Getting Started installation configuration zonefile catalog-zones .. toctree:: :maxdepth: 2 :caption: Running running/logging running/using-tsig running/zone-expiry running/interfaces running/tuning .. toctree:: :maxdepth: 1 :caption: Manual Pages manpages/nsd manpages/nsd-checkconf manpages/nsd-checkzone manpages/nsd.conf manpages/nsd-control .. toctree:: :maxdepth: 2 :caption: Reference reference/configure-options reference/log-diagnosis reference/rfc-compliance .. history .. authors .. license nsd-4.12.0/doc/manual/configuration.rst0000644000175000017500000002671215002373054017430 0ustar mozziemozzieConfiguration ============= NSD has a vast array of configuration options for advanced use cases. To configure the application, a ``nsd.conf`` configuration file used. The file format has attributes and values, and some attributes have attributes inside them. .. Note:: The instructions in this page assume that NSD is already installed. The configuration file ---------------------- The configuration NSD uses is specified in the configuration file, which can be supplied to NSD using the :option:`-c` option. In the :doc:`reference` an example ``nsd.conf`` can be found as well as the complete documentation of all the configurable options. The same example and reference can be found on your system using the ``man nsd.conf`` command. The basic rules are of the config file are: - The used notation is ``attribute: value`` - Comments start with ``#`` and extend to the end of a line - Empty lines are ignored, as is whitespace at the beginning of a line - Quotes can be used, for names containing spaces, e.g. ``"file name.zone"`` Below we'll give an example config file, which specifies options for the NSD server, zone files, primaries and secondaries. This provide basic config which can be used for as a starting point. Note that for the remainder we assume the default location of NSD is ``/etc/nsd`` though this may vary on your system. The example configuration below specifies options for the NSD server, zone files, primaries and secondaries. Here is an example config for ``example.com``: .. code:: bash server: # use this number of cpu cores server-count: 1 # the default file used for the nsd-control addzone and delzone commands # zonelistfile: "/var/db/nsd/zone.list" # The unprivileged user that will run NSD, can also be set to "" if # user privilige protection is not needed username: nsd # Default file where all the log messages go logfile: "/var/log/nsd.log" # Use this pid file instead of the platform specific default pidfile: "/var/run/nsd.pid" # Enable if privilege "jail" is needed for unprivileged user. Note # that other file paths may break when using chroot # chroot: "/etc/nsd/" # The default zone transfer file # xfrdfile: "/var/db/nsd/xfrd.state" # The default working directory before accessing zone files # zonesdir: "/etc/nsd" remote-control: # this allows the use of 'nsd-control' to control NSD. The default is "no" control-enable: yes # the interface NSD listens to for nsd-control. The default is 127.0.0.1 and ::1 control-interface: 127.0.0.1 # the key files that allow the use of 'nsd-control'. The default path is "/etc/nsd/". Create these using the 'nsd-control-setup' utility server-key-file: /etc/nsd/nsd_server.key server-cert-file: /etc/nsd/nsd_server.pem control-key-file: /etc/nsd/nsd_control.key control-cert-file: /etc/nsd/nsd_control.pem zone: name: example.com zonefile: /etc/nsd/example.com.zone We recommend keeping the ``server-count`` lower or equal to the number of CPU cores your system has. Optionally, you can control NSD (from the same or even a different device) by using the entries under the `remote-control` clause in the config. Using this tool, NSD can be controlled (find the reference of all the options :doc:`here`) which makes controlling NSD much easier. If your install does not come with the keys needed for remote-control use pre-made, you can generate the keys using the :command:`nsd-control-setup` command, which will create them for you. In the section below we will go into more detail about this option. You can test the config with :command:`nsd-checkconf`. This tool will tell you what is wrong with the config and where the error occurs. If you are happy with the config and any modifications you may have done, you can create the zone to go with the file we mentioned in the config. We show an example zone at :doc:`the zonefile example`. Setting up a secondary zone --------------------------- If your needs go further than just a few zones that are managed locally, NSD has got you covered. We won't go into the theoretical details of primaries and secondaries here (we recommend `this blog `_), but we will show how to configure it. The example for a secondary looks like this: .. code:: bash zone: # this server is the primary, 192.0.2.1 is the secondary. name: primaryzone.com zonefile: /etc/nsd/primaryzone.com.zone notify: 192.0.2.1 NOKEY # NOKEY for testing purposes only provide-xfr: 192.0.2.1 NOKEY # NOKEY for testing purposes only zone: # this server is secondary, 192.0.2.2 is primary. name: secondaryzone.com zonefile: /etc/nsd/secondaryzone.com.zone allow-notify: 192.0.2.2 NOKEY # NOKEY for testing purposes only request-xfr: 192.0.2.2 NOKEY # NOKEY for testing purposes only .. note:: Note that the ``NOKEY`` keyword above are for testing purposes only, as this can introduce vulnerabilities when used in production environments. For a secondary zone we list the primaries by IP address. Below is an example of a secondary zone with two primary servers. If a primary only supports AXFR transfers and not IXFR transfers (like NSD), specify the primary as ``request-xfr: AXFR ``. By default, all zone transfer requests are made over TCP. If you want the IXFR request be transmitted over UDP, use ``request-xfr: UDP ``. .. code-block:: text zone: name: "example.com" zonefile: "example.com.zone" allow-notify: 168.192.185.33 NOKEY request-xfr: 168.192.185.33 NOKEY allow-notify: 168.192.199.2 NOKEY request-xfr: 168.192.199.2 NOKEY By default, a secondary will fallback to AXFR requests if the primary told us it does not support IXFR. You can configure the secondary not to do AXFR fallback with: .. code-block:: text allow-axfr-fallback: "no" For a primary zone, list the secondary servers, by IP address or subnet. Below is an example of a primary zone with two secondary servers: .. code-block:: text zone: name: "example.com" zonefile: "example.com.zone" notify: 168.192.133.75 NOKEY provide-xfr: 168.192.133.75 NOKEY notify: 168.192.5.44 NOKEY provide-xfr: 168.192.5.44 NOKEY You also can set the outgoing interface for notifies and zone transfer requests to satisfy access control lists at the other end: .. code-block:: text outgoing-interface: 168.192.5.69 By default, NSD will retry a notify up to five times. You can override that value with: .. code-block:: text notify-retry: 5 Zone transfers can be secured with TSIG keys, replace NOKEY with the name of the TSIG key to use. See :doc:`Using TSIG` for details. Since NSD is written to be run on root name servers, the config file can contain something like: .. code-block:: text zone: name: "." zonefile: "root.zone" provide-xfr: 0.0.0.0/0 NOKEY # allow axfr for everyone. provide-xfr: ::0/0 NOKEY You should only do that if you're intending to run a root server, NSD is not suited for running a ``.`` cache. Therefore if you choose to serve the ``.`` zone you have to make sure that the complete root zone is timely and fully updated. To prevent misconfiguration, NSD configure has the ``--enable-root-server`` option, that is by default disabled. In the config file, you can use patterns. A pattern can have the same configuration statements that a zone can have. And then you can ``include-pattern: `` in a zone (or in another pattern) to apply those settings. This can be used to organise the settings. Remote controlling NSD ---------------------- The :command:`nsd-control` tool is also controlled from the ``nsd.conf`` config file (and it's manpage is found :doc:`here`). It uses TLS encrypted transport to 127.0.0.1, and if you want to use it you have to setup the keys and also edit the config file. You can leave the remote-control disabled (the secure default), or opt to turn it on: .. code-block:: text # generate keys nsd-control-setup .. code-block:: text # edit nsd.conf to add this remote-control: control-enable: yes By default :command:`nsd-control` is limited to localhost, as well as encrypted, but some people may want to remotely administer their nameserver. To control NSD remotely, configure :command:`nsd-control` to listen to the public IP address with ``control-interface: `` after the control-enable statement. Furthermore, you copy the key files :file:`/etc/nsd/nsd_server.pem` :file:`/etc/nsd/nsd_control.*` to a remote host on the internet; on that host you can run :command:`nsd-control` with :option:`-c` ```` which references same IP address ``control-interface`` and references the copies of the key files with ``server-cert-file``, ``control-key-file`` and ``control-cert-file`` config lines after the ``control-enable`` statement. The nsd-server authenticates the nsd-control client, and also the :command:`nsd-control` client authenticates the nsd-server. Starting up the first time -------------------------- When you are done with the configuration file, check the syntax using .. code-block:: text nsd-checkconf You can start the daemon in a number of ways: .. code-block:: text nsd -c nsd-control start # which execs nsd via the remote-control configuration nsd # which will use the default configuration file To check if the daemon is running look with :command:`ps`, :command:`top`, or if you enabled :command:`nsd-control`: .. code-block:: text nsd-control status To reload changed zone files after you edited them, without stopping the daemon, use this to check if files are modified: .. code-block:: text kill -HUP `cat ` or "nsd-control reload" if you have remote-control enabled With :command:`nsd-control` you can also reread the config file, in case of new zones, etc. .. code-block:: text nsd-control reconfig To restart the daemon: .. code-block:: text /etc/rc.d/nsd restart # or your system(d) equivalent To shut it down (for example on the system shutdown) do: .. code-block:: text kill -TERM or nsd-control stop NSD will automatically keep track of secondary zones and update them when needed. When primary zones are updated and reloaded notifications are sent to secondary servers. To write changed contents of the zone files for secondary zones to disk in the text-based zone file format, issue :command:`nsd-control write`. NSD will send notifications to secondary zones if a primary zone is updated. NSD will check for updates at primary servers periodically and transfer the updated zone by AXFR/IXFR and reload the new zone contents. If you wish exert manual control use :command:`nsd-control notify`, :command:`transfer` and :command:`force_transfer` commands. The transfer command will check for new versions of the secondary zones hosted by this NSD. The notify command will send notifications to the secondary servers configured in ``notify:`` statements. nsd-4.12.0/doc/manual/conf.py.in0000644000175000017500000002335315002373054015731 0ustar mozziemozzie# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) import os import datetime import sphinx_rtd_theme import requests # -- Project information ----------------------------------------------------- project = '@project@' year = datetime.datetime.now().year copyright = f'2001–{year}, NLnet Labs' author = 'NLnet Labs' # The short X.Y version version = '@version@' # The full version, including alpha/beta/rc tags release = '@version@' try: response_versions = requests.get( f"https://readthedocs.org/api/v2/version/?project__slug=nsd&active=true", timeout=2, ).json() versions = [ (version["slug"], f"/{version['project']['language']}/{version['slug']}/") for version in response_versions["results"] ] except Exception: versions = [] # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx_tabs.tabs', 'sphinx_copybutton', 'sphinx.ext.intersphinx', 'sphinx.ext.autosectionlabel', 'notfound.extension', 'sphinxcontrib.jquery', 'sphinx_rtd_theme', 'sphinx_substitution_extensions', ] intersphinx_mapping = { 'nsd': ('https://nsd.docs.nlnetlabs.nl/en/latest/', None) } autosectionlabel_prefix_document = True # -- Sphinx Tabs configuration ----------------------------------------------- sphinx_tabs_disable_tab_closing = True sphinx_tabs_disable_css_loading = True # Add any paths that contain templates here, relative to this directory. templates_path = ['../templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'sphinx_rtd_theme' html_logo = 'resources/nsd-duotone-white.png' html_favicon = 'resources/favicon.ico' html_theme_options = { 'logo_only': True, } # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['resources'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # Set canonical URL from the Read the Docs Domain html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") scheme = "https" html_context = { 'html_theme': html_theme, 'current_version': version, 'version_slug': version, 'PRODUCTION_DOMAIN': "readthedocs.org", 'versions': versions, # "downloads": downloads, # "subprojects": subprojects, 'slug': "nsd", 'rtd_language': language, 'canonical_url': html_baseurl, 'conf_py_path': "/doc/manual/", 'github_user': "NLnetLabs", 'github_repo': "nsd", 'github_version': os.environ.get("READTHEDOCS_GIT_IDENTIFIER", "main"), 'display_github': True, 'READTHEDOCS': True, 'using_theme': False, 'new_theme': True, 'source_suffix': ".rst", 'docsearch_disabled': False, } # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'NSDUserManualdoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'NSDUserManual.tex', 'NSD User Manual', 'NLnet Labs', 'manual'), ] # -- Options for manual page output ------------------------------------------ # Manual pages are generated from the actual manual pages using mandoc. # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). #man_pages = [ # ('manpages/nsd', 'nsd', 'Name Server Daemon (NSD)', # "NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.", 8), # ('manpages/nsd-checkconf', 'nsd-checkconf', 'NSD configuration file checker.', # "NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.", 8), # ('manpages/nsd-checkzone', 'nsd-checkzone', 'NSD zone file syntax checker.', # "NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.", 8), # ('manpages/nsd.conf', 'nsd.conf', 'NSD configuration file.', # "NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.", 5), # ('manpages/nsd-control', 'nsd-control', 'NSD remote server control utility.', # "NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.", 8) #] #manpages_url = '{page}.html' # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'NSDUserManual', 'NSD User Manual', author, 'NSDUserManual', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author epub_copyright = copyright # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- # -- Options for todo extension ---------------------------------------------- # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True # -- Extension interface -------------------------------------------------- from sphinx import addnodes def parse_cmd_args_node(env, sig, signode): try: cmd, args = sig.strip().split(' ', 1) except ValueError: cmd, args = sig, None # distinguish cmd from its args signode += addnodes.desc_name(cmd, cmd) if args: args = ' ' + args signode += addnodes.desc_addname(args, args) return cmd # define new directive/role that can be used as .. subcmd::/:subcmd: def setup(app): app.add_object_type('subcmd', 'subcmd', objname='module sub-command', indextemplate='pair: %s; module sub-command', parse_node=parse_cmd_args_node) app.add_css_file('css/dark.css') app.add_css_file('css/light.css') # -- Export variables to be used in RST -------------------------------------- rst_epilog = ".. |pidfile| replace:: @pidfile@\n" \ ".. |configdir| replace:: @configdir@\n" \ ".. |configfile| replace:: @nsdconfigfile@\n" \ ".. |logfile| replace:: @logfile@\n" \ ".. |xfrdfile| replace:: @xfrdfile@\n" \ ".. |zonelistfile| replace:: @zonelistfile@\n" # -- Options for substitution extension -------------------------------------- rst_prolog = ".. |version| replace:: @version@" nsd-4.12.0/doc/manual/catalog-zones.rst0000644000175000017500000001613415002373054017324 0ustar mozziemozzieCatalog zones ============= Since version 4.9.0, NSD has support for Catalog zones version "2" as specified in `RFC 9432 `_. NSD can be a producer of catalog zones as well as a catalog zone consumer, but it is limited to process only a single consumer zone. Setting up NSD as a catalog consumer ------------------------------------ NSD will process a zone as a catalog consumer zone if the zone has the ``catalog: consumer`` option set. An example catalog consumer configuration could look like this: .. code:: bash pattern: name: "member-zone-config" request-xfr: 198.51.100.1 NOKEY allow-notify: 198.51.100.1 NOKEY key: name: tsig-key.name algorithm: hmac-sha256 secret: "SXMgdGhpcyBhIHNlY3JldCBvciBqdXN0IHRleHQ/Pz8=" tls-auth: name: primary.example auth-domain-name: primary.example zone: name: "catalog1.invalid" catalog: consumer catalog-member-pattern: "member-zone-config" request-xfr: 192.0.2.1@853 tsig-key.name primary.example allow-notify: 192.0.2.1 tsig-key.name allow-query: BLOCKED The consumer zone ``catalog1.invalid`` is configured in the example as a secondary zone. It transfers the catalog from the primary at ``192.0.2.1``. The transfer is mutually authenticated :doc:`using TSIG`. The content of catalog zones are only relevant for the name servers handling those zones. They contain a list of zones that are served from the name servers and it is likely undesirable to expose that content. We have protected the zone against queries from third-parties by setting the ``allow-query: BLOCKED`` option. The transfer is protected against on-path eavesdroppers by doing it over :doc:`authenticated TLS`. .. Note:: Using privacy preserving option is RECOMMENDED for catalog zones (See `RFC 9432 Sections 6 and 7 `_). .. Note:: Catalog consumer zones do not need to be secondary, they may also process just zone files. NSD supports the `group property `_. Member zones from the catalog will be added with the pattern given by the group property of that member. If a member does not have a group property or its value is invalid or doesn't match a pattern, the pattern given by the ``catalog-member-pattern:`` option will be used. Using nsd-control to get catalog zone status -------------------------------------------- The status of catalog zones and catalog member zones can be consulted with :command:`nsd-control zonestatus`. .. code:: bash $ nsd-control zonestatus zone: catalog1.invalid catalog: consumer (serial: 1708341939, # members: 2) state: ok served-serial: "1708341939 since 2024-02-19T15:19:44" commit-serial: "1708341939 since 2024-02-19T15:19:44" wait: "3461 sec between attempts" zone: example.net pattern: member-zone-config catalog-member-id: a5b75379.zones.catalog1.invalid. state: ok served-serial: "2024013019 since 2024-02-19T14:25:43" commit-serial: "2024013019 since 2024-02-19T14:25:43" wait: "7195 sec between attempts" zone: example.org pattern: group1 catalog-member-id: 96143f7d.zones.catalog1.invalid. state: ok served-serial: "2024013016 since 2024-02-19T14:18:10" commit-serial: "2024013016 since 2024-02-19T14:18:10" wait: "6544 sec between attempts" The first ``zone:`` entry in the example output above shows the status our configured consumer zone ``catalog1.invalid``. Besides its role (``consumer`` or ``producer``) it show the last SOA serial number that was successfully processed, and the number of member zones that were added by processing the consumer zone. .. Note:: If the catalog zone has become invalid and isn't processed anymore, :command:`nsd-control zonestatus` will show the reason why. :command:`nsd-control zonestatus` will also show the ``catalog-member-id`` of catalog member zones. In the example output of :command:`nsd-control zonestatus` above we can see that ``example.net`` and ``example.org`` are member zones from ``catalog1.invalid``. Apparently the ``example.net`` member did not have a valid group property, because it has been added with the default ``catalog-member-pattern:`` ``member-zone-config``. Setting up NSD as a catalog producer ------------------------------------ A catalog producer zone can be configured in NSD by setting the ``catalog: producer`` option. Unlike consumer zones, multiple producer zones may be configured. NSD creates the content of producer zones and therefore producer zones cannot be configured as secondary zones. Likewise, ``zonefile:`` options are only used to write the zone, never to read it. An example catalog producer configuration could look like this: .. code:: bash server: interface: 192.0.2.1@853 tls-port: 853 tls-service-key: "primary.example.key.pem" tls-service-pem: "primary.example.cert.pem" pattern: name: "group0" catalog-producer-zone: "catalog1.invalid" pattern: name: "group1" catalog-producer-zone: "catalog1.invalid" key: name: tsig-key.name algorithm: hmac-sha256 secret: "SXMgdGhpcyBhIHNlY3JldCBvciBqdXN0IHRleHQ/Pz8=" zone: name: "catalog1.invalid" catalog: producer store-ixfr: yes provide-xfr: 203.0.113.1@853 tsig-key.name notify: 203.0.113.1 tsig-key.name allow-query: BLOCKED The producer zone is configured as a primary and allows (in our example) transfer of the zone over TLS only. Also, just like with the consumer zone configuration example above, queries to this zone are ``BLOCKED`` to comply with `RECOMMENDED `_ privacy and security considerations. We also recommend - for primary zones in general - to serve *incremental* transfers (configured with ``store-ixfr: yes``). Zones can be added as member zones, by adding them to NSD with :command:`nsd-control addzone` with a pattern that has the name of the producer zone as value of a ``catalog-producer-zone:`` option. In the example configuration above, patterns ``"group0"`` and ``"group1"`` both have that option. Here is an example on how to do that: .. code:: bash $ nsd-control addzone example.net group0 ok $ nsd-control addzone example.org group1 ok Like with consumer zones and consumer member zones, :command:`nsd-control zonestatus` can be used to check on the status of catalog producer zones and its members: .. code:: bash $ nsd-control zonestatus zone: catalog1.invalid catalog: producer (serial: 1708341939, # members: 2) state: primary zone: example.net pattern: group0 catalog-member-id: a5b75379.zones.catalog1.invalid. state: primary zone: example.org pattern: group1 catalog-member-id: 96143f7d.zones.catalog1.invalid. state: primary Like with other zones added with :command:`nsd-control addzone`, the member zones are persistently added to the zone list file (see the ``zonelistfile:`` configure option). The content of the catalog producer zone is not persistent and will be reconstructed from the member zone entries in the zone list file. .. code:: bash $ cat /var/db/nsd/zone.list # NSD zone list # name pattern cat example.net group0 a5b75379 cat example.org group1 96143f7d nsd-4.12.0/doc/differences.tex0000644000175000017500000007015615002373054015552 0ustar mozziemozzie% DIFFERENCES NSD 3 and other name servers. \documentclass[twoside,titlepage,english]{nlnetlabs} \newcites{rfc}{RFC references} \def\nlnetlabsno{2006-004} \rcsdetails{$Id$} % Prints RCS details at the bottom of the page. \title{Response Differences between\\ NSD and other DNS Servers} \author{ %This escape is needed. Because of wrapping by hyperref \texorpdfstring{ Jelte Jansen\thanks{\href{mailto:jelte@nlnetlabs.nl}{jelte@nlnetlabs.nl}}, \textsl{NLnet Labs}\\ Wouter Wijngaards\thanks{\href{mailto:wouter@nlnetlabs.nl}{wouter@nlnetlabs.nl}}, \textsl{NLnet Labs} } {Jelte Jansen, Wouter C.A. Wijngaards} } \date{ \today } \begin{document} \flushbottom \maketitle{} \begin{abstract} This note describes observed differences in responses between NSD and other DNS server implementations. NSD 3.0.0 is compared to NSD 2.3.6, BIND 8.4.7 and BIND 9.3.2. Differences in answers to captured queries from resolvers are tallied and analyzed. No interoperability problems are found. \end{abstract} \tableofcontents \newpage \section{Introduction} The NSD name server is compared to other DNS server implementations in order to assess server interoperability. The goal is to observe differences in the answers that the name servers provide. These differences are categorized and counted. We used BIND 8 and BIND 9 versions to compare against. Also regression tests have been run on our testlab, comparing NSD 2 versus NSD 3. Our method uses a set of queries captured from production name servers. These queries are sent over UDP to a name server set up to serve a particular zone. Then the responses from the name server are recorded. For every query, the different answers provided by the server implementations are compared. Unparseable answers and no answers from the servers are handled identically by the comparison software. This is not a problem because both BIND and NSD are mature and stable DNS implementations, all answers they send are parseable. Only in a very few cases, where the query is very badly formed, no answers are sent back. The differences are found by replaying captured DNS query traces from the NL TLD and from the root zone against different name servers. The differences in the answers are then analyzed, by first performing a byte-comparison on the packets. If the packets are binary different, the contents are parsed, thus removing differences in domain name compression, and normalized (sorted, lowercase) in presentation. If the results do not match after normalization, then a list of difference categories is consulted. The difference is classified as the first category that matches. If a difference in answers does not match any category, then the process stops and the user is notified. All the differences are categorized for the traces we present. In addition, we gratefully made use of the PROTOS DNS tool developed at the University of Oulu which they made publicly available at \href{http://www.ee.oulu.fi/research/ouspg/protos/testing/c09/dns} {the protos webpage}\footnote{http://www.ee.oulu.fi/research/ouspg/protos/testing/c09/dns} and played the queries against the authoritative name servers. We fixed a packet parsing error in NSD3-prerelease and both NSD3 and BIND 9.3.2 remained running and responsive. Additionally we used the faulty DNS query traces in the wiki-ethereal repository. These can be found in \href{http://wiki.ethereal.com/SampleCaptures} {the ethereal wiki}\footnote{http://wiki.ethereal.com/SampleCaptures}. These traces posed no problem for BIND and NSD, mostly FORMERR answers. A previous document DIFFERENCES between BIND 8.4.4 and NSD 2.0.0 can be found in the NSD 2.x package. In the places where differences have been found between BIND and NSD, in the authors' opinion, no interoperability problems result for resolvers. \section{Response differences between BIND 9.3.2 and NSD 3.0.0} In this section the response differences between BIND 9.3.2 and NSD 3.0.0 are presented and analyzed. We start in Section~\ref{root_b932nsd3} and Section~\ref{nl_b932nsd3} with presenting the difference statistics for two test traces. Then in Section~\ref{sec:features} and Section~\ref{sec:funcdiff} the difference categories are explained in more detail. \subsection{Comparison of responses to root queries} \label{root_b932nsd3} Comparison between NSD 3.0.0 and BIND 9.3.2 for a root trace. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ d-additional (\ref{d-additional}) & 455607 & 59.19\% \\ n-clrdobit (\ref{n-clrdobit}) & 208389 & 27.07\% \\ b-soattl (\ref{b-soattl}) & 101707 & 13.21\% \\ n-update (\ref{n-update}) & 1858 & 0.24\% \\ d-hostname (\ref{d-hostname}) & 1032 & 0.13\% \\ d-formerrquery (\ref{d-formerrquery}) & 773 & 0.10\% \\ b-class0 (\ref{b-class0}) & 264 & 0.03\% \\ d-refusedquery (\ref{d-refusedquery}) & 79 & 0.01\% \\ d-notify (\ref{d-notify}) & 18 & 0.00\% \\ b-mailb (\ref{b-mailb}) & 7 & 0.00\% \\ n-tcinquery (\ref{n-tcinquery}) & 6 & 0.00\% \\ b-classany-nxdomain (\ref{b-classany-nxdomain}) & 5 & 0.00\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 4 & 0.00\% \\ n-ixfr-notimpl (\ref{n-ixfr-notimpl}) & 3 & 0.00\% \\ d-version (\ref{d-version}) & 1 & 0.00\% \\ Total number of differences: & 769753 & 100\% \\ Number of packets the same after normalization:&1474863 \\ Number of packets exactly the same on the wire:& 59161 \\ Total number of packets inspected: &2244616 \\ \end{tabular} For each type of difference the number of packets in the trace that match that difference are shown. The section where that difference is analyzed is shown in parenthesis after the difference name. The percentage of differences explained by the difference category is listed. Adding up the packets that are different gives the total number of differences, or 100\% of the differences. The number of packets after normalization includes the number of packets that are the same on the wire. The total number of query packets is displayed at the bottom of the table. \subsection{Comparison of responses to NL TLD queries} \label{nl_b932nsd3} Comparison between NSD 3.0.0 and BIND 9.3.2, for a trace for .nl. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ d-unknown-opcode (\ref{d-unknown-opcode}) & 2541 & 26.44\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 1817 & 18.91\% \\ n-clrdobit (\ref{n-clrdobit}) & 1495 & 15.56\% \\ b-soattl (\ref{b-soattl}) & 1120 & 11.65\% \\ n-update (\ref{n-update}) & 990 & 10.30\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 847 & 8.81\% \\ d-hostname (\ref{d-hostname}) & 531 & 5.52\% \\ d-notify (\ref{d-notify}) & 98 & 1.02\% \\ b-upwards-ref (\ref{b-upwards-ref}) & 78 & 0.81\% \\ n-clrcdbit (\ref{n-clrcdbit}) & 63 & 0.66\% \\ d-version (\ref{d-version}) & 22 & 0.23\% \\ b-noglue-nsquery (\ref{b-noglue-nsquery}) & 8 & 0.08\% \\ b8-badedns0 (\ref{b8-badedns0}) & 1 & 0.01\% \\ Total number of differences: & 9611 & 100\% \\ Number of packets the same after normalization: & 90389 \\ Number of packets exactly the same on the wire: & 52336 \\ Total number of packets inspected: & 100000 \\ \end{tabular} \subsection{Features} \label{sec:features} In this section we enumerate a number of differences between BIND 9.3.2 and NSD 3.0.0 that cannot be immediately explained as design choices. These features could be seen as bugs in software or protocol specs, except that they do not lead to interoperability problems. \subsubsection{n-clrdobit - NSD clears DO bit in response} \label{n-clrdobit} NSD clears the DO bit in answers to queries with the DO bit. BIND copies the DO bit to the answer. \vspace{-8pt}\subparagraph{Analysis:} In RFC4035\cite{rfc4035} the DO bit is not specified for answers. In the examples section of that RFC the DO bit is shown for signed dig responses, although this could refer to the query or the answer. NSD clears the DO bit for all answers, a decision based on speed: the EDNS record sent back by NSD is precompiled and not modified during answer processing. \subsubsection{n-clrcdbit - NSD clears CD bit in response} \label{n-clrcdbit} NSD clears the CD bit in answers to queries with the CD bit. BIND copies the CD bit to the answer. \vspace{-8pt}\subparagraph{Analysis:} RFC 4035\cite{rfc4035} asserts that the CD bit must be cleared for authoritative answers. The CD bit should be copied into the answer by recursive servers. BIND copies the CD bit for some formerr queries. \subsubsection{b-class0 - CLASS0 formerr in BIND} \label{b-class0} For CLASS0, you can get either FORMERR, from BIND or REFUSED, from NSD. \vspace{-8pt}\subparagraph{Analysis:} Difference in interpretation of the RFCs, a CLASS value of 0 is interpreted as a syntax error by BIND but as another valid class (that is not served) by NSD. Resolvers are unaffected for CLASS IN. \subsubsection{n-tcinquery - TC bit in query is formerr for NSD} \label{n-tcinquery} NSD returns FORMERR if tc bit is set in query. \vspace{-8pt}\subparagraph{Analysis:} Queries cannot be longer than 512 octets, since the DNS header is short and the query DNS name has a maximum length of 255 octets. Thus TC (TrunCation) cannot happen. Only one question per query packet is answered by NSD, this is a design decision. Some update, ixfr request, notify, gss-tsig TKEY sequence queries could theoretically carry longer data in the query from the client. In practice this does not happen, as 255 octet uncompressed names are not used. If this were to happen, the client could attempt a TCP connection immediately instead of setting a TC bit, or use EDNS0 to send longer packets. In this NSD is more strict in validation than BIND. \subsubsection{b-soattl - BIND sets SOA TTL in authority section to 0 for SOA queries} \label{b-soattl} This happens when asking for the SOA for a domain that is not served. \footnotesize \begin{verbatim} Query: ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0 ;; flags: rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA \end{verbatim} \normalsize Answer from BIND 9.3.2: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 6097 ;; flags: qr aa rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 0 IN SOA A.ROOT-SERVERS.NET. NSTLD.VERISIGN-GRS.COM. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 10 msec ;; SERVER: 127.0.0.1 ;; WHEN: Wed Aug 23 13:52:36 2006 ;; MSG SIZE rcvd: 100 \end{verbatim} \normalsize Answer from NSD 3: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 26095 ;; flags: qr aa rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 60 msec ;; SERVER: 127.0.0.1 ;; WHEN: Wed Aug 23 13:53:30 2006 ;; MSG SIZE rcvd: 100 \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} BIND conforms to internet-draft draft-andrews-dnsext-soa-discovery which has at the moment of code development not (yet) been published as RFC. NSD conforms to the RFCs. \subsubsection{b-classany-nxdomain - BIND gives an auth answer for class ANY nxdomain} \label{b-classany-nxdomain} A difference in behaviour for CLASS=ANY queries. For existing domains both BIND and NSD reply with AA bit cleared. For not existing domains (nxdomain) NSD replies with AA bit cleared. BIND replies with AA bit on and includes a SOA (CLASS=IN) for the zone, as for an authoritative nxdomain. Query: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 13328 ;; flags: ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruO. ANY MX \end{verbatim} \normalsize Answer from BIND 9.3.2: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 13328 ;; flags: qr aa ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruo. ANY MX ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 0 msec ;; WHEN: Wed Aug 23 13:58:51 2006 ;; MSG SIZE rcvd: 103 \end{verbatim} \normalsize Answer from NSD 3: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 13328 ;; flags: qr ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruo. ANY MX ;; ANSWER SECTION: ;; AUTHORITY SECTION: ;; ADDITIONAL SECTION: ;; Query time: 0 msec ;; WHEN: Wed Aug 23 13:58:51 2006 ;; MSG SIZE rcvd: 28 \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} Feature of BIND where it answers authoritatively for CLASS ANY nxdomain queries. \subsubsection{b-badquery-badanswer - BIND replies with bad answer for some bad queries} \label{b-badquery-badanswer} BIND replies with an answer packet that cannot be parsed, or does not answer at all. NSD always generates an answer, with the appropriate RCODE (mostly NOTIMPL and FORMERR, but also NXDOMAIN to NOTIFY queries). All these queries are malformed in some way. A (very simple) example of a query without an answer is a query packet of 18 zero bytes. For some queries no answer only happens when BIND is presented with a trace of queries, not for a single query. \vspace{-8pt}\subparagraph{Analysis:} BIND includes (part of) the unparseable question into the answer, or some internal state of BIND is affected by earlier queries. NSD manages to answer the malformed query. Note that NSD does not answer queries that are too short, or that have the QR bit set. NSD tries to be as liberal in what it accepts as possible. \subsection{Functionality Differences} \label{sec:funcdiff} The next group of differences are due to the fact that NSD does not implement some functionality that is requested by resolvers. This is a design choice and should not cause resolver problems at all, since responses to those requests are within protocol specs. \subsubsection{d-notify - different NOTIFY errors} \label{d-notify} BIND and NSD give different errors for notify queries. The servers are started without any configuration for access control on notify. For notify messages aimed at a zone that is served, BIND 9.3.2 returns a NOERROR answer, and NSD 3 returns NOTAUTH. For notify messages on a zone that is not served (in-addr.arpa.) BIND 9.3.2 returns NOTAUTH and NSD 3 returns NXDOMAIN. \vspace{-8pt}\subparagraph{Analysis:} Default configuration differs between the two packages. NSD is more strict. Error codes are different, the tools that send notifies are not affected. \subsubsection{n-update - NSD does not implement dynamic update} \label{n-update} For UPDATE, you can get either REFUSED/NXRRSET/other RCODE from BIND 9.3.2 or NOTIMPL from nsd3. \vspace{-8pt}\subparagraph{Analysis:} NSD does not implement dynamic update. \subsubsection{b-mailb - BIND does not implement MAILB} \label{b-mailb} For MAILB, you can get either NOTIMPL(BIND 9) or NOERROR/NXDOMAIN(NSD 3). \vspace{-8pt}\subparagraph{Analysis:} BIND does not implement queries for the MAILB type. NSD treats it as one of the RRTYPEs. MAILB is obsoleted by RFCs, the MX type is used to transfer mail information now. \subsubsection{d-version - BIND returns servfail on version.server queries} \label{d-version} NSD returns version.server query, BIND returns servfail. \vspace{-8pt}\subparagraph{Analysis:} Both NSD and BIND return version.bind queries of the chaos class. These queries differ in the version number they return, of course. BIND does not return version.server queries. This is a design decision on the part of NSD to return version.server queries with the same answer. \subsubsection{d-additional - Different additional section on truncated answers} \label{d-additional} NSD and BIND return different additional sections on truncated answers to queries from the root. These answers are 480+ bytes long. \vspace{-8pt}\subparagraph{Analysis:} Not all the A and AAAA data fits into the additional section of the answer. BIND includes different names than NSD does, and BIND is observed to sometimes include one more AAAA record, less A records in the additional section. Resolvers should be unaffected. \subsubsection{d-refusedquery - BIND includes query section in REFUSED answers} \label{d-refusedquery} BIND includes the query sent for REFUSED answers. NSD replies with only the DNS header section. \vspace{-8pt}\subparagraph{Analysis:} The resolver must inspect the query ID. The error code provides sufficient information. Sending the header makes NSD replies smaller and thus more resilient to DoS attacks. \subsubsection{d-hostname - BIND adds a NS record for hostname.bind} \label{d-hostname} BIND includes an additional RR in the authority section of the reply: \footnotesize \begin{verbatim} hostname.bind. 0 CH NS hostname.bind. \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} The RR seems useless. NSD does not include it. \subsubsection{n-ixfr-notimpl - NSD does not implement IXFR} \label{n-ixfr-notimpl} To queries for IXFR BIND responds with a valid answer (the latest SOA) and NSD responds with NOTIMPL error. \vspace{-8pt}\subparagraph{Analysis:} NSD 3.0.0 does not implement IXFR. It returns NOTIMPL by design. \subsubsection{d-formerrquery - BIND includes query section in FORMERR answers} \label{d-formerrquery} BIND includes the query sent for FORMERR answers. NSD replies with only the DNS header section. For some queries, NSD includes an EDNS record in the reply if there was a recognizable EDNS record in the query. \vspace{-8pt}\subparagraph{Analysis:} The resolver must inspect the query ID. The error code provides sufficient information. Sending the header makes NSD replies smaller and thus more resilient to DoS attacks. \subsubsection{d-badqueryflags - BIND includes query section in FORMERR answers} \label{d-badqueryflags} BIND includes the query section in reply to unparseable queries. NSD does not. \vspace{-8pt}\subparagraph{Analysis:} Same as d-formerrquery (\ref{d-formerrquery}), but the implementation of the comparison software could not parse the query either, thus a separate label. \subsubsection{d-unknown-class - BIND includes query section in answers to unknown class} \label{d-unknown-class} For queries with an unknown class in the query, BIND includes the query section in the answer. NSD does not. \vspace{-8pt}\subparagraph{Analysis:} Same as d-formerrquery (\ref{d-formerrquery}), but for a different error. \subsubsection{d-unknown-opcode - NSD returns NOTIMPL for unknown opcode} \label{d-unknown-opcode} For queries that are bad packets, with malformed RRs, with an unknown opcode, BIND returns a FORMERR, but NSD gives up after checking the opcode and returns NOTIMPL. NSD copies the flags from the query, and turns on the QR (query response) bit, BIND zeroes some of the flags. \vspace{-8pt}\subparagraph{Analysis:} NOTIMPL is appropriate since NSD does not implement whatever functionality is being looked for. \subsubsection{b-upwards-ref - BIND returns root delegation} \label{b-upwards-ref} For queries to a domain that is not served, which can only have arrived at this server due to a lame delegation, BIND returns a root delegation. NSD returns SERVFAIL. \vspace{-8pt}\subparagraph{Analysis:} By design, NSD does not know the root-servers. NSD is unable to reply as the zone is not configured, hence the SERVFAIL. This is also discussed in the REQUIREMENTS document for NSD. \subsubsection{b-noglue-nsquery - BIND returns no glue for NS queries} \label{b-noglue-nsquery} For queries for the NS records of the zone, BIND does not include glue for the NS records. NSD includes glue for the NS servers that lie within the zone. \vspace{-8pt}\subparagraph{Analysis:} The glue saves a followup query. \subsubsection{d-noquestion - different error on no question} \label{d-noquestion} For queries without a question section the error code differs. NSD considers it a FORMERR. BIND returns REFUSED. \vspace{-8pt}\subparagraph{Analysis:} Error code not specified for this corner case. No problems for resolvers. \subsubsection{b-uchar - BIND returns FORMERR on strange characters} \label{b-uchar} BIND returns FORMERR on strange characters in the query, such as 0x00, 0xff, 0xe4, 0x20, 0x40 and so on. \vspace{-8pt}\subparagraph{Analysis:} NSD does not give a formerr on these queries, it processes them. NSD normalizes names to lower case. Otherwise leaves them untouched. BIND preserves case in answers. Choice made in REQUIREMENTS for NSD, also see RFC1035\cite{rfc1035} 2.3.3. \section{Response differences between NSD 2.3.6 and NSD 3.0.0} The differences between NSD 2.3.6 and NSD 3.0.0 are listed below. All are due to version number changes and new features in NSD 3. \subsection{Comparison of responses in root trace} Differences between NSD 2.3.6 and NSD 3.0.0 for a root trace. Note that apart from the 26 packets that are different, all responses are binary the same on the wire between the two versions of NSD. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-notify (\ref{n-notify}) & 19 & 73.08\% \\ n-ixfr (\ref{n-ixfr}) & 3 & 11.54\% \\ version.bind (\ref{nsd-version}) & 3 & 11.54\% \\ version.server (\ref{nsd-version}) & 1 & 3.85\% \\ Total number of differences: & 26 & 100\% \\ Number of packets the same after normalization:&2244590 \\ Number of packets exactly the same on the wire:&2244590 \\ Total number of packets inspected: &2244616 \\ \end{tabular} \subsection{Comparison of responses in NL TLD trace} Differences between NSD 2.3.6 and NSD 3.0.0 for a nl. trace. Note that apart from the 311 packets that are different, all responses are binary the same on the wire between the two versions of NSD. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-notify (\ref{n-notify}) & 289 & 92.93\% \\ version.bind (\ref{nsd-version}) & 22 & 7.07\% \\ Total number of differences: & 311 & 100\% \\ Number of packets the same after normalization:& 99689 \\ Number of packets exactly the same on the wire:& 99689 \\ Total number of packets inspected: &100000 \\ \end{tabular} \subsection{Version number - version.bind and version.server} \label{nsd-version} To queries for version.bind and version.server the different implementations return a different version number, as they should. \vspace{-8pt}\subparagraph{Analysis:} Expected. Correct version numbers are returned. \subsection{n-notify - notify not implemented in NSD 2} \label{n-notify} Notifications are handled differently. NSD 2 returns NOTIMPL error code, while NSD 3 returns NOTAUTH or NXDOMAIN error codes. \vspace{-8pt}\subparagraph{Analysis:} Default config denies all notify queries for NSD 3. These answers are correct for non-existing and not authorized domains. \subsection{n-ixfr - IXFR error FORMERR in NSD 2} \label{n-ixfr} To IXFR query questions different error codes are given. The NSD 2 gives FORMERR (due to the RR in the authority section). NSD 3 returns NOTIMPL. \vspace{-8pt}\subparagraph{Analysis:} Neither version of NSD implements IXFR. It is more appropriate to return the NOTIMPL error code in that case. Bugfix in NSD. \section{Response differences between BIND 8 and NSD 3.0.0} In this section the response differences between BIND 8.4.7 and NSD 3.0.0 are categorized and analyzed. \subsection{Comparison of responses in root trace} The differences between BIND 8.4.7 and NSD 3.0.0 when presented with queries for the root zone are below. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-clrcdbit (\ref{n-clrcdbit}) & 516372 &84.39\% \\ d-hostname (\ref{d-hostname}) & 53431 &8.73\% \\ d-additional (\ref{d-additional}) & 32526 &5.32\% \\ b8-nodata-ttlminup (\ref{b8-nodata-ttlminup}) & 4611 &0.75\% \\ n-update (\ref{n-update}) & 1856 &0.30\% \\ d-version (\ref{d-version}) & 1033 &0.17\% \\ b8-auth-any (\ref{b8-auth-any}) & 519 &0.08\% \\ b8-badedns0 (\ref{b8-badedns0}) & 492 &0.08\% \\ d-unknown-class (\ref{d-unknown-class}) & 482 &0.08\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 451 &0.07\% \\ b-class0 (\ref{b-class0}) & 97 &0.02\% \\ d-notify (\ref{d-notify}) & 18 &0.00\% \\ b8-ignore-tc-query (\ref{b8-ignore-tc-query}) & 6 &0.00\% \\ b8-badquery-ignored (\ref{b8-badquery-ignored}) & 4 &0.00\% \\ n-ixfr-notimpl (\ref{n-ixfr-notimpl}) & 3 &0.00\% \\ b-soattl (\ref{b-soattl}) & 1 &0.00\% \\ Total number of differences: & 611902 &100\% \\ Number of packets the same after normalization:&1632714 \\ Number of packets exactly the same on the wire:& 2299 \\ Total number of packets inspected: &2244616 \\ \end{tabular} \subsection{Comparison of responses in NL TLD trace} The differences between BIND 8.4.7 and NSD 3.0.0 when presented with queries for the .nl zone are below. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-clrcdbit (\ref{n-clrcdbit}) & 2857 &33.53\% \\ d-unknown-opcode (\ref{d-unknown-opcode}) & 2692 &31.59\% \\ n-update (\ref{n-update}) & 1283 &15.06\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 841 &9.87\% \\ d-hostname (\ref{d-hostname}) & 531 &6.23\% \\ d-notify (\ref{d-notify}) & 293 &3.44\% \\ d-version (\ref{d-version}) & 22 &0.26\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 1 &0.01\% \\ b8-badedns0 (\ref{b8-badedns0}) & 1 &0.01\% \\ Total number of differences: &8521 &100\% \\ Number of packets the same after normalization:&91479 \\ Number of packets exactly the same on the wire:&90837 \\ Total number of packets inspected:&100000 \\ \end{tabular} \subsection{b8-nodata-ttlminup - BIND 8 uses minimum TTL from SOA also if bigger} \label{b8-nodata-ttlminup} For NXDOMAIN queries in root-servers.net BIND 8 uses the minimum TTL from the SOA as the TTL of the included SOA RR. However, this minimum TTL is larger than the original TTL of the SOA, both NSD 2.3.6, NSD 3 and BIND 9 use the smaller of those two values as the TTL of the included SOA. \vspace{-8pt}\subparagraph{Analysis:} Bug in BIND 8 solved in BIND 9. \subsection{b8-badquery-ignored - BIND 8 replies normally for some bad queries} \label{b8-badquery-ignored} BIND8 manages to reply for malformed queries. NSD replies with FORMERR. \vspace{-8pt}\subparagraph{Analysis:} The query is bad, formerr is needed. Fixed in BIND9. \subsection{b8-badedns0 - BIND 8 ignores bad EDNS0 queries} \label{b8-badedns0} BIND 8 ignores queries with bad EDNS0 section. It answers the query. NSD replies with FORMERR. \vspace{-8pt}\subparagraph{Analysis:} BIND8 is more liberal in accepting broken EDNS0 records. NSD is not. Changed in BIND 9. \subsection{b8-auth-any - BIND 8 includes an authority section on queries for ANY .} \label{b8-auth-any} BIND8 includes an authority section on queries for class ANY . BIND9 and NSD return an empty authority section. \vspace{-8pt}\subparagraph{Analysis:} Fixed in BIND9. \subsection{b8-ignore-tc-query - BIND 8 ignores the TC bit in queries} \label{b8-ignore-tc-query} BIND responds to queries that have the TC bit set. NSD gives FORMERR. \vspace{-8pt}\subparagraph{Analysis:} This is like the n-tcinquery (\ref{n-tcinquery}), except where BIND9 returns NXDOMAIN, BIND8 returns the query with qr bit set. This is fixed in BIND9. NSD is less liberal in accepting queries, it returns form error on queries with the TC bit set. \bibliographystyle{nlnetlabs} \bibliography{allbib} \end{document} nsd-4.12.0/doc/differences.pdf0000644000175000017500000150764115002373054015530 0ustar mozziemozzie%PDF-1.4 5 0 obj << /S /GoTo /D (section.1) >> endobj 8 0 obj (Introduction) endobj 9 0 obj << /S /GoTo /D (section.2) >> endobj 12 0 obj (Response differences between BIND 9.3.2 and NSD 3.0.0) endobj 13 0 obj << /S /GoTo /D (subsection.2.1) >> endobj 16 0 obj (Comparison of responses to root queries) endobj 17 0 obj << /S /GoTo /D (subsection.2.2) >> endobj 20 0 obj (Comparison of responses to NL TLD queries) endobj 21 0 obj << /S /GoTo /D (subsection.2.3) >> endobj 24 0 obj (Features) endobj 25 0 obj << /S /GoTo /D (subsubsection.2.3.1) >> endobj 28 0 obj (n-clrdobit - NSD clears DO bit in response) endobj 29 0 obj << /S /GoTo /D (subsubsection.2.3.2) >> endobj 32 0 obj (n-clrcdbit - NSD clears CD bit in response) endobj 33 0 obj << /S /GoTo /D (subsubsection.2.3.3) >> endobj 36 0 obj (b-class0 - CLASS0 formerr in BIND) endobj 37 0 obj << /S /GoTo /D (subsubsection.2.3.4) >> endobj 40 0 obj (n-tcinquery - TC bit in query is formerr for NSD) endobj 41 0 obj << /S /GoTo /D (subsubsection.2.3.5) >> endobj 44 0 obj (b-soattl - BIND sets SOA TTL in authority section to 0 for SOA queries) endobj 45 0 obj << /S /GoTo /D (subsubsection.2.3.6) >> endobj 48 0 obj (b-classany-nxdomain - BIND gives an auth answer for class ANY nxdomain) endobj 49 0 obj << /S /GoTo /D (subsubsection.2.3.7) >> endobj 52 0 obj (b-badquery-badanswer - BIND replies with bad answer for some bad queries) endobj 53 0 obj << /S /GoTo /D (subsection.2.4) >> endobj 56 0 obj (Functionality Differences) endobj 57 0 obj << /S /GoTo /D (subsubsection.2.4.1) >> endobj 60 0 obj (d-notify - different NOTIFY errors) endobj 61 0 obj << /S /GoTo /D (subsubsection.2.4.2) >> endobj 64 0 obj (n-update - NSD does not implement dynamic update) endobj 65 0 obj << /S /GoTo /D (subsubsection.2.4.3) >> endobj 68 0 obj (b-mailb - BIND does not implement MAILB) endobj 69 0 obj << /S /GoTo /D (subsubsection.2.4.4) >> endobj 72 0 obj (d-version - BIND returns servfail on version.server queries) endobj 73 0 obj << /S /GoTo /D (subsubsection.2.4.5) >> endobj 76 0 obj (d-additional - Different additional section on truncated answers) endobj 77 0 obj << /S /GoTo /D (subsubsection.2.4.6) >> endobj 80 0 obj (d-refusedquery - BIND includes query section in REFUSED answers) endobj 81 0 obj << /S /GoTo /D (subsubsection.2.4.7) >> endobj 84 0 obj (d-hostname - BIND adds a NS record for hostname.bind) endobj 85 0 obj << /S /GoTo /D (subsubsection.2.4.8) >> endobj 88 0 obj (n-ixfr-notimpl - NSD does not implement IXFR) endobj 89 0 obj << /S /GoTo /D (subsubsection.2.4.9) >> endobj 92 0 obj (d-formerrquery - BIND includes query section in FORMERR answers) endobj 93 0 obj << /S /GoTo /D (subsubsection.2.4.10) >> endobj 96 0 obj (d-badqueryflags - BIND includes query section in FORMERR answers) endobj 97 0 obj << /S /GoTo /D (subsubsection.2.4.11) >> endobj 100 0 obj (d-unknown-class - BIND includes query section in answers to unknown class) endobj 101 0 obj << /S /GoTo /D (subsubsection.2.4.12) >> endobj 104 0 obj (d-unknown-opcode - NSD returns NOTIMPL for unknown opcode) endobj 105 0 obj << /S /GoTo /D (subsubsection.2.4.13) >> endobj 108 0 obj (b-upwards-ref - BIND returns root delegation) endobj 109 0 obj << /S /GoTo /D (subsubsection.2.4.14) >> endobj 112 0 obj (b-noglue-nsquery - BIND returns no glue for NS queries) endobj 113 0 obj << /S /GoTo /D (subsubsection.2.4.15) >> endobj 116 0 obj (d-noquestion - different error on no question) endobj 117 0 obj << /S /GoTo /D (subsubsection.2.4.16) >> endobj 120 0 obj (b-uchar - BIND returns FORMERR on strange characters) endobj 121 0 obj << /S /GoTo /D (section.3) >> endobj 124 0 obj (Response differences between NSD 2.3.6 and NSD 3.0.0) endobj 125 0 obj << /S /GoTo /D (subsection.3.1) >> endobj 128 0 obj (Comparison of responses in root trace) endobj 129 0 obj << /S /GoTo /D (subsection.3.2) >> endobj 132 0 obj (Comparison of responses in NL TLD trace) endobj 133 0 obj << /S /GoTo /D (subsection.3.3) >> endobj 136 0 obj (Version number - version.bind and version.server) endobj 137 0 obj << /S /GoTo /D (subsection.3.4) >> endobj 140 0 obj (n-notify - notify not implemented in NSD 2) endobj 141 0 obj << /S /GoTo /D (subsection.3.5) >> endobj 144 0 obj (n-ixfr - IXFR error FORMERR in NSD 2) endobj 145 0 obj << /S /GoTo /D (section.4) >> endobj 148 0 obj (Response differences between BIND 8 and NSD 3.0.0) endobj 149 0 obj << /S /GoTo /D (subsection.4.1) >> endobj 152 0 obj (Comparison of responses in root trace) endobj 153 0 obj << /S /GoTo /D (subsection.4.2) >> endobj 156 0 obj (Comparison of responses in NL TLD trace) endobj 157 0 obj << /S /GoTo /D (subsection.4.3) >> endobj 160 0 obj (b8-nodata-ttlminup - BIND 8 uses minimum TTL from SOA also if bigger) endobj 161 0 obj << /S /GoTo /D (subsection.4.4) >> endobj 164 0 obj (b8-badquery-ignored - BIND 8 replies normally for some bad queries) endobj 165 0 obj << /S /GoTo /D (subsection.4.5) >> endobj 168 0 obj (b8-badedns0 - BIND 8 ignores bad EDNS0 queries) endobj 169 0 obj << /S /GoTo /D (subsection.4.6) >> endobj 172 0 obj (b8-auth-any - BIND 8 includes an authority section on queries for ANY .) endobj 173 0 obj << /S /GoTo /D (subsection.4.7) >> endobj 176 0 obj (b8-ignore-tc-query - BIND 8 ignores the TC bit in queries) endobj 177 0 obj << /S /GoTo /D [178 0 R /Fit ] >> endobj 181 0 obj << /Length 1182 /Filter /FlateDecode >> stream xÚĄVYoÜ6~ׯУD ďĂO©±MaĂ0ŕîšäa9Q •Ö’Ö®űë;CRZ5QÁ+’3ś{ľ!K)üXĘ(%Bj™- çTĄűcBÓ/@ü#a‘©°śh¦X* ŐŇ"Kú”Rb´gpţ4]ŠooŽ,]µÉC’>L4PH˛&-.P*-#ÖĄĹܲëMňö=˛!ś)™ng0E$a›ĂÇěϲ?ĺ… YŰô%,´ÉVŐ'ĘDÎ2Řł¬+›}Ů#Eg;řŔń˙ ţ•e“Ţ܂ӄ;„ŢŻńć*Ű6‡°h‡ŻeUÜ#Ă:lÖe÷\v= ›!ÔŚ8Ą8ÚĚ9qL‚ŹĚIąđŇo˝]ő€ćrťÝân ć6¸čE ČĄ†8CĘQŽ(a”D+˝”O”Š%•c=q˝ ,BÍY äD`&˝Żw^/Ĺ[s‡–ěĽ%KŇ ­‰ŕHÁ Ł ęe|Č9„.žń‡Ç@Áá‡ęŰčŮXl·ČŮÁę0W1wŐ b•“sW_ĹOó“~2 FuŢŠ‚qA7:jsŁ/@ČěÝŮĺxßďm^p›íĎGźŢ&Ç@x §T”ĘĹqPűÂńŃČöą<Aťń7ńKA"Ő($ů}3uĎÔš$°:4çÇĎ4=@«Ý&@vVĄ/ ö/s ęč8%!Xń¤NÖÉìˇ Ž.˙ş$¦!VCoKý/ÄĽ˙Ŕ®1ˇŔT@]ˇě€ŕ’®f°éȆ‘űmם綠ŹübNá˘äUŠ(*CélľÂ… ł¨dÖ´ľ-•‚ŤŇď=Ś SĚLämw}@çňNđN¬4Ź<ˇÂ<µj·›$źĽĽ¶ UÄ&ÉQĎ€Íň’ăŇSăýűő*,†#HŔý€BëşÂy#‡ zʶ~ý§< O‚ŘH©ĐđaŇÔž"dxP«ęj@ťŻ÷”s—uí®.Źc1 1&)lŰł7‚ü/ş0dZ›ĄůMSN”Ł?ŚSfI-±4>.†›%Nk˙nPaă0Wh@ńoe=Í)\Ľkę¦OÍF¨Ůô#ˇ¤˙†bg0ń ¸2q‚ş‚ް§îJŮ+iţ Śđ”ă>´Öľ c|^ÎüŁô/Y<‡endstream endobj 178 0 obj << /Type /Page /Contents 181 0 R /Resources 180 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 190 0 R 197 0 R 204 0 R 208 0 R ] >> endobj 179 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/wouter/texmf/tex/latex/LogoInGradientBar2.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 216 0 R /Matrix [1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000] /BBox [0.00000000 0.00000000 703.00000000 64.00000000] /Resources << /ProcSet [ /PDF /ImageC ] /ExtGState << /R7 217 0 R >>/XObject << /R8 218 0 R >>>> /Length 219 0 R /Filter /FlateDecode >> stream xśm[ne» D˙Ď(ö˘čMé?H~2ą `'čdţ@VQÚ÷ńmŕÚ˘ő$‹ĹâţuÄŽ¨űçÇ×ëĎłăŹ˙˝~˝âQj iÎă륿}ľ,¦júöű9çóő÷ă߯_ö´ćh} 9¦ăO1´sÓ/uÎ:Ó:hůĎëŻüűĺč^¦ožçóWřO?€‹–RŘS[¶Ńř[(3Çyü÷ŹW:ţőę©öí(c„Î=ľ^=Ú ĺ¶|ľÚl1Ä|´l,~Zs†µĐŰ–^F©űŞšCy8*ép†o|Zsöß-÷Q˙xńx ==ź‘ăueá5ěL21ëVrŕUUÄR*ăšüďĹB®mk)tvĹyN·žĂ(Gĺ|ą¬9Lα¬8îCXÔ–,„gúŔ¸GGî矼0»8Şĺ[ʼnTÓ¸”`śÄČEŤć´Nu—ˇ­Xa#/Žb…@fdR»†ZŔDĺžśM㹢Ć˙Âä.Â4ą_âJîUc[†LÚű!ŠčB@ówć\|E=óR.ŻÄ ň\źpŕ ś|ŤŠîěÓÂc˘&¬ ZjÄ˝]G(e)ľ`]˘Q4ZRtIf´řÓz…ňź#‰śż[ď„B,®k»ĘŤ=9JgŢč4ÎE÷Ś×iť1[S4!DńLĐ(€oĚQ´¸ď¨çBańč J ÜćD€e§%ô eń@qĚlh›9L?ŢŔ®rĆĹŇň^wňűş,âź)"1ĺK_T•ňB‰nçm‡G¨’•|ďkE9ßL09ÇZAxg}Ěŕu ‰vp`ÔĎHݓלkýQ—Č×%ůýźĎřx{˛ť2{R`ʼnüü’…Ča€ź¦dŇ0‡É-Ę—Íń=§gŔÄ­zĘD¶Oy÷Α>»ţĚ™)ě<’jpV… ňlvŹa—–Ąm2PjwCrüdÁoJ,řŠkóů^î’´Ď»ĺćnŢ_ś5ß-÷YçŞ7K%Îqäojou?Ŕ‰$vkWĆŮblžRł+űČs/Ű ˝ćÖşĽŔŻiL!ťkQ°ˇH˝Xźަń¦Ě)»†Z§ŢwIHTČš8ˇP뢮Ź7p0®J%ęz&=aJ|,J"‰xŕiůĽ,M…îVa”:µ,A"Ř~žżî})RÍŔĘ‘Dţ~öăąô>Ďq™•ÎAÉpTcP˘qsaµÇ*¶"ŁÇřZU_©úÖă 0'űűµ˝Öş$“Ë«Âă%2‚’’F‘!eČ8ŠË¨^žD”Đ"żʵT%ń~ë:5ŽC´î,1Ŕ5ϱë2®™3CâńĽ7ˇEeQť9b«,xyŢ3\Ű˝C3ýy„¨Zľ'+@2ô*d}Żhk8Žmá8ŻO*U 8»Ş’¬Bľ‹f€·}ʎńŽT÷Ëbޢč v «ݩ͏€€µÍâT§$± §‹ę*©ÁťRR)Őx¸\M˘-ą±!€l,ž–¶hęa»Č9µB ź‰Ő«~ą†ş"…ZwOJĆ·  µ˘g$enęr¶-׸…>(¬¶CÉM˛4¤$Y…eđQV jË]8ťcÖUµĺžQťŚ¨_tZ’É<ä|ŇÄ>,šUś0T’ “ě^F[wńź%“–t'ň¦Ôń”ÔOń,Ş…¨Śq÷ń¸*Oâeq¦×–+»ügÇ÷äüPIÝ®&ŠCůôu;?/_ąB*‰‰}ńwť.đ“ëwEYťŔˇę%á»áČś^”=>>qxSĎQžłˇ»ĆŞG»®lKSéu š÷0`RVw)q0@íKZ jHE„-ďÓ%D<=ýĚ/Ňâ{ÁęšŃČÎ&Q Ć[>~÷͇wy4ÄęA®¤Žz™ąnK†‚¨1®Ęé1Š QV¤] ô:Ć®ý‰-łěhĽ&ŕđáŕ\rČ 8ŐÎŇÝ{&ÉĹ7dj–˛ĹeLj;Ď1“bă+–…Cť;¨&ŮşT˝Z:Ő B¶Hъ듪ž.aôŞů¦#˝i–'a™ÚÁkR(Hµ:Űŕ&˘ę¤wcĹĘ (ŃşZSRJ9Hźi :ťŹ_ť¸?ŢÂá*q»?‘xâŽčr÷|X/čż=_‘®Ů\ě’î{—ń{ąŰÔw“ë&á ‚ůËv´{ 0iÁô›Ş`»»÷8Á×ŰBvV—Ťl \V7ˇof^t”ŰJf­čŢW‰ĘPKł>\4hĹű(ŐÔ“Ş}(c1Ęj/žľsÄHą«N“¤“?·Ĺn©0 Z]™9žĎĆJJŢ]hŞ$Ł i‹űę ¦žíîŚY˝Ö¤Î$ŻLľeź$ˇ>ąä«¬C.‰®ěN á¬UÄĄŃ’>ĐśmMŐשŕŐ«ßäÂjc°J†žc‰ąUü¶ÁÎNZ(řŔô٧ťzy#Ż üĹk}§Ää0`87+ů3D“)¬®~¦ *Ń•źš»¸™šÚ!©ÎU’őĄd(čĘcé5e©)…ŕf÷Ř[Ě˝bY¦H[‰,-§ Ž,Ru9_o¦>6Q§‹KŞ™łňňâ}ł«ß*ź|ťócüß’W>éSZO§ĚFqt׫Ëâui‘äi•ě˛(V2ľęĹĐÔ”žcťŞoů1CĄZťžűÜ»It'őGűžYÚ1Íě‡â}oÜŇŘÍá5NçW—Ó˘ÂäŔeI*ó†!‡ď)Ű‹§K+,®Ó× ąAó´ă ®UŮÇÖÓqÜ$IţFĎśÉíáH!˘-ĺďßŢä•WťcÂ]$ŽäĘeѦú^çź• _ŃÇ ďµúŞ7VË;A,5ąéúÖű—ú`îY˝{0÷,Ţ!Ý3Ř /Í-ćž­\–W–ĄTfôO^şŠ«§1†+6HŇ?;ýF""}Ćţ? yŤendstream endobj 216 0 obj << /Producer (AFPL Ghostscript 8.51) /CreationDate (D:20060104161305) /ModDate (D:20060104161305) /Title (LogoInGradientBar2.eps) /Creator (Adobe Illustrator\(R\) X) /Author (Bert) >> endobj 217 0 obj << /Type /ExtGState /OPM 1 >> endobj 218 0 obj << /Subtype /Image /ColorSpace /DeviceRGB /Width 2921 /Height 143 /BitsPerComponent 8 /Filter /FlateDecode /DecodeParms << /Predictor 15 /Columns 2921 /Colors 3 >> /Length 203322 >> stream xśě˝‡Ç•çŰ÷"çś"9G1T˘¤‘eËr’wďóy;o÷íěěězfvťdkd[–,Ů%R"ĹśI0€$D rîűUťîsOW7/ ‘6Ë3ÔEßşuŞ«Oť:UőíSˇh4j}‘u˙7„˙ůfņBó扊˘B ľŮć˘s,2A•ĺSJâlHá„đ|EÍEY\ČWâ\TfE©^Čä+qfn–˙L G|%ÎĚͰÄp(Á·błs¨Ő5î.!!ä›mfvFgŠRĺ‘Ç[]«DÜbbBŘŰţ¨ůěܬ-Q··ţřnzvZ·IL$„Ăž¦@ͧUĹćtĺ-´UbB˘W"ň@âś]”jÓ¤p˘÷!9ŁNsĄ$&ű6˛ÍÚUĺ“˝ZqăÓ“ügFrš·(¤©™é©ŮiúŚ»KMLńćAs!Ďěě¬ĺ¨ *ć˝GHťšŕ?łRŇ˝Eˇˇ& ŤŻź#bJ$ŮŰŞHă#ü9=95â«89f9]('5Ó›Í5139Ł7ęŚVĹ=úJĽ?6Äź3“Ó"^•FѤü¸uĺ“’">ĎqhbzHźS“}[©t͚˷AÜĐ„ÝČ•’á[ÔŕÄręZZiI)ř?oT~rz’ş-"jîŐ ÜăČäRW}ŹĘ'{îú0:5>=Ł$˘UˇĚ(Ę·Uď÷óç˘ĚH¤ĎŮ©Ů~ý-?:9N6'“”’ŁZŐĄ9Î($&˘wř>îîˇ{h|ý1ŠrrҲü$Ž OŽŃs„IKJÍOĎöŢcßčŕ„’¨T:919;%Ă÷;{'»š›–•ë'©ůŢŮ˲‹Rý,9•mNj$ą,§Č›Ť+1>­ě*Z)5)ą83ß;đ!4‡ŤI}ároQ¸Çîáľń© Ś·Jbb Ú!Őc(ĐýďŹ łDX’’,‰cSwbšÓPTĺ•%D÷GN2(ĘWÁ M1¦ÇŐT¶ü°źÄŰ÷»řĎ•ĹŐ^‰Hč÷śŢ˘*óĘ|ł]ínˇh´ĘĽRßgŤî«ż“˙\]Rë[T[_'rŇçÂŚ\_+‡tĄë&®Ę/źObk_‡]-ËZ[Vç[Të˝;#ŽDJřf»ÔŮÄźkň—Á®08vÝť°ű#2 ţŢ!JŘ9xÝÖŇNBzRZYNˇŻ‰ľĐqť?×TĚ×g»‡úč32ÔVřVţfďí=¸[ÚŚűZň®ˇ{ăĂäç ‹Áŕ”z˛ÁöŢęď™ÄŮú»n;Cmvjúş˛o(ó­ű]äúb¨Â »ęu}ˇĎ}ŁÔÓ“aĆsĽV÷íB4†˘kŔĘůzČ:n 9ä(§ĘĎ`Ţěmďą?ˇ› =«ňÍl‘m@ITc(dŐ.÷µçď\C6úĽqŮJßZ5őކşŇP‹B „ą%FôÖ–ľŽ±!şG”ÓPTé•+ţ8˘;f.ą©™ő~­Š±řlűUţóą;ĽµBjąw§µ»j/Ußg 'ˇý~×°6&ŕeä"›wB‰§o_á?_Xů”ŻDäa?ĺŔ®úfűíŐĎůóÖĘ5yi>úŚqöÔ-[b^ZֶʵŢ<ĂŁ×zZÉ‹F+ˇ_¬,®ńu`>h<Ęź·W®őö 8Đ;H%PĄĘü2ďh… xÜŽÄzĐş˛z_÷ř×W>ăĎ´fŻ7$^ě¸Ń768ŁgC¨R}aĄ×ßł”]ş—Ź>#4Ç›˝ěxëE6&_Yű´7ŹĄŽ6Đ5žŞŢŕÍQşŠˇ7p˝ 2˛×”ÖyďNB×ŕ=ňľ`— óľ †®}ýnKÜ]łŃ›:ßÜŰNć FŮĽ­ŠćÂłFÝhP€©¬)¬XîéhHȆ˙ŁĎ\ćóľ~qácú€FŰ[»©Ŕoŕ@żţ¬ů,˙ůő ĎyóŔ"]čl"GuF9«‹«˝ 8 0†ÚŕáiŻ/÷±«đ ?˝y†>cdyşn‹7,ŇĹŽëw‰…éą–­đŽ/Mwo·őw˛Äňě"d3ň UOŢşÜ;ŇOSrH¬/ŞDNO­úŻt5÷;3ň¶W­őU Śłd0aâ0ÔBsĽőżÜuĄ9÷÷lĂ6oxăČÖ«§ä×qGŐ:ď¬f9Y"Fv_GôrgÓeíÓFµú\ŹÁ„“]ĄE4&˛m^ľĘë:ö ÷Ľ~‚˙üW[˙Č[Ć»3íŤČI­Š˘ŕ}ůÎż~xę=ţüüĘťľî1ĘůđÚqţó{Ű^ńćŐ…1龉‰ ŚAĐ.ŻÄć{íW»[ÉDc8®Č-ÝPŢŕsŹC}ż˝f›h´ŘźnŐ+±lčԭ˴Љ6<=h—×’7v·4+©$f$§BâĆe+ĽŃŻc Ń⬂—VíöJ´´GNúŚr0"{ó4v5+@™č(FX8BĐ#|Tôkqň˘Ń\kJj—ç™.†ăsí׺‡z-=µ/É.ŘYµŢ×Ořţ±źóçýÔ×}+]=wǵ!ń•5>&şk°Ůşô=BbivÁľş­Ţz̆úő €ŽĐf?÷J¨ü=*ŔSőŕ©^îj‚ܨö^ŕ^îŞŢč•řyë8˘Ô\¤ŕěÁDy0AřĽĺ<< ZÁ€DX{sŻĐż?ň3ţüęşýežů \úÓ·/Câ°-1gEqŐz?GN{&[—ŻŮVąĆ›Ăj1˘©9NzuAůÖĺk˝K…wyńţóßďýŽ·(K4A‹Á-Ůîç™ ýźţ„?ż¶ţŮrĎš \z(!„ÂŤÁźĘ>—ŻđC~á Ď_ n»Gź)ý§Ă?âĎŻox®Ü3ÍÄŹ®Ç34®%ćˇŐúIü—ó˛DtźUë˝y0]jľw‡>Śz(g§o¶Ö‹'ś‰ŞôÍM/xóŔö"ţµôtoYNÉUOy—_0]‚ŁĹB%±ÂëŔ`ÚučĆé;Ý“Z 1" ć_^ˇ?=ű’ô­MĽN;ҡ¦S¸1ă‹j‰ζT¬ňfÚŁnô˛ľłů%o¤˙űŕ?óçďl~Ń+čhËy-qęU™·—űtmdPúĽ«fŁŻ[…ô}ôŹüůŤ-/{ý%H<Ňr®©ç6MW1Tm]ľz­§kcX<Ň|łBäÇsA9{j7{—Ź`p0˛C%BV(+5˝®`ůÎęőŢçŐúĹEĺ}…´~mýłľ•÷ň§dí‘mSĹŞÍ~-Źô?OĽC;—úÂŞ§Ľc(F¨síWὨ™o(T”‘ÚۡWW»[ČJŔödŔ mđ.†Ŕ…îęS}6dĄ%¦`´Z]RcäK©ëć}Ě&˘s!˝ú ]őǶöuN(ďł L÷V”T{§{eĂDëŹę6wů=k<¸—¨ŐlĚPVJ:ě‰w•ž%̸Ú`JH€Á÷®«Xjş:N3GK·ŞŻOO~š”ćăh(´Ľď.fLş•`Ľ4˝Š><65ŽŮ1˛%E’P1ß]94ď1e§fřî1a‚ v|fgB´ó•ŇŇ˝»!Đ 8BĽ9ßZ($NĎÍP&̆|Ç0ŢMĚŘ+5%’ä»™;fŻ…ŞŻ|oĐŇ+ä´gi=ôݶ‚Íđ.m‚Ú+ôÝ1ˇl´ůź 7żĽyhÜŢáWŮ ľ{÷ö¶ťNómŁÓĆ}ČľÉ%PĘć DuÝř‹8JáŇ|łý!§Pśě5Oł>¦ěȬÍpČz©đęýb±#ŞŻÎÍq—Á|@ÖôělÔ2łˇ49$  ް·¨˙ĹLŢéÔěĚś¨9K„mĺ;śS§ç<şŃ&LV~Ú/bEi3Í1LNO˧CÉ—ůXÁ·S†Ä¨ŇŔ”¤$ăi.;‚áÓÎ Ęś† [AsŤOMD-łU1ěymô˘°#¨9Áčă!UůdŻĹfGđ1öĎz4wédG†»Ó’‹VEŁqGC{ŤŹĚzt· őgbzrvĽD»˘¸ŢV fGĐJýcC^#Śą¨÷…A+őŤ z$FłÜ¬š‹öfdJHçĄeńc‚}€O,Ç~* ÝV.÷ Ýś5$F•ďë˝ÇEaGŕä ŽĎ9Ă [óĽôlŻ®ł#P LZ¦\÷¨ŠJW†ą~± ;‚ćqµŞÍî`:Çʏw¸_9^îßâqx$.ČŽô8{Ą2ˇĎ–f°Á„Î ›3śE-GŻłS2Ľ÷¸”ěć$÷F¸V”PmĚĐŚÇ´ ;‚çrgஆ\SwŮh˝#ýoż…ÄŠÜbCâ‚ě2tŘ] ]şÁÂ> wĎ] ÓˇŹÄ'ěĄEaG02âîÔŕîný‚Ś\ąě•&‚ŞWˇ*ŻĚk—ŚÁ@Ü⬺ʄkňËŮĎDżhş{‹&Ťň.a3˝ŹiQŘ‘á‰Ńć{íłnź6Şžx™×|ł#¸ÇëwŰb>•s9i™Ţľ ;ŇŇwÇ1&±„‚˘¸kĂJ4őŢ›śp ´1Ťß. ;‰h݉V‹B1`—nö¶yđ”WWy=˘`v]ěZw+ŹSśđ¸«óËŤ‹ ˛#W{ZúGcţ ąčÚëĘë —uAvŹOŹ®„BÖ—5pĎĹ ŐŘÝlűĆöMFu™«KkY"ÔřbÇŤŹłŠ.é]Ý fGPČ…;×˝ Ł­Ü4ĹP…¶’c(%čˇ× fGPČąökŽÄXQPBął206ű6íąÇU%5 ťď˛7ĆbEÁCŰĽl•1˝Z,väJws×`oěo-ŠőËV¤z$>jěHÇŕ]]·ĹJ/ČŽŔ˘žk±¨’¸«f٤i×+qýV–Ëv¨é”gV¨|rą+·ä<9KbI…<Ó°Ťí! 9Ň|cźQTaFŢžÚMĆ=.ČŽ@KaWŤ‹(äنí<€7řńő“lś9ećî©ÝlĚîdG`Nˇ¨ĆĹô¤”˝u[ŚyÓ‚ě2ŕ ­Š1멪 ^ Ľ(ěĽ8¨DL˘~Lh.ViˇîQ[ĺĂÝíŻßfxż ˛#ă,r{v +-}ˇŹoś4rKóWď6Đb±#_?A®‹\Ćpđňę=Ľ/čŕŤ^?“&I™@EO´]˛D9tŹĎ­ÜéĹľ…í=ÖzѸ‰Ż¬}š™Â©™éŻÓ~‚Ëd–fbP6ö™dG`—x ĺâ  /®ÚĹë ř«Ë‡ú„ëH ăU»řOX›ß\=*î(A»VWŮLL>¸z”6qe¼㙆íĆĹŮ‘ŹośđvmÜTÂĹ,%;‚‘ĺ˝ĆωĄ¨µˇ|ĹŢşÍFQ‹ÂŽ`dyďʧ$Q®đˇyG™`vS’_]>,)á_]»ĎX~Y©?|ó´q19’řÍMxDÄw.bÔ¦r_]·ź%búŮŮßNz”p_ýVŻźĚŽ@"2đę%7X]AĹ×Ö?cµ(ě$ţä̱1Ô1au…ËżľÁ¤+…ÁěěçŞuo·űµ¶¬Nş¬Ľ`Č3ćˇhsĚ;ä4çýĆ#ŤÖŚţ‡'n¸ÇKÉŽ`>nljÜŢŔr¶ŕEËánՙۍü=ŐcčŽĘő¶%Ä{ęö•~e—D&MNk°ŐvrĐĹNŢşL‹CΆâJ9+ÇČxSAĽ§ˇţ ‡aŚáxAvdtjüjwë¬-ŃΆ—ç•ČÖhč&üWÔËJ'V,3¦{ ˛#xç~Źý":߀× ĺ’)Ą`v…t őNÍĚp!Ô˛ęĹĽ sákAvd`|H/Ń8-ˇ˙“NĚMÍ4¶t‹á·vmiş5ô{k©ĆFçb±#“ŠSě…®śBC"ÉĆŽű‚ěމžŤýĘů„Y­—¶yŮ‘Řîřň >b¤E`G,żf}Ů‘ąX!.v$ęÄů0$ĆĎŽ@ś*Äď ¨8a;łŽôµüň%:\ęcBÎĐb°!»>ł3*~†OQaÁ…Ŕl©P(~w÷‹%ę÷đ|rá)ĄD’ąňŢu®Ľç5  vǦÍEv’‰†ý]v…Ä$şo4¬Ţŕ73ł##“Ł^‡«ghcüěškhrÔ·Łą˛’ÓŤŽĚŽYLŠŢ*0pűGŤ™ž™tM¨XnJ$‰'{ăĂóéjNjń=űÇÄâF,AĽ{íÁěHźóJ˘7abʱV^YväîH˙¬VŁ;SE …xçŘ” –„·ýř{/'%ŁŹô ÷ÍzHjş’¬|Ă$ĆĎŽ ‹uőĆ:š`G`ĆKł ŤŽĚŽ@Ey—ÚUu˝R`ěł#pť=­jEŻ2;…ÜŁ÷›˝ý¶$3ß0‰ÁěČČäl(™ ‘§Đ]Ş6•®źŇ¬BĂ)_2v=ńV?ŁpÄŘá[iíďtöTLxŻ*żś,ŹĆAĚu»z‰)î·LdGZúîLĎřwíš‚e,Q«źŹŤ†3vjź°#ś…iľ×nWŰÓúx@d]aoŻu·ßRvL™V•Ź`ÉŘ‘.UČ=ß"'/CŁÍyÔ6îrmiť1\vmîőHôş˛zĂOfGZő{ęr7‹Su~™±-ĚŽ éXŢŰŃ™ÓVŰ[ąš/ąď;ÉJ±@…iěj2–zá«Kk)3ÜĽłíW˝Ř®Ą˝ĐÍ« ç0ąÜyÓ»Aëd®3Öh‚Ů#«r/Ď-1޸ fG0äťľuyžGݤßR…86Đí„AŰş“m—&

Rě&ŚÎ»Ů®p`ž®Űj\ fGN¶]ĆLÁř •»Łre†ßr¨ÉÜá`‰űëÍýď`vä“'ĺśW¦g¶ł°%cGPČçÎJ˘i‘yWŤťťÂ»%LŮ7-[iěł#÷ ±ĺśÇŃS “—ݵ›č3´ÝW˘Ą7Ś‘%cGŕ÷~pő¨ď<NăK«v“ëČŰŢK¸uąkł3›żńWŰźŕ@˛š5Ý˝-Ý™ę +68[&‡šNÍ7éŘ_żµP/ÜĂďŠi˛{´…DVł+1,‰}$úMăç–_‚ů}qµM`Ľ»,ÜT‘˘đ—Ś7§ŮLü%"‹R™Wě”—‚Ůxˇď_92jÎC•‚'&D^Yó´áŮĆĎŽ@âĎ/t)ˇó ~_ßřmŔ…ţĽĺ‚ĺJv>Xic;*Ä·Ďtż¦e˙˛^ßôĽ-±·ýş¶_‚Ä=Nצ´(ě<´“·.‹ ĹşäBĐćsČ_^˝‡Fmx×?=ű[ç˛Ë8a"đíÍ/?Śź…˙Ĺ…ľn ×ËBśˇßĚ Kh8ůÁěH×`ď»—?ĺ˘dqČüęÚ}ôVBÎ#d‚• Ů4ćoť˙PMün}Ä/ł#źÜ8uý®˙ŕ™úí‰ĚŽ\ëiűä†o×¶PÎłn;°”ěÂAMö‚Zďë űđdŽ›yűÂG\±ŠńúĆçŚ9Q0;‚‰’U™ ™Ťč#Áě ieĘJIç®tĽő±6«˘qěĆüŹĎßžgŽfý宯ş`v#{ŁŃäh»ża›}dQŘŘ%ąđ"Mě’±Ŕ˛(ěFv{ ő¬ů— 1trfęď>ű©÷KO÷ţfď·iĺŔ83-Áě.`v|Ŕ=_XJvőÝ‘ţo}2Ě ±“ŁÝŞŁ|ÝŠa!jÇ„';peoô޲K™đo]Ńr^ÉüĽőüđÄĺPĽŹŽ˙ˇwd&+K81= OŰU!§ĚÔH˛ŃÁdG0s´ŽłTGćú˛ZÉžŐ•ga1ŕ##9ÝXÚZię˝Íŕ», ˙đ’©Ěě|ëĂŽô÷ŹLŤ ŇĂâg…)€Ł `GĐŞÎ–Š‹Á˙§D’ŚđEaGĐ/Ś·‰¸5ŕ™…QG+¸Wíxo0śIr·|0;˘w˘g,É]čŢ=ľGŤqmşż|‚ŹČô„‰%Á‚DI U~qţ˛(ěć$b‡ăXníG™¨C€8›^úÖä"2î‚¶´gśS6,§wÉýÚŽP‚?'ťŤFKź/ś˛´d u ;Ő}‡$FchŘŇÇĐđ¦lB(,wÁQ+-1:15)«! OIJ–4ç{¤ HŞeśŇQy¦m¬EbGĆ”ÁµŰ'Ár$: F<ěŠűÄŽ`<`W ·ŚÚâO^ݢłQdţřŮ4/g«3G‰r=đľČź vÚ5,ިŔs™¶ź>őĘ„÷–Ă#ĹŽ «ö‹HšŁ ɦČK˦'Ë úšE†lI ‡sR•—oibĆVéH(Śf”k:¸ CiؔϷ¦ŕ§Äč[¬žáDĂ/‰ź10“§ŚÇĘ‘–đH…úFŘ“@›CÉ ÚÍ•…{ÄÓď·ĹOô#° BQfţEsŃî Yoř¸ĂDP9K“Ć=ĆĎŽ Iy¦— Z5U«®Ý޸e°`G ŹŹU4;% Čć]˛Ě‡9Á­ńGÝä[Jp#şť{†í}ĺ¨V'8Ü<(@%Ś‘vżjw nGb‚”I&ItŢKVŃ€lfS"ɆÄ%cGĐ\lŔ“up#©ŘE™ůŇŔł#ĐnU4{~Zvßč · L ť‚ćwHA¨4_6ÚAö¸`v÷…ą%ŹěĐä{#,şAş§' ŞâA˘4űËsKĄ{ÂŽpŠźŃÇ=ŘóXxéą÷Fďóä 9i‡U4EäEb5CĘsë˙Ұ#°˝Wş›ą¶hsää΂±lMI-Ś6†W~|¸X’UŘ5ÔËż‚u2biÄĎŽŔZ˛9…DtüÎÁ»H-–źžSí>é#€™ś™ľÔyĂrŚz߀ @jwϤHdmiťôľ‚Ů<~o ßž$Ń•Ĺ50&(Ü^LŃ"ËsŠúdžX"~bl*ÄĎŽŔŇ6vĹBŕŁó:g4)’D [7{Űů˝1Ř%o˝Ŕ5¤¤&&ńXŹ_nŞX%‡ďEaGŽ´ś“î*Ü5 T V9EÔŘ‘Kť7…ÇóŐ|/ěŃLŘ :ČRťHBD«D'ćDŽ ťM›Ž;o° AË@Éő[vZ_VolŐ°#P‹7č3ćnŐye‚—UţŇVw”ň%cG „ĚLĂÂd§¤ĂŃâowŐlŔO`f^Źídă)Ă>Óä(Ş'&2˛…µ;r¨é…gŹę•âÔ¤Ů;v×l‚?‰^;ĆWWuŢc[ÇÉĐĆ%cGđo:Z§ü·ÜŇ«‚z\U\M]űĆ#<6ˇű'…#LZGŐ¶Đî4á_ł#č_ě' ­`á:OcÖęŇZĚě {Ľú#1ś(śĂčËköÂnw ŢĺÍ'ŔŽ OŚţđôŻyEENf&§ýń¶ŻČ˘‚Ů‘ś|—§-‚[Ć ůÚúgäşĐ’±#p$~~ń ˙‰Îw\§ł>-=C1šřŮ‘ŽXúŚ´±|%ď7“DôGYT;293őŹÇÁs4Śqr“ŻżŘůš\š fGĐgyŠDÇĐČYŘUO­.©…Äď{{‘¸iŮJü¤WHü˧^‡DŚ)ěXââÎę Ç[/ÄęYZű’“c˛#đIţűçoóźÜaBdKŚŞ™Ý_í~]Ţcüěü™8ú˙ą«z#ěOŻł¤ gěŻ÷|S?;‚;úɧkGák)‰Î8¨‚[˙»˝ßƧ#ÍçŽ: .bD;*Ŕ=µ›ŕ¤áĂ;úÖĐÄ(q 0›hěn9řTB®.;‚ˇóăë'i×Ć †čFď-ň´ń vr´[ŐE›[pJł ••p(˘“1Ăďť¶4„J˛ňǧ'F$7~OíFxż¸5˝4ˇr%&„+óË0âčĐęČĐáb0ËpW¨¨Ě¦şŤ* ó­(Ş’Ăq0;µÄŔJMmO˘{çb @­ä¨@†7zÚ†§Ć(ꙜH T‡ę‚rąřĚŽôŽô÷Ž Ps%„ 3óĐýçôé<ČÎK¦śŘ< čaČ!=ŕď©uű™Ęť¨nÇ5« fGş‡úć˘4—W/áŁ5Ćáx;0 ¦rrp\vQl<©]`ąíť—;×ńł#Ć.-˛1ĺ}áqVN0;˘w˘ŁT›ÚÉ@ţh=cŰýQfGđ­ű;wÔ¤JţÓð#NóEĺUăětw Ózµ§Ő‰í-ČČ…zÜîďęÖ[Ú…X[V?«đػݫů«aüěHso;ëJ^]Z ýżÔAJ«lÂzäxkÚó…Ćáa(ŮAL8°#hŢ€J • ń±Iłl…ěěś„¦Ţ&ě®Ů •gS`„ `GđĂăúŁN+Á뀢ň;”Lˇäř“µŽÖSŐTD–ŰŤlŰkô‘4Ä‚ĐXXZŚŞňýuËA)€QAG`uµ`śwT݇Ä­ŮuDáčPî8P<#X`ůţúžÚÍRb;˘ˇŰä¦$&Ń=~ćěűZ:xÔő…DU žrüIš»g¶»ŽX»Ş7ŔsÓË‹zĚŤZĄŮ«„IŹźA ň¬ ¨,$š‹E¨DxÁ÷QcG~+!Šî+ŠţÂ# ¬Ę®j×k;˘Ž ’FĂKDEż;yëwĚýő[1O˙HČuŸĚŰę™ÉéĆ›ôěě wm(áúňŘOMU*á =˛4ěŮĂB{÷ŐmAĂ#ŕÍZtźm•kÔË— ‚J>żr§ żˇat#ôH;b±ě%ŞýőŰ`=Ž6ź»çěŇ‘4č,lL`!÷7l#<‚ËŮ^µNž"±děČ»—óš ŚŚ T‚ń‘´Ää—Vďr\ Ż®ŰŹ©ńÁë'ť)9Ç ĺ1ĚŽüËůůó–ĺk`áĆ4ݵ7ą)ôtňô­XWĄ˝şŻw,mÎ!ĆŻŁęPŰhĂíÇséé—‘uPÜ*Ú㡄>Ł “xĂ–¨&2Ví‚FťwĚ—Šu±á9< ôPgˇ\YN©´ě†$´*O9źiŘçä\űUVÚÂLäß~]j‰ßŘř<Ş_]:ĚoDě¨Z/Ď~ `G`ݤqxiőnř*źÝ<«GmUzč^ń‚Ů‘_^ü„GUŘüĘÁĺĎţŘM~ÄĎŽĽyö^(Řş| ´Î$Űj4Îw¶Ľ¤Y}őő Ď›E;ł­6BŹł#?9ó»ŻŰ–ŻŻ·„Ýi¸îßŘřÜžOnśdsôÝ­/C—~uéPż#ż’›îńł#pÂŹ4Ç65˙|ç×,ý8xŤ™ašŞCmě©|$ ť0ĹżĽ#ľµéŞúń\Ó®mYi1|ĽćŢOňć™,Ç„ľ˛f/\zŘsöL`ß^Yű4ţ<îŕŞIáČźîřęÔĚôŰ>q–aĎ׊?ěĆ‹·Ď3ľ}}ăó0ΗyDŁ#iÎŘPJĐh;$ţÓ‰_r9zäG§mżö…]Z =lëëc´ő×{ľ%›"€]ŇŢ‘Ş4Ş„Ç193ýŹÇcÍűâŞÝ˛k°#ťŠ9Ä‹ßŰö8?=ű&QŚĐ#KĆŽ`đâ×!ŕşŔ`b ůÉŮŘî˝±ĺ%9ĹĎŽĽwĺSCáA÷0ĐH*=Tk `Gŕ©~*ü„˙°˙ŹáŐ˙ ༆1k“čě\Žďű˙ůęş}0D‡›Nł3ĽLç‡ý?|ó4µMr$ńßď}pę]~ńl_ť:’ć'ßĺ9Ú¦Š•p'0k{çŇ!ş‚ź˙oOG®°#pÚy*‡éŢżŮő Hü‡ĎßVó]Ź—Vď’Á´âgG>ľqň¬ÓŃ0&ţŮŽŻBÖ:ô#6ˇŻmxV®•ĹĎŽÄ‚Žč8Ö0ř·źüP_PbßŘŠüĄ˙ń“𬠖°01O4őŢţĄňýďOżvƢ·>Bˇlď>1†.;EUj¬w"ˇKÜa6GłÚëÄD“čw”ý·÷>aBa*1;nîkעCäsbDSNŽ˝E‚-Őçôťźž$.#l&f÷Çië]{mYMť8 ˇ6ź·žçč ëĘęĐŮoö¶w@u®ěÔLéł#;nŚMOĐf+† Lä!‘NĂ!‰čŚłssʨ:Rę‹*3“Ó`‚P2Ő!'5ŁJŐ`vDCĆöA'»gĺ«%Ӳ½ÄŔŽŔ«:h˝IŠ$˘Ĺć˘s·ű»pGőąCŔŽ@KˇoĄ8S…fWďÖ*_E]†\ąÎ?;‚0ňr p†ˇĂ“ŁL~o}ÇĎŽč #SŚC¤ę÷ů'g&ťýĘPDIa-ÄŽL:E…ôaI !Ĺ@ľóńPŕĎ_:;bŕô­@ž°#±ô„ńů ĺŃisHÎŃ-YTv$ÖŁtëQ ę˘ÓĂéâTŚ&QD ŐÁMŠ„ 0Ťh>D\L‰$9ÖXCIH˛Ă‡Ř¤nu‘·ŁşpŞä0tů–łŃ®ę–˘0…Úđô/Ş×ßń§#QNÁ˘'¦§řa…¤ăŔŽ Y&fbu nd–ˇ–äćPüěČŚ*!ĆvPX0´…’¬üDŃŞě~ĄŃí¤ŃV%Ę羀 €tب + žii¶z.xR<7Ćł(Î*4 ~N=şMěßĂ«–†%€ÁCä *r -­Ďň%fĚ pű|;D“X}°K‰Ş6”{şKĂŽŔtKM¨)(Çđ«rWôŽ:1é fGšÄ‹b¸et(ysoě}5¨ĆbÉčĐŞ4& Ľż‚ Čmţ`vÄŢŘpŢřD¨˝Ü¶ŻĐď8K–ĘîĐnÄ˝‘űĽÉ»$÷Éž°#śâgG®ő´rG+Îȧ2仕x@hůČÖ¨@*rOłż—†ąŐßĹF%¶7‰ü°x¦çÄNpMÁ22Gr{fűügü쌢_[X{2ĄÂ‡4qÇ\‰Â°#üUT´>u ŕVĹxën>v­-;-Ë"ż&D‘UqÍŐž»đ¨jpâÎßą6)^¤“cMüěZ q<ü|™>ËYÇ'ž¬ ůĄZMďEÂĆkÇěČAZ@Ăiť‘— -mTe˙ `GZűî°ÁĚVKT,b=a“CÎ{Úúâ$ŻŰDÂr]1~vDďŇÎĐĎB!ÚuĹEçÜź5aKśź™‹Rx[YIJ,J‚ţŤ±Í÷Ȳ#üŐvÄ7=<;bÉ6ýýbGBN ’±Üš˝děČdŚŤ±#đظńĂ* ‹ˇíOAW•±ď&ĆŽ8†€ÚäŘ\ '$Hv„ŕHdGěÄDAĺĄDyúx;˘0m…vžP"*¶¸ěȤú*Ćč;‚jH‰r·#€™ń%ügśě‰;‚g!nĚHJ“§ü°#2ł#”<úě~.O`ˇ-´Q7P‚¦“8‚/;‚”ŽHv¤Hźkýćß>;ÂĽ:H˝]\v$ß ¶¦ĂÇŘta©9´ť‡zđoáBIvÚBA˛#(<;%“Wú±ôtúwÄŽ_; Üá âDŘüjÎŃ{Ť‰(ÝĂŠ"ĹŽhL$ßąčŕ ()”[őěŕv  $Çíő°#2 a"–(ˇ‹2؆/;b"KĂŽ ’âP ‹ö× †Y–SDćH™@ËăÁńVŠĺ°#č^ „R;˘ŠĐsÔÂdžĚ‘ l‹‹(ÁYşňgG,7 ň„á?;Âą­yŘ”‰ü’ˇ0Ý;˘ON‰ą‘KĂŽHLÄ—ÁČ^_´üśˇĘČíač†ÜMŚ“!L„˙lp0‘3·ădG0Üú&ŮŚŐů±uÉvD`": ~µK˛#–^úĽĐá`"QµöD‹¤č&ě2-:;"ń™iějÖ•MŔEŚ#ˇ#K v„€ţ3€‘/;Â)°#—;›ř+fGÜ€HíČR `G0T‘5¦jď­ÝlémÔ‹Bťp}–ÇP_v$KżY勉ř%”Řtg5\Ú`1uUÉŽ đĹUÇĹ1í—­ ‰‡šN‰‹ĂŽTĺ—Ń»°’@ßdL„ŮKosr9¸źđŕ®0˝!٤g ˛¸ěÂD´qěJÄvďŁĚŽ&b°#»Ş7JŔŽ8_Ů›UdL$;ďSŮŕt®ćD1 äaŮ‘&"ŮůjőҰ#řęş/ĽěĄß –ěH‰Hvj/·ÓŘ‘ë=­Lî¦:GĎHvÄŇ«öľJľv„ľâiŐn X;˛·nK×`/śQŕ° *<‰vęâaGľˇ7c väů•;aôxbĹěJlvDb"ËWÔkĄ’áCć¤eʇ6ízŢqÚi9ĹŽHL„Ů< Ęů"ĄvDuÓ`GP"Ľ7¶Ľä`"*a@§aH˛#(‰YĹvÄÁDěDě4P÷÷¨s1°#ĆWÄŽX(ů±#ú«&Bě,đ{—?•»‡űÜęh’I 'ľ±%¶ßŔŽt‹Ż,}˛ ŚłÁŽXµ %0;ÂČyždŃŮůł#çPrŤ/ÂnË­Px’„LÉ‹ËW–dHvä_?őšĄ×^Ţv{qŮő•_$;Óńž‹±ď3A2’)Ír"ě\}1˘Ůě†ÉŠýŰÝßôb"–›ňW6NcG¬@@äŮĆDŢąô ĎîŽaLD˛#Iú¸ÎżděľâMfGţůä;Ă㣱‹‰ź‘_ů˛#‰ŔŽHL„™€ß^;ĆË(ŔŽx1Ë(yKc"ě]”ěţ¤9_|hv>ąI’Y–[$‘ĹeGŕ»đć™x"¶čěČßú!/2;ňăÓ”ŘěČňĽ#8Ť—ůî–—QIfG–ĺ–ŕÖ,=·=ˇg[_";‚‘—ˇ _vdMImafždG^ׇ7Á»;˘Câ1;‚ď‡ĂéfGŕSµőu8çѨÓ-%;˛Í™ÚHv¤:Yb8˘ă€şŘĚUTŃřŘŽ·Ş§BöUĚ_Ʀ&”Ĺvł#J·¨ĘŰŤ±ˇ<«°#Ó“zćčbG,íuÇÉŽđš¶Z*ךůĐěHR$© =Çrł#–{“eqŮ‘HB書ť §[…h/’RüěJ¶O#˛Ój_¶đâgG˘Ľř{ŔŽDíň˙ĐÓvÄç«Gź™žťŽű ěHţ˘ěLµŇ"˛#¨*×öÁŮ‘)ý˙ůe±#łĘR‹`$ĆŽű®Ň—ĹŽXÚ™]|`vD~őر#đfXsÁźT™‡`GňŇłĺĂzĽŘ¨„Ą÷Gů'´by×z`v]†W„żDvÄ DüjiŘKo\ů˛#ěőZ_„éR_ŮđŮL¨ă|éě,Cż°9żkv„v}ĽěDzŚ‹”Ř|ŐN_=0;g„ ÂŽ<^ěHmÁ2i‡—žť©ŃĹC°# ';@~ő»fGĽ€Č°#:ÄHµĺÇŽś[¶Ź,;B«KżgěţJY¶ĄaG`î*]€Č±#ę«|ő•ÁŽTć—ť‡ţü®ŮdĆĹ/ĘŽŕW´´÷ĺ˛#–ŢË”/vůe±ČŽŔ¶ĐW;bi#Ď?ů]ł#pФó%˛#ES?;âDQ_éÝ /;"÷óYv„b9xŮŚJěă-;˛Ż~+FĄ/ĘŽěŻßZ¨'Č;bŮďÚé ±#WÜ€ČďŽY[ZGÎç"˛#(GS Ź%;‚?8ů®Ľ¸ ;‚ô'ypv„ľň˛#PoLÉqv’Żn°#ôCľňh˛#›+VŇ+ě‹ČŽtöĘ 2ÂŽ X\L٤ż€Č—ËŽ"‹ËŽđW‹ČŽ`ętÂÁ˛śÁWrÎő ěČÎŞőä´<;‚aNňŕěüęŮ<‹äHŇC°#–>ŰËůRŘř´ŢőěČţ†mpĽěHÓÝ[M˝·ż(;b©ŐKĆŽhëň˛##“cşňÖbGś•Ć%bGR"Éňí‘Ç‹±<;}ń˛#Ó“z—v‰Ř:(ňx±#–÷ÓjzÂŽř|őčł#wdÖ9žćAŮ‘¤p„ęü$îČ“¸#ôů±cGPOVËdGĐ\tŹ_nÜ>Ȇҗwd|jBé€sńAŘčIvJßΗȎ@K»DôgGđ+Öđß5;BgÖ,bÜďń4ÖăwDOë8ŹWÜu< 5ŕł#Ń'qG‰Ź;ňXÇ©)X&ŤÉăwDd“CâgG.w5Ů.Á—ĘŽ8Ůü±#0ĽëiýîŮ´Iľ^˘gÜ‘5euGšĎńOžÄˇĎż—qGč ţóŮ‘M«h„úrăŽlp˛ˇôxĹQÚ$ötÉŇÇÓXŹmÜ4&§^vŮŘ[vJŁÇžđ˛#»j6Ҩ˝qG|/R `GÔń40_„Aw ˝/=îOĂ~YěqfͰ#ú ›çcĹ>0;ňú†ç0`= qG>VÇÓŘN˲#{j7“CţĄÇąâOóŕěf űęT×^Dv}·Ŕ­Ž;‚‹oť˙ĘyĽŘ‘?̸#ĎŻŘI'T.";•`×ńww.ĺWőX_nÜ‘şÂe’xxŮ‘˙zägĽ\˙€ěČ_ě| Łçcw?§ĄżEŚ;‚*ń…ŘÔ!’ľÚÓ˛děČŠ˘ŞáÉ1/;‚ůË­ű]_”™žťAS§¸#¸I©KŔŽ,ú™5“3SłOâŽĐ·OâŽ3;B@IÔľŁä”Hěa=Rěȡ}”ÉTĆE‹ĘĚ:jé{f ňŕ‰Kv¤0= *!Öł#wGúŮN2&â ”PZ\v…§čó\´Ä;bé%cţI)źđ79fwĚ„pqf^˙Ř3čÂäTIvwż‡÷óÁcÂŤóč6‘Ď=NvÄŇłDţLěň˧€;’˝)€ÁŻ”1Ôź™ą3ĐÍ&m(ĂÇ= ;é4çÇ“r¶Bmv¤G„a·Měߣ ĺs`GĽĺw nź»¶/;Rś•/·ů—†évc"–}Í}qńaب.:ňŐé$RˇvOtŢ_–Ęďěď^X;˘€Áŕ"®8K–ţěTŃř„ˇ?;‚I)ŹűľěHU~GůČV–TĂcŕh틵ɆňظµTěČ­ţ.6ňľěžTúśűxšĽôl¸(Ä=ÖUfŠĆÉŽXzí?;B@IśěŚu„+]ÍŽůŠÂŞČ•Óv­-;-ËJvD%5W{Zlk,Ř‘ów®±ź°čěbD%fG DŮ(!ňKµ$LÄ`Gäf­ČŽ\¸sť»Ş/;‚v“[ŕěš”‡NfGđ¬yËOϦŐd;˙üěČŕř0uUÉŽ`¨’š†‹čŚĚů˛#AĐé|ʧńJě6™źÉRÖXW ?ˇÓâ%;BÁHdHöµĄuđ[0DĘçţpěşüŞ’jËÍŽŔr˘/Č]ObG0’Ęךˇä¸">:ě\˛#đäĘéâ˛# ©ŮdąŮ”,ŹYŚG™!LÄ`G^tď>°#];®Ý*Ą:pTČW‘ěČ˝µĂDôî |ŚŽž2ő°ěČz‘ěČN(ˇ´4ě 1"±—ÁÜđů•;$;ŁDŰ·’Yá%”Ř%{3Uw鯭Ćrł#:‰ÄD TDą}xí»Ç_ ;éżąz”FCąÁŽĽľńyĆD,=M ®zćö8ÖdG`X^Ź1Ď­ŘIďQHvä››^HŚAg"¦†ă]5ß»ňX…»H‡wÁH,ĹŐĹ mýłP{ř'íŽfł#°fŚwű˛#0Ľ´?J)€QHÓIÁĐĆi$ůĆĆçO´]bŘNc"Ę`JvD#‰Ńě|ĎnĆ1±#P˘Š‚÷űU­™”ŘKoVńgbG(?ł#0r"';ÇvÂ(ů˛#Żmx¶ý~[o¶‘i˛#í÷c?Ätf[ĺZڶ_€B]qeÄńü«5M•`Rw÷tÝd8)~¸˝r-¬ÍY…ˇh»UNČ*aŇăgGĐ—9ƸĄ·`!Ź·^b‡ľD )vÄŇ›‚ΓŤ˘k@ÎÝąĘýVeWµk5€AKŠpůĐUí“·.qÇÜ_żSćŹÄĆ᪒č~Čn˝t(%°#gn7ň1 ˘#c$•Łü•OÉÖҰ#°˝oÄ6Ĺ÷ŐmÄ#`»«‚.Ąb÷łĹ}ő[áŃľ@ŇŃĽr `G`ŻSČÝĄŃőŕGIR¤"·ŹCŇ$°ęȆŞĘXA»k6Áíä?—†±ÔŢĆa~çg}YÜEŠ8˘Ó“_Z˝GŃ$†CWMKJ=xý8­Dµ.­«öěĄßżçÜőĺ+ŕ<ŢzľsŔžtŔsxaĺNŚ­ź·Ä‚ĽĽfÚD7ŕ‡E•G[Îó( ăŹç‚  $E ´Ń$M˛‘~Ř|žQN"EÚú:Ř|áî^ÔĚżąú9ł)P‰*V°#ÓłÓ Mpôx{Ő:Ě#ÍgyřĆÔcoífhĆ/ş‚Jľ¸Zoi_:¬GýxGŐz s°#§Ľsé˙ůŇęÝđU>»yVŹÚŞ(x {ĹSfGŢo<3€ůËvV݇*ÂP;‚NýmýN6§8ŮKď+łK%„r­»•m5i(m˙ŘĐ{—?埼˛öéŚäTa®ęĘ’šmb?>€AúÉ™Ř}ĹŻ ŔD@HüĆĆ&asôęş}Ń~uéĐ3+„n\{Ń9~vN‹ŚćőÍM/@íyéî·W®áĄIP Śó­MPŐď‹Ń$;ŞÖ®)­ýżÝo˙öÍ0éq˛#Č˙Ż“ż˛Š^#Ź>{Ë‘yĆ\I“d8ˇb~rć}zQe´·ĘŃ!€žűI,˘@ô+k÷!—‘‘HĐ,ßÜřÂäě” Ep`ĺ.8şoť˙PŹPJÉáÚÁ&ŕ‡Ľ·ŤIÁ_ě|M6E;Ő=­¸vUéLHÜô"|•·„úŞĘsVŘŚ#?;ű[^ÜřÖć3“Óyńcö9ŃYMˇ´dě”đŞăĂFĹ@ó“ł°Ý{cËKr<ŠźyďʧŚĂ1îÁľ˝}>ýůÎŻÉeđv3G¦Ž’ť'űĂÓżf6Ú+'Źě¦÷Y M8°ę)Ě`Ć%·Óq®ýęá›§©mPÉďmű >üŹcoóNuMI-ž5OµTx’őűˇü Vâç˙çł"›+€ÁŮÁ€Ä?Ůţ*Şúźżm¤`‚ýň…¨řŮ”đyëyGbĆźířęŕřČ˙<ń›P¨„Ě?;gŹ_ )ĘČűîÖ—!ńźŽ˙ŇrnňĎu”‘˙řÉxÖk‰.v¤ůÜŃ;|#\Ž·ç[ŃĽ íĄýÚPčO··đSďOŚé !¨ĐNˇBKĆŽ@÷Ô"•މÄ8ľ§v3\}z˛´\ON´ť7›áVÁ‘Ćv٢CD0ă2Ą '>§áx&6=ŠM ôľ*¬83#Tç`/ffGöé ¦ UB«JŞ1`ţ®ě’ÎEsaľ‹`vD˝Ö29J›­(ÁCëękWcś-ŹĚ4ë°#ô&RKß[čbsR3¤‡ĚŽ´Ükź™9 ëÝŻ–Lű¨¨„„ß}Ůx ŕĐzC/jÎĚÎvę)ô“âĚąWŔލ7]‡ű™óNßÔŁş ×Tš¸řŮHvZŢr^đĆŔjěĺqţřّٹYÝm‰hÚPvviCz{7¶`ŔŽXv\› ë*Ôyâô c+ó‘eGřŰ'ěozvÄő_*ĹÓ’Ź;béČŽ–Dé¦8ü†Ą,{XŠŽźA‚ůP"ś¦ÂÍÉv#šD“"1ŕ#Aa\±”Ťó%&D|c¤/G}%&«đ!ú°›™iľq´RTÜ[HŇ7;m[Ř㓏…»aÔ›ĺŮ@)IɲUŘ]ů)ŮćČ ¶˙ťš!ł„{âgG&f&Ů´…˘ĘfÉF†Ĺ7ɰ#¸5Yź°Š;+*9’dl“ÇĎŽŕľ$mušvǡ1š7€Á“•ő ëăodpO•G!As‚Ł‚ćL3 ĺ§e‡ô©O‚Q˛f4:F˘ąhgKv3n_Ťš­ ĎĂxŽěůü'şŚdÂĐnĆÍĆĎŽŕŰ>ń­ŐSH…ĐĽhG?!_…IÄă‡cÇ}yf•‹`Ű›DyŰcę°›!ţ-~hĎÍôß™ŠípiNüělŐÔHňęwv=łśđ!śŘ:ě†U4I«+r«rě}ËpR‚Šb‘GbÁýĄČ@ÎĚ3޵Ć_zŤŢ@2ó±#tkňt0 a"fRBEn1ţťžě4 Gäa¬*=1U i-;˘šk¸8vŔV%HűYî=C)Á·wbzMŤ¤Č€RP şGĚŽŘÔhÔ:If#š„˙ fG`ŽÔŐ©~(M1zmKŕńůl2.Ń$Râv„Rüě"EzB·ťăÉţ¬ĘWí†>+,”0:9ÎjV‘[’çÖ˙ĄaG`i%)Bť‹{Ń$°ŔęčYÁy¤'§IíĘOĎ6t#~v¤ot Me1,ü“˛ěÂ2w™ěîńbgÓ¬sd4yľˇcÍ’" Ő dG)˘Ć& C˘?Ş}/ Oe?ľ¨-qbfZbňk1ŘHäÍ*űcŁ™)´Ö#I]“ B 3\=.€1H‘Ľôlřu|ŹD“ȢŘKŻČK¤ĆŠwq0–m­\#˝ÖvÄŇşw‚«ŤŃS:śëËę1Îč7źX"QGc!k[Ő:ü ďEFjÁ…_[!Xě$žh»ČˇŃ[1öĹ"đE’vT«µKôčkâDŚśÔ éIV©Ř$±4+AáÇZ.°¸y.‰‰É´1‰ň”” %MbéŐjľIPó©ŞĺÂ÷Š[śěĄ7–xLWl˝b˛c6gwí&cŤď‘bGnö¶; Qť![úŇkËęËł].J;˘I‘ˤ¦˘čoz›ĐŇG§IŹ×¸Łrť,Ó dGúFOSö‹3řŕ^!˛–†A:u;FŠ`šź–#ńë]5đ̡^?Î3)8¸^ ťĂÓ{aĺNYf;b©-s}:\PTKLKL‘18ˇfäŹj:Ĺa$lj–›D–ądě$E,}$Ť ¶·ĄbŤÚŻź`ł¦î1)•˙ÄĚýĺŐ{äl:iěn–Ţ E:aß]‰LâŻUL‘XüN)11ţŁ5Oëău\¤]”“Pő8ŔXH¤¨ťŤ—÷×o#ňÝËź2)Â3S®ŔWô>\x;bé?mF/ĚĚëóg¶C"*‡±%âłăŮF1ÜP ‹ÄůŮ‹wśÚbÜqquٰ®EÂk fG`rĄY´Ş@ěČş˛úőî®?;3(Ď©Č)‘Ód#‰ż˝zŚÝcÜ#ĆÇűÂ|}]=“ČŽŔőŠ…Ä‹*׺]Lvv×l˘—­uéPż3ŔŃĹř(˙$š„?;‚ôÖąyĐL´%˛Äom:I4Hřę°˝ěź×.§Pj'Ú.Iú٤%|nĹÎĘ<—';bépk°‡W/'űŻ¬Ů 'ó}îD1pŕ ß2f ßÝň˛,3€±t,"g,Şw˛3räyÁčłeZâŹN˙šŰ38 ü'Ĺ&±tđNmL˘,Kµeůj)Ä dGŕü˙ěü‡C漂?)ě§vÄŇx®§ź™ś.#ő~oŰWäDfÉŘÜă?ź|‡˙„ŻŇ;z_ÝŁn=ä4šřŮ‘Ž.¨ Gîs«bşdŚÚěŇ÷Ź˙‚çhh@ĚČxŕ#šD.Ͱ#–v9J–Ą—nä ™qóď{{©-Ć \á0îQD™;÷{$éhµ©bĄÁ…°#(˙żţ6Ď_ qŹSWKéµű˛¨řŮţߎľ%$ć éÉ `ůł_•EĹĎŽ`Öö÷GťnU"Ä«•QÔŤNj“¤Ą×ëdDŘ%ŠďĄă¦ô;‚Ůś4¨4mĄ$&ý«­ŻČŐă%cG0ä}|ý$ízâřpKtäő vr´[Őjox‡BpäúF|!„îFˇ ?şv||f’.ĂSMŚ„m8Ć Á‘Ű_ż+F“S·/ó–|nz6˝ IŘ -Í]ínî˛a T]Ď GBN>#Üf0;241‚r$f¦¦ŁV„Á¶őuöŤ P¶pB|B8(g]ˇk,Avöň^`zr*y›TT~FN1e˛#sŃąŰýÝQkŽľ‡‰žťŐ{:wr8ŃXÚ `G,í®;cSHŻŰ‡•‹˛ŰŤhÎ?;béíłY±?el­ÇÄĎŽĐ·Ľ˘}aŢ#¶B´/“ČŽĚ8Gg°ćË0h=cŰý‘bG,1ż|ÂŽÄŇvÄUGřő˛ĺe. ;b‡ń{tÄ.Ä=Ⓩ‚ŽĐgz„knQçw,z5żEa$ôjƇWíŤDAG¨đIŠŔ'mĽŮ•ˇG<•w±bGĐćă^‰úŻp‚™yQŘWč·X#čµ;bąCŹČŇ‘µŚn?;bąCŹČ„”é‘ŔŽXîĐ#2EufC˙5vÄ=b‰‡ÉÇÓXzö5áwŹ–^Ő%2 JoiÎeş,®žw+=€±t›K^D¦‚ôܰ{ŚŚź±ôłźÄ(”ˇ(#?A«„z$–IOcé曑"T1‹…1ÍDTŐ⬂·ĆĎŽXîĐ#ÎĘ ŢÁk4Ě~;béĐ#Cć=FťĚů)îĚÁězD%cčqčŻa-D·• fGŚĐ#2ńń4–^Y›Ę1\iyN‰a–ŚÎ`Ţ8'Gd'ˇ4#xL0;bąBʏ(CuA9©$ĘĐ#n‰)ą.‰ÁěEˇG¦}Ś dŐ.c‰úĹ'Ě:b=aGDŠź±dčOëSĐKűK×zZDDşXvX`ď.ćҰ#–;ô‘(č}n8ĽKŚ,kKë w4~vD˘psPj‰ëËę ‰ěĄLÍÝNîÉXYlffGŕ\r2a”n8…ô¨·źý&9|č/§ř٤ćŢv9–‰]­Ź§±´›w¶ýŞDŤ9yŽXěĺ=b$#čµ;‚rbUÚĽ<·dą{#$Á=žľuyÚďůxË8Č&ęúOs<Ťĺŕ ޢŕEo®X-_9˛ŮK›ń[‡’‰‚ŽĐçóâ ©8¸łzá˝°#–:V¦CX.ŰDAGč3ž2‡‚3î‘«¸˛qĺ-Ír±‰A! Ţk±=vdfvćđÍ3ňŤNŢ #V ;‚t˛ír˙Ř€ń*wýVšÁ8ÔtšçJ2yŽXěĺ»önŻ˘vRÜ™—1BŹČ¦Ą #ôYdÓć-<ę :b-ĎءGüÖ&(č}–ˇGŚd±–QÍŤ5ćwŽ÷żŤĐ#2­t±bG ńýĆĎÔ±řś #t–đtěP'W‚¸ŐÎ+­2ô‘č}\’řŢ•OyÂ.Şę=ă`2ô‘Ś #ÖBěËw/ö-ŞĐ9žĆŇŰŐ’ć)j±bGŚĐ#˛¨j;D^ fG,˝]Í>v¬ +šymĂłĆň}üěĺ=BÂ(QĐ»…s˙ÎÎ+mlGł# Üą|ŘŽ+éŮ)č}8™Ś #Ö"±#đ—Ž4źŠu>žĆrdc$ :béĹ™źžý­|]‡“7čµěüů7Ď|ŕ»ËÇÓX®lĚĽO»ŽX ±#"ôk%Á˛bÇÓXîlŚ„Á‘gÓ?:ýk5AđÜ@R$ńŹ·ľbl€°#–zÄß|AG¬…Ř‘N7"|ÂgÝv`ÉŘ¤Ź®÷™ćčÖ3‚ŽX‹ÁŽXîĐ#Ć*†tÄZ‘ˇGŚd±bG†&FdŚ™–‰ĚŤÝÍó :Bźeč™’#‰ąëucĆŔŽXÚi—Lžm_Z˝[†…°±ÜˇGX$É5‚ŽX‹ÁŽX2ôgÍ÷ }< ýńwźýÔX“§„9ďßěý6}ÖˇG~CŰô!• @  ;ÝúłděE`hG·>ť­üW:9ď7a¦Äâú°{F“U葎ëv)"ţ­+ZÎ+™§n]î·y!N˙oOÍ&ZĆ|ЉQĘ{;v™9©Y;ĚŽXşw8‹#Ug‡Ăś•z¤«‰÷dcRŐŇVş±´ĚŽXzjÉë粨„P—L9°#–}bűoń3őbů­˘ł#¨’:-á|LKLÎöĽ°?;Íqݎqkx_ů^vD‡qí ń¶L$!blĚł#–ŽP`IşÂů¤ŢCN0÷ř#vÄ—=řM‹ŔŽĚsÄ2<&ěÎ@ĺ¸ć!8b-;‚4ťăSW8Ń;âňĘ´xűśSĉ&Âw'ű!ÝuWąA;3;ë]« kp$$~8-Ţ>§Ň·é>vgnĘXEĺU(ٶú<-óq^ŁĚŽXŽŤ3ÎK˘3ş 5[vDWiFş.™aýFťWb0;Ű= n¶j(5)Ĺ‹†, ;‰˙šć‚söŘß`v$Ş0šqCÁPůĎ˙ŁĆŽXjs\®Ç‘\Ô\R;¸ÇX9N·IirżZ:01"#Y|%5Ăű‚Ů< Ĺ,Ď™łSĚř%Ö"±#ĐŇűăĂž{TĘ“‰u·ń©‰AşG‘ ůé9lL`Ůđh<«śŃĚätą±§ş Mą%&XˇĽôlď=. ;‰÷FěÍ6‡AµŃţ‰›ĚŽ ďôŤJKBş“›–…Ű4Š fG,Ý/d/Ł˘ «şUXbďp˙„Ç®¤çxźx0;bŮ>´ą‹†rňÓłĄÄHgéˇ6yĽ÷¸d쥗_Q±977IGů¶bAv*Ń5tĎ>uŐɇ{,ÎĘ—­ }ľ;|ß0H1ZäĹŮČęĽgđv(ÓZiť`çď÷2`:öH|ÂŽPZv¶·­żCŐÜ5˛'@]ĄVc‡FřHTją%^­^2vÄŇě‚;@űK{ár źĂw‰{„Vx˝…EaG ĄmýťăîA“˝ş‚ŠLŹGĚŽŔ€ßľßÍg đ ”e–{lE0;b黆]“_Î>-$¶ôÝÁ8ë¨:oűÇĎŽŔ…kîmw Zb~©DÇ ĄWşš |viEq•·ł#x­»ŐX¶C Tç—{{n0;‚‹$PňPNMÁ2Ă fG,˝Q Őšqß#înui­ô0ˇĎöéb‡ í_#ډWşoňg”P4Wľűí%k!vÄŇŰĆ=C&‚ ű,{.:εž6§űDYâÚ˛zoG fGĐMwo;»Y1ŰTĺDa‰°á§‰ëĘęĄůęr"”ȢrRłÖ—7hQŘK«„4$v ŞhĚ)5v„2śkżf8ä°'ëJë˝ć+ËqňÖ%;MĄpBduIµÜ€éî»ŘŃ䕸Ąb•wŢĚŽŔÎźąÝ8ä–6ßPŢŕ"—ڱ´Ź}Ą»Ů`s[ĺšDńľ <iL(Áł2Y ±#$ńrg“1é€ ˝˝jť”…—ŻţS‚×áŐ±%cG,ĺk»hL¬ŕË=Uµ^Î)T„ńv5% UëËWîq0;B޵žw!ţQŽŕIëÔŘŐÜč#±l㲲Uʶś3<| C'M+lř©[—•J%EČÚ^µVJ˘\čýőŰäřrUśeĂůŕďŞŮhŢc ;b)Ű;ôIÓI5j‹‘źiŘ.Ťůyq– 'HÜS»É¸(ě–xíĽŽÖ&×…ë —ď¨\Ç{0đ´Ţ8aÔGÎF1ĽvB/9Ćşާk·ǵě&/‡›Îď AFŰL1=ť×ĘěZuX[Z·ÓcĚŮKĎ#޵\  Ş\rľ¸r—l®Ď[Ď{;&[–Çć€>i:ĄŢ× …Ľ¸jw™gzĚŽLBbËąë7:ă÷ާŞ6ěŞ1;Ú˘°#řńŤ“±µÇ„ů˘!‹ÂŽŞ­}÷ ćł+¶ËŽvw¸˙_ÎdĚCńhľ±ńy9…µ9tă”ÁŽŔ=;°ę)c©v)ŮS¸p˝Ăý’“Ą“ť9Ţz€dG0ß\±ZFżĆÓŃ«^.vdYN± '6>= EĹlB˛#‰ ‘5eµ2ě($^ën™™›“ěHFJÚš’:㕉Ů {I*JuZ5%Päo‹i†fFWlN‹#‰f¶YČhNź}v˛ůJśqL Ák•H"Ě®Ş–ľGmÝ|,dÉ}»ůđ}ňŽ#Q„K1ŠŇXTB­đ¬˝–We››Ó=ă]yŘh]Ö}źŁ\ř6ŽăáD0ŠĺôJßť*H¤ł~ ®D/ĄĚ#Q®rÇńp"ÔfV©DHĹz‰$ůfðÇ{p˛}[ŐŇ[éRâ|| Ç­…,ßGKo®Ě8¬@˛b3}$˘ĺ'¦'©EÂáäHr˛ßs„—6=‹ŰśQ‘xĐ\¨ľ:F$ „FT ü$/KDI.÷Ě·ŃN1] đQ±´D˛ÇŇhfÖŽ”š”컯NË­ę]Ź „ĘĂQ#‰č>é~ŹEQŕhüňŔU26_)ˇIÇT‹Íhh,‚Zy7‘N€B¸#™ÉéľćWĆg†g6N$yBżőYH™ĹÔqzf:W)¬Č_ó+ážÜ´L/\bŮMđ=f¦¤űš&Ef&yŐ·ąĐ}đ€¦f AsĄřvŰ!gĄˇÎ°6YóH”ˇqQŽoQx@Ă“*$,lEXőşŞZâ4™‘'I? _+Źś'ä™ÉiŢ JętIgŕËOĎőíh:nŤ­«Iá$ăEOJhsôrBQHzrš×ő·´«}/őÚ'˘µ™›śžRg„%&ć¤fyLG.™žĆ‡dĹ–Ąúv[|+5DZS˘Łľ }  Ąá˝J˘P1(ň#OZRjžźÄ %1¶…éÝÇĄ48>Ě˝}Ö8rC!QEâřL(C·čÝUĄ$&+'ÍgnF©MěÜ—dxÁP’hUÖĎÓTߢş{Ç`â7˘, řJĽ7zdb|tj,E3Ž(ĘkW1Ţő ÷Á˘z)ú(1Ce$>SŮ @¦F9Î¶Ž cb”:b‘rÔ;čľ–\?ëBCô‰c>ĽšĄMrŽMOĐ4µ(#Ď·kßčáůj~zNľźDrç~2eigŻotp`l™1×MMJAăűú ΙM*ˇůÚĄűăĂčÚ( 3Od(HĎńµ9ČĂ” „A/ěĘOMtßĂż¨!zYnjć|{{°ä°ŕ ![iVoĹ$¤…r|‡!KżľĂź+óĘ|­@Ĺ TČP’]ŕÍO-?:…ÁcßćĄgfäůşLWşšŮVçűKDś“ qŞ(3Ď7[k_;˘Č㻢跑>dC QHQfľŻćô ÷łůB6/s`i×9pwdj ĄˇVPBă”J `jd$Ąćgäx‰K/&B%F'ÇŇŐČZž]ěkĺĐgő“jłâĚ|/$d)•躉8KÉ©éąŢŃ ·KśpŞ3ó*§¨ŃŰ÷»G&F§çf3“Ň 3óüłMŚĘ˝ď%IÁ¨úeé7óřóĘâj_+1,âůf–^»yŻ9áŔÔC硄?Gôd›XRí»l×ÖßyWť…7Šo!±<§Ř› Ľ­ŻsHITŮ0dĎ7ÔJm§gë…ú,F+* ő‡đťüÂ.ń‚鲜_—IE®ĆÄ …P’‡jAčšRâE!ŰŕÄčŘäDvjL„Ż@RŮĆGŕ!Ő·k#ŹŃ2ÖúID!čÚCz•í€ëKˇ¨4އ©ćČcjédëşÝo“»\ćóľŽ8PHTť´Őŕ[Ćâ‹‚jĄó,Śż÷jwËŔÄ2cL/Lϡđ:«čű·ű;á`ĆŠl_|{‡<Ć ŮŚ7PY"Tb@{ŹpáĘ˛ŠŞňË|%BWÔëÓȆ™ŕÍ^ëné×!T1sAźőíhČpÚ1Ńh±ť†Ä 7ŕ ÝĘMĎÄÄdUiŤW"¬ÄMEÜŞÉonZ6:Ł/ŤjsÜTl{Ą˙îřɶK죜:Ď‹ŽÄŰ}ęíť)xăő…Ë}=L¸^0¨?ÜuĘćőŰ1#|ĘV™WZ_Xéë“‚”šzoßťď €‘ýJçMňšÔQ•ůeľSÂwo!*˘0ůľx€<‚ĚöĆżp‡`‘Jł ×éC(ŚK‚ĘĂIKÖŃ˝ćkjfN:JS‡˝¦çŔOđm.ćgwÍFßľDkGßČý$LĆÓsĐ}Í×µž¶ëŽź°B‘‚UŢ<¨öĹŽë¸AÔ LśŻ;lG)řÚ<[ÚČsO#2Qăp^6ńç›hÍĎ&^č¸~Gąľ÷“Éđ7VWűfűěćYäˇĎçE=(˝}á#!q‹ď4çüťk°öí÷{ ő<Eůfűôć™Ţ{ÍduI­ŻD ŮÍ÷î`”™ś™B!«Kj|Ť †ŞĆ.›bD¶}ő[˝y0¦źkż†˘ s%”ł©ÂgP€DôGäÁTŮ`ĽQäŃA"UQ…™ą°öľď1j:ĹëBĎ4l3ŽĄŰuĄë&Š‚bDXSRëë#Ďe‡ůŔśý'8–‘Ţ<ű~¦~»ď ¶ Eˇb¸Gµ¶¬ÎWâĺÎDů^Ýůń™÷ůós ;|%^îljş{“>Ěą}Ö› ­zęÖLT ßÂŚo«\ă]=Ć·gď\íîGGĂTČ÷-&Ťä*ś+¤b‰ĺî®ŮäÍcé7+88_Cq•÷53Jżąz”6ĐCVhkĺß1v©WÍjűsҲárTű99äČ jGßÂâ6˝N˝P4<gu6;%cYn±/ńy«mŐ{®fÉéĽKLÓ“í=öęYa:L“Ż÷2#9Ô:ü|Ď»O+9I©é‰)ĹY޵\Ě_úôňĹÄĚ$-CůŞýřô$:†Vő]Ü›ť›CC ëĄ{Z2Eďö]·§m!ü˙ě˝÷—Ç‘&Z·˝÷Ýh 4Ľ÷˝J"契Vcµ3ófŢŮ=ďĚŮ˙áýđÎyűŢě›YÍí¬f4#ďH‰EO‚„áŃpÝ@{ď}ß®÷eFUܨ¬ę¨{ŮF”Č{«óf¤‰ŚĚř*˛˘ ,đ„M˘»ÉŇU0QťĺžÂ-äSěîOBčúB…®¶m ÉĚ ÜU-,.ČKZ—:™T§%vśŻÎ˘dńĹřĚÂ\\Ĺ9U¸ Lť=\ sBU_`ŘŃŇkŤ#é™i™Fn®JGÇt”6ŤâÂĹś[itŘ>-3$ö­Ö*‚®ÖĹäËBK…Ńťz,§—KĄ™°Ĺűܱ%ŇLPmáŘ®-‘1%Žřč#cG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"úwCv$˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Šč÷—"ěHDEQDEQDEQDEQDEQDEQDEQDEŃď/EŘ‘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘ß_а#EQDEQDEQDEQDEQDEQDEQDEQDżżaG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘~é#cGlńßţYި6 .f;ĺlŞgÉbş ×ȶůkZZZ`U‹T•MMŹĄq´5CjLqŚ6lŃ)äK[˘X|1ľčŽYz,--Đ0TłÖkŽTO`1UĄc,-]óô[XŚëĆëQŤĹ2Ň҇bnaž?g¤gżŕŽ* d¦g4޲âq[Ť‡Ą[ŽĹĐx4L5_ÍN,=–ž4G(ł_p8¦ĄeĄg7>>żč6 ě2Ňú¨_Ýř´LŐÇŽóń……E—c,-;#+ăěÂ\Üĺ“‘(`hŇôÂÍĎĘ ¬j>>?çö““™Xlrvš?ŁLŕpˇńč&ţg«qHĎÄ?AĹĐx’Š–Śj äŚĎLň缬śô ÉŻ©ąţZ“Řx”Gúśť‘ąÔ¨Žy9Ę*ć˛JóąÎÉĚ śÇÉąi‡Ł ŽY(ć/s sózđÓőpˇmţb3óhý,}F“ ˛óüe0Só3|4 UˇXŢÓ=<5ĆźKóŠËLĎĎÎĚ»ÓÓ łG¤×š˘Ü¬ěÜ ÉAďä<–ĺ/ÁqfjÎáĄQ4ŹXŇ“łSKWvzfnPÁqtf‚żVä—rśťš_Tâ %‘™–Q Ô9Ăüą8·0Pç€ăČô8­,(]Š#$:Ňžť™™ź•ë—Ú¬^¶YéŮ™Yą™}ÄpA*hŮćd¨qTMkÖ«č`~v®ż Ć«cv^qĚĚČČÉČ”šĄĎY™eyóŮ›ť†äŕZ×™E9U-ĚcuĚ8}Ě„ŘrÄpŤĎN‘YF±ň yŁŃé T·3ǬâÜŽł óăł“sÄ1# #(«TH>Ô/ćKň —öŔÄȬ» s e„y¤>bůdçÎ#Äs=ż°޵Źőčç>biu@üň˛˛G“8975Łçă‰éÔr¨jVë2.eůŐ š‡>q8fćŽ*z×7>Č_Jküe@´-nÇadŃ0,˘@Łp{¨‹>`ľWV*LLKĚô’ßZÁ,bTQ 棊ą. â)…¶źšSF • X í@™±™ Ą˘m Ë"¸ĐşGű§]…‰I Ô«ŕ˝Dfâ‡Úç4áją‚¬ĽŇü˘@Ž]ŠăŚË±¸l M~s ť?×WŠ=&ËÖáť[YP8Ať#˝ÜG,˙@MŽ&uŚôń×u• ­ęBI¬J¨ńĽĚěŞÂ˛@ăŢ1ŇËĆËż<#Ö5¦{ZD±Ľ …689281BźQ¬ľt…ż Ú389<>ťŁTä!Đv Iw†{řë†ęU}ěśšź¦>eçW”öńJo+n,­ Ô„ ’|K{8|1˛ţ‰a+>(Ž9ů0C~ލµŤiű—Ą$0Pr†Pfz‚VĘT–*“¶ÁÎIw‚Ş K!9Cq©ű&ďľV—×b­ůË@$Đ*R_Đ6 ?GG=şŹÇaˇ ŇţŞPÓŤöS!ę«w|Őš´¦˘Î_;Gú Wń–kveGhËAµ”ä`iŽ…ţb¨ e ľ´—»˛¤:ĐĂÄšťPZBŤYuaůŠ˘ Č<ĚФ柝·˘¨<Đ-Ä RçgÉo¬+]ČńF˙jÜŞ (°‰+Í-¬)®ôsD{şÇČÍÍĚŞ(( t™`ýŻ÷Ý毻ę7úËXZ÷vŹő[zĽjŠ*k‹+ŞšěGűÇB(U´ż0@V!„j­ÍŞ>˘L ÂÄ~B?ţ?–OCY°á;yű"ŢP˝:ĐľtŤö ÂÂhM5ľ˛$cŰPZg¦ K»±¬Ö_Ö>äyhR÷1'żş°,PECŤwş*Ĺ6®XŘř+=·x7TWRY ,v¬í<>°j[`!ţGźˇL6-ÁńrĎÍ1×oŻ+YQÄëz•Ü{TU_ZhC!„‚cţćšµţ2Păí#=X¶řTXłFMşŘużZł#°ń·:Đ*Ô ©BW¸S8zó,ŢR».P/ai`­‘ú*/(H»3Ü}g¨›>C—ňľŢ»y†>`ul«]Ěq´¶FŤ‡tšˇóť×FÜ ‚©j\Běßąqš?o_ą>PB}ˇ6úŚ(ć/§ëz˙m”Ĩń’śÂuUÁîÄŰ×O%8Ö5—qÄ ‚µ˘Ď(°ŁnC Çk}·G¦ŔqŞ [_ŐŘřÖÁNSUĺÂ"T)”it|ÚŇĽÂťAAgŰŻ »›ÇŐĺ+ń?č%Č3í1Ńx” ô0[úÚF¦Ć`ţ2±yÉ-l®^č:žG÷J5°*8Ý~™ż>Ů| °ńW{[1sS`„A€ ős„Ç ‹kkiău¸Đ°f{µúµ”Ő+C™Ŕ†ˇ*¬5őɶÖTÖ5UÔ6ěŐ+¸í=Ť[ťpěÖ»Úę˘rTĺ·hđŠoö·÷Ś âöă°Ĺ shjôÎj°´oŚb A}D±®Q@“ö5n lü‰¶ Cî­­¬_äEĂi‡čcc 8­ÇëýwzĆȸŁU›W4e1o»ŐJź×U5úíŕő8¨‡ ®xCYmMgŽ×úÚč3”j QŔ†ýb÷ p悜|Ô¶%HE×±Ösüőů-űË€°fŻą~Ş:¸z{ Ç ]×á'@ fçÁIX_µ*ăČű‚ă§·<ȱĄ·­Ĺí#f Q€ÇŽ2p,Ĺ1~猪Ą=Ž·Fá3[ äm‰Ş°s‡WŚĆ7WŻ<*üůů7řóá¦]űpdŁzqŰăţ2`„ĄÝ5҇ý nÉö•ÍUM ßě$w˘˛ ¤¶¤jMy€}k°k–ŽQŐ†ę5g&ďŢ830éś¶Á_ZĘ3ůÉą×řóCM»]Gx/hY4(śuÍűŞţ‰!úĽiEÓRôáoůóv<XćlűUT— ŚĐ¤ťőü1ŞşŘ0>č ZŠů«‚އCŢŻQŐ暦ŔŤvU—»oŇglĐ]·×_Ś íŰővµ(· ľdjóCčUX¬(^蜪 ްýăCŐŐÇ˛Ý ›ü}Ä_/uÝ€gei š$P}×›×O¨OzgřĺÝĎúË€ŕzAQĐg¨-µZUA/Ń–6ŽP úB±×[ŽóׯîyÎ_Ă-· {4ôuOĂćŔŞn ´w ÷ĬF#h†°:ŢŐţ^LOĐá5;ýe — » —đˇPkÂ@gô›+GUśMG÷ö4n4ŽÚĺ ''âr@™ĐŇ…şŽ´ž‹Q!+¶”oß9Ú7<96˝0›™–Q“·0Ăç÷bď Ă^Um˘3łŐ>4Č·‡źĐ:ŘAŤ·”{<0gęĽ:ŽMtF^fvľţSŽřbs„ýc,C…¸Â.{|f‚µĐ*,ÉŔŕv÷p˝(DÇ–<°a´ă ¶´úł<85ĘĹ·ö–Ţ®ÎÎĎ-ÚvZ,–ŁŽÇscÚdÓ°Öwإ҉ŃR ţ‚§ŞĐÇ@m‰Qť‹/P<ł¬|ÁŃ0ŐáăXFZ|Qă)J«…6ĹŽ«Z´UŚ–ťéi* ˝TĐ †ŞsZć!fű&@,<ö}÷0:•‰ŮÎčVey :rżTŔşpŐĆ„@~o)őŘ‘Ŕ ý3´(–(oČÁ8 Ö‚_đWżÄŰ:´o[ž¶©ŞŇ<†zâŞ[¶ Ť7*L¬ A(ăo»Şu Ą¨@ń¸Ż*ł¤Zů¶YĚŔC ńó‹ Ć)mž–áŽU[úŕ~i\…ĂT‡ľL팮ÍĹçŚWŔŚL9ŞPŚ–Ť÷ëŻůřîN7ڍ{›A±IPĐ~ޞ$†=0âššź‰»Ó‚«¸Š@ÝŇÓ¬ 1A='ű–˛ ‰x|~vnŕ‰0×ĂĐŞÜĚlyšéRG˙VĄ™¦ĺećúăUĺóďwJ,=•ăłw7Ťđé‘&-5ŞŘłč`¸ŚŮ\ˇńłŽC}„Űá?1ĄŁú™š ˙aÜĚüÜÄlTa»móź_€)‡ĐĐ$˙Ńü%B𩤡őŤńçŔ3/K‡í)Reé°ýR٠ݞJ< ˛sc 硩Qţş´·4ĹŃ 0]=ŞÇXÚŮ™Ů裡ĺtp„żúc Đ“ÆHŹĄ©=vŠPhEAI S‘čżgŚ B“XH›—ćśéůH ˇÉUđŰ bśĺŮѤ\ĚŇĽb˙Ęídq-Î-đăÂ{ž5l…'Ť’XÝ=n¤ Ű*˙ŔÇřĚäŤö¸W™@$JWÎJ^ĄcÝ˝ŤćéT.ĆĘXhpV—×ů݀޳_´î uCňéłă¦ĄcČ3SpÄXů9®Żj”KŠ·m¨Ëč#ćq•ECťŢě2T486UÖůŤÂĄnî Ž YúŠçzsMS±7Ü ŽmťŇ-!Ž é„rľŇÓęőľlTµaĹi_şFűÜă3]B3Ć$ú#+XĆçćo­5ă—X_—znţš´iE“ä…ĂŃ,ËýĎšŠzčUŮGŚŐ¨ZZnŞiň/´sť×P’¬Öţ*P m°‹‘vLM•őŇńÇ‹]7\őe3Ç-µëü?ě¸ĘŠnGÝż‡‰EÝ1Ü+«Â¬«j”Jş÷B×uéŤ[ÚTmZ±Fr„hAŐk«ťPsXÝëŞV{ čĚ3íWřëÍű­ ÂŕÓ™#Ş[S^çÇaí_ëkKř ®HH%€}DKßméI´ íŮ\łV*¬}Ěă¸đŰ-Ú^×ě÷^˝ň>ŢÓ¸ŮX>ŕxµ· â*ťpÜZ»Îŕx¶ă*űD¨ ŞUn°®Żö´Z^ Ś;B5ÝpU4ęŮ·*8~y\Ĺ/GÝz–BţęŇ»üů6?Xćzßm6 p––:†>ÖvnĐE'Ż«lô‡íˇâK$G úÄnÇt‹hb‰?šgéäťKěAwÔ5[MĽő!ýôÖGŤŞ uˇĂÇf<6íÎú Ĺ>\ËĎϿɟŻŮ‰ …Q+ČQ&.ˇ=XłţPôŐŢÖ«.îŞŇď}ýěśM´U¤ =‘6ŚŔů®kŚAaŽ»ë7ů­í;7Ď0’~cHlďCŰ[Ű` <Ľv·QęčÖ1¶ňđű—G×íńďŃ~t6Ű{dÝž@Ž*ŇÖăFÚ "mŕxôÖ‡ .)ŽQňHÓNÉrmiüBčů\ěľq‰c{eŹŻí޸v˘ßµ}›Âc2~ĆéjÁolĂß»y†m(ő.ôCM»ü›÷×[ŽsI(ŐŔC€ŢńAiűĂ=`€q|çćiyDci$ÍÁUŰ%ÇöáX˙yď^*zwĂ&yfrúÎe ˘µ”¦ďiŘěŹÉťďĽ‰ĄNn[ą~[ęôĎ'^v?ÚOo8TíuŹ1\§n_’¸j[;^łCú0CScGoťU}–˝{lý>iŃnô·źĽ}Ń8ßĂęŘ׸Ĺhąß8FÁ®.ŞxvăáŔĆ˙úňQvů ‘ü8§ËÝ7Éo”çÂ(&ýměŽß˝yFnĐ,ÝG̸ßu˙ŐĄ÷z\G•ěôÁ4/u߀EOl]Ňč„É>ŰáXm0z~ł ř€ţ۫njá‚CűČÚ=ĆÁ)JţňŇ;üőĎ}Ţ ˘Óí—•ź ‡ZëS> ęyőĘsń9KظUPG8/_|›żţÇĂ_äxęÎ%H,}ÇĎřŚÚ7Żź”ďC‚ÖW­:´fG¶É±ďŢâŻyäKFUp ŢÝ=ŚÚăÍűüĐż÷űüů…mŹB«áŻJ3ôż=ôeŁ”ü-Ç™#ŤxÁľKü+¬Ěčăö•ëŹ4íâŻpžQćŞwiCźl>ŕ÷Ó~zîu>mĂÚYĘ3ůßţWţüąíO¨Vp|­ĺŮP>ÖÂ,C*üçr?ţđ·Ěq˙Ş­ű—đLţë[ßĺĎ˙éŃŻGH×-Ż2Á,ĂU;Fz_şđÖ¬w¸ ßžŢxPîŃ -%—KĂżĐTÉV§$}q×ÓFčŢ_(Žžý 8>»é°Áń/Ĺ«Kc·ŕJľú7Śł!‚QCUŇ|Ŕ±|ĺňQ#Śăăë÷§hŰ÷ĎüšYţí“l,2{_X;‡} -8–Ż\z×8bÚRłZÎŕ˝Ţ÷N˝Â_˙ËSbT›mcěCŃ»ĎmRîCa‹ßşvr6>sŢřV˙@Âń0*„hýLcąb2ő‚¤ßňíë§ŕôŇ)=˝°^ž_ŚŐáߣ}çř/(l vOm<`¸ŘuÝq9b±Ş‚˛Ç–p9ŕz :°Ř†KşŽ/_|‡š…üľ=ö/şo`¸ä{ö™iŘ I`bvęlű•…ĹE÷^ý~\c»7:=q±ű:—ńň°˙?63™,ý* ö&ň\»3,:jăĹ 6”ÖĘSďŘ`ďÄGh"±őżŁg*‘ŞŁĄ 6´Çˇ ˇ”_Ó˘·&Üb±UĺćÖ}ŻąřB˘aú%yěÔü~/©$š …ť…ĂŃĎĄ">üůE‡inf@¸ z~j~†ă/ڤ‘ÝÄ_ŃÁąEnĽ#>(#_§_´g2&qŞcči9™Y2\…ˇ_gŤDˇ7ŇŤ¶-8qaŐË4Ť 죊ä ěH`ěŰ8ˇŤé”F0:NđË6H Jť`ôŃ_€ńňđn9×ć/ó{NË„±Ľ3ä ×™ČQĚ#XĽˇ üÓpěń’Ä*Ő¶lW”=Ř[·Šő`\PÍZ¨ŞôtcL±#ř“ ± „ŹhŕȢTNćS+ßS†ľ.ďä±#¨|v~Öj•Lࡓ=0ćkŘł”`Gćăq~OÝ ?|äĹŽHŕĺ• ¸A\vÝĐÎD óî7ězĺ}>xý ±#ôfż|Â|1\†ŰŽŞśqµWöQŘ? "v„^Şökr[ ż1 wĹŽ LĎ §„ë‚đc@ MžěHďř`âřĚNhs¬ >˘…^âč¦AE9Ľ{Á2őžSó¬cl ˝Ž×+ňFČŞP˛Ä,|ěHÇpŻ×¨ąń*ć¨ŕJşÝC10ăĆ+¤áŘĽ;C=†yŇ!Ćé$0asĹG!Ąî QY,ęĆňci‡cGčőß~ú%rÖr‰,“^«+VGČĚíˇîŔ>b¬.063ŃŁß?ó5_ĹŃYó`»nD—‰ %°‡aŽúŘ%Ŕg‚üÔx§ŕ®Ř‘ÖΙ ĂŽţV8vëË8ą°ÜŇk*ęŘ._ë»=ďC…GŽEA$ÚDtYReA«DDźä(Fd}uٱб#“łÓ·=!&Y¸}¤Ç1yľŃÇßŕěHűPĎ ŽCÇcÓŠ&Í™ěČu‘˝Ż-5k 7&;%ßć‹ S˝kă-˙pěȬz+ńZ@UzOnÄ&ÚŰ*Sm1Á-ôż˝ŽQIFű¬ ýµqEâí˝;®Îů´đ9đ-qŮ]bÁ`±Í‚çWö˝dď¬ßhż”`G WĆżŮËręÎ帹iRµ˘¶-µëč»8~rK¸Ś×U5V{˝ťpěâxűâ|Đ6 šp›[”ŁÔ2ÂdéP‡¬⯠ŔľU[ _:;Ň36ĐŇŰćŻĘňľs˙aG‹Č…ćÁCX˝ÝŕŽiělä…ćŃMXŕ%®sx¶ýĘj¶IP·Üŕ=ń^ݧě겕«˝á„”`GŚč%[”äÂ7:Ü˝Ů#M»Ř!÷ć™Ŕ-aŻď ĹpěČĹ®]Ł}ü,ëáµ»‰#v7oß8mŕlPŰ^76‰m‹T#’¶Ö®“&ëĹŽ@/±-3ĆâŕęmĆo8v~Ëë×qqY]}iµ©˝+väč­ Ř.öOm0ł5„cG`8–ZÚ…“ÇŽŔé2{LĎl5¨<µÁ ’Ą;MÂioĚ4}nűě$˙řÜkŽŹíµěĄyE¬Ä$8{;ę<ţ^J°#ř %F"ÁЦę†pĹ™ /l{ĚŘ„cG ˝ßÉ„keŞ ÓŽ™[˙ţé_ĎúŢŁł´‡öW¤;2>;ĺĆŚmËk;`b =ěś˙=ő+˙ŻŔşąj•Đ˝+vä»'^FüNv1_ß÷)ăaJ°#˙|â%ąaÖů%ś‚ăâ~‚[¨)h‰ű˘küĆţĎ›ť”`G^»zěJŻ{’ŕµ?>đ‚Á1%Ř‘WŻľĄŰł±"¶Ř|ýéÁĎŇţevaîŰü4pʶiĹš§7˘Ď°PK)”ټ“2$;‚}t ăp8Ö4±ć…Ň -<-§O_Úő4očľć×.vÜCE9ß<ě¬ĘŃ™‰<úăŔĆcÓ÷ܦ#ňIJ°#Řî}ëč­ ú°*ěÉóqWěČßżű1ódUúřW}I4ű7Ś–`ěX˝Íđl ű"±#1Ą6+˙`óŁđý†ÉN`ÜJf¤§iÚIÉţ±sÁôém{LbGP®"żÔHsWěVĄĐŘü;==}{í::;‚}ąÜ{“î°äŔŞÍNIC™#ĎŘŞd<"ĚH¬._é?{\6ěŚ;˝Ô*±#–Ěůł|-vŽń„÷ťą•S?›{§T\L Ü˙ä‹´î“sÓF(‡~‘ž–°Ć}/i;2ÓÍ(mJ°#‹¶í;_r$--–ČÂŔŔKĚQ EöŃ…Řś`T2‘ĺ"ěźRŚ ŻŤfČ6‹™bíůg<ĺôŚsöpě›M$ÁBÖśFÉGôúqź;˝ŁvŇ#lË` šjÜÎc.łPě“&ÄNü\ÖFşÉVą=­ň–Aťă_Đw—NĹEą,ߍ-ÉcGÜżÚ\@NAVzÍŃôü¬='ZEy2Ľu¦;297c»E«ŚDF†ˇz±#čĐřě$$šwoY˛Ä5+t;˙J8’<ß˝÷v„nŽŕŻč”Ś”ëk)<»ńpěȨÎÄKź•HXö˘ÉňĽbi<±#úŻÓ¬‹P@*˙% "v„o%°,ꥑn!ÖŐŢ+±#uú+kQybX“ď‹Ţ%‹ˇkř+ô֟Ό•ĺ;ůB0/Ľ Ótf)!!±ę˘ „Pç„°ÝňTĺϧŽÁ_gÇ Ő0ţš†ÝŽTÂáŘ‘‘©qykONf–ÔçU…ĺ$˙đ›w!©î$¬$xŐ—VKŽáŘüUŽ*4łäXS\IšüÎP÷¢s­ sD)í6,EqđC…ępÍ8µÇŽ´ uń5géé‹Ů ¶Z˝W{Řą9ňĹbTH±ž±AŢÍZT.mlr ˝¨üöP÷Ľ+|ĆC÷ü"‹BŹ”ˇť;…çŇ5;ę#¶.ZĎ+ óslި—*1;‚zäkÜůvVĄ!Ť!Ř lĚÝY8;iowáq™ŚX†ôľ frłŽŘK^”S Ă CC°#µß^ý€¨8ěńůkE~Éá&O,$yětű׎'8zU¬­1SˆąÜsSz( ¶W®.öŁC’ÇŽČż‚qäŁE¦ťňËß™rÍÜN:âŻFĐ:%Ř‘—.ĽÍĘź]Ž6l%I#vŽo,šÚ+öřBĂJ;Ň1Ň+o&bMHpA:`÷Ů3ÁBQ[¶·=žźť ż"ʇl¨J]&ëngŕH?µá dť)Ź_R‚ůĹů·X3Ă…ž[ăCđúâΧáý˘Ź?<ű*˙ľzŹh<ôůC"9„u7ěČÎü†Ítâ8/Ž}ňľĽëY8;r¬őÓĆW(˙ ď.:;kÍ,=–Ŕô…¶ösń…9qLA@§y1u‚Aˇ}ń˝'J+aŮ™Ů2ŇźěČ‚ë‚Rm÷ýźÂť"›˘4oŕ>ćî™Â±#2c… bM"ěČÝčcÄŽ0Äň>2¦ŔĂ2ä@ß]äŔl牔›pěŠ'% :jKd…:ŐňŠ©ŤŔ‘ŽKl·U´đËXG§ŚÄ;¨Ę›hIě]1Ă=ÂjÇçx(čT}/—RWUĹHó©ĺ¦‘ˇ© őC Ť Ť“í]áÉcGfTҧőh8& nęh@ ţÍÍĘFŻgçç oę‘ä±# ń¸t9°[ÇéąD~Ô)9>Řü\†ß°5°ËăWlźĐ™t„˛]MÍÍpgý©Gî+ěL:‚ľç˘×^Öž›2–ĆŽ`Šĺ ci^1„alz‚EČH=ŽfśNAVa¦dŸâúĂŽ@_ÉS4&+#kH_C¬ŤÔ#áŘěgć]-Š–ća¦k]´±żL;"“Ž`ĐԡɱɹDˇgřĘR٤.qěduů/É+ ™g$şÝŇ7.čI=‚ÁÄuŹ&Fµ¦XaSşGű™#ÄR®ÇpěLR¦2äŁU,´Đ‡đě! ň‚‚I’Ł‘z$;‚Ms„ߌޡł,´PbŐEĺ”tÄr•ďęňÚůxĽk´ŹH©G°g“?D×F§Ç&)[׸‰@B°#2éĄßlV÷¶Ś$8Rę‘®±~üC—˘kŘz±WSe=~rŁ?‘s qĹĆ•'”RŹ '~hă‡k+PŕöP뱕ĹU:Ś< 9Ć }ÄYŕ‡ëŞܤ#aG°˙Ç;CÝR„dę‘pěN:2ÇA/L¶:4ő§ ÁŽ@-kŮłé‡ë*!ŤN&ŰgŃë}·ů"*Čú™×W©ĘTŐ “ysŕëĘZ‰ ëÔĽ¶˘Ă%U‘z$;ŽNŃ\˝*=–~˝?‘Ëż"ż$‘tD­Żl4Őy7‚‡×›z$yěHŰ`',Ż­¬‡ É>nU/s$Ä>y줋şł ä,ŕe¤ĺÁŽŕ‡t§2ŃîúMđŇ] ’F!;b$X˘@K_«/#őH8väR÷ ţ!Ä ˇ¬¦u°•‰?őHvzÉY_¶:pÜ^·5_čJäŐŔa…ʤ#¬ť›nφÁÚˇ~8-_íĹńOxi7ęŰëˇT9Ć€š·­\‘¸éh!ĄvySŹ$Ź‘IG°ä·×5«Ë¤…Qę‘cmřđsexĄ·uČ]ˇĐŔ«× NŽ^uß8´ÔYđ6u}uçu¶/Fę‘pěȱÖs :\Ż~X~ąç&Ƕˇ^6­hň$ѧ¨ŘJśďlaŽ”zŁÄʲ„Ŕ*c-łk“…`GTŇČžŁbHđÍćšµđR.vÝŕŁ|hČݡÎŹxCG!ŘXůÇÖîÇ“Bh÷6nöŔľ b°®˛Á IxínoŇĄ`|OÜľŕřŐ¶ţˇ@ $Źż$ßÚßżj+üęc­Ř“ÇĚb…^ëm»íJÖţŐŰ ČUŰĐT™t\ N?ěhˇóq[ďq®öÄB°#śtT“hővh<ä”zäő–ă®,ŮDĂŮŽ+Ľ^`hvÖm„JĽFiz~öDŰB)B"vD&=żĺa¨ťwnśá'{6K ‚1’ŽěmŘŚďß:ÇzĚH=Žyëú)ţ!DbKÍÚłWŮjĂĺ0^· ÁŽ@!°@÷>µá ¬ó[×OrG×í•[ąä±#ç;ݱBÍŹŻß•(“ô<ľ~źÜ2,väŢdďhŰĘfČŢű­vŤ8ćĘßPÉcG~vţ 渷aËŞňÚŁ7?tw+6\čĂM;Ť¤#źÝţv o^;Á?4RŹ$Ź1’Ž|nÇpů|`é<0»ĐKť®ăĂÁšBř…OIŽÉcG^ąü;«phá}k=‡ś°#ŕřĄ]ĎIG0Ĺ0…żşř.oµ(ődě—­€Ďn5˙RiÇČ=żůayţç¦ň§I;‚…3îZ´múĚ5Łá)ő¬Ŕ÷ŕű> YÂĆżiÚ‰mÎ{7Ď|čZmüđ+»ź»Ň{KiwÁ©G’ǎȤ#°t_Çž[ż˝zŚ üĹ‘/ČýKňŘ‘—.ľ­n«qN!ę?˝ő8coß8Ĺ(eĹßżű~ňôĆpałřŔ§I˙ć #+Ě \‹ž}•7w3ŐÁŽ`ăóßŢůýĚÖÇŕŐüŕĚo#ĄÁŞaĂňץobČŃśş/l{ľßwŽżÄ(č–g7&dű‚ţÍ#_ESż%’ŽĽ¸ W|O\sť#Ü .U”Sđ/'_v’aÄbPhňÄ#;ňOÇ~®a Ş˛k¶Ău|íę؆PL¬_YţľÂŽ`öőĚŞżcO ĂŻÓ°<˘•ę;j!8hŤ+VcIÂĹUG@şí…ąÎpě”Ţđ´€uĆ>±gl°]ʍgúíő˛MG §C űĺîÚÔ¨B,± śł ő¤ʰ‹ę¬Ő…˘4”®đľeĂŽôŚĚ-ÎÓ‹ô?,ăÔ|â #őČň`G0ŞŁ3\4vZ, ćŚĎ´ŃS('énPF,-?;Ž1˝Ň@ż¤Ô#Ú5JĽě _QO),¨i¨MGiç(ˇF2¦t_đ˘˙"ţ*Ą;b&ĆńcGôĂEď„iĚ‘íť×4˙K m–4ku1’d‚‰»‡’–F$Z%î-ď­Á¦Pôłí6•’pĂř"ů®pş÷ş¦ěZĹhŚdf†NŹKAáܢ…Ö°)’.Éű,3u–Ô3'–ăŤÂ&‰A宏eëĘłŃZô›aë>joóD^ľ…îHśŘµt°Š˛&ČWťV•Żt± G;"2‘`.äŽ(;—TŢď_Ę"!g;ÎMbk›RŻçŔ/éb¬0Ş­ť¬©0€ăq#¦–FQTÉť@v{ î#~Bçâzőî`eA©ŚŻW””äaíË‹TH„څ䬭¬‡®Ŕń±¤tuůJ‘›Ä†ZŁQU×ÓĚ'"ßů%-"ÚŤą0@0ÄM Z´Á•veŕiK‰qB(čáŘ‘+=­îř©î¨w…ç¦o%ĘŻ­l -;Ň6ÔĄ MH'bW{[Ő¬%zTŘŇŰĘÚݡ˛Źh!f‡IaĐ7čÝΑ^Ö˘řúŘ*r“`iĎ&c{ ©C°#˝ăĽŘŃ_ĄŰC]¬˘ahËjŻőßć…P]PN‡Ý2]z$ŤBňŘ 8_Ý…źÓŠ–é rŢkݓŎśWY4ś…†Ą‚‹rNôq]Ucˇŕ‚Á˛X*,~ÍĺZ_۸ ŞQo˘$ʇ`G0ő¬°Gß=-Ńĺ–‡^Ú$҇cGdX!QĺEŢćm+×K#‚ąŇ{Ë9ŤµŐI(ĹĺŐ-X&P&§t€.˛hą«É¦A12ž ć’î×Ŕ˛bŤ_ˇŹ—ÄKĚ/m¸”J'@$* ¦6yěČąŽ^hř9Ő µ“ěĚ,)–;ęš±H ¤Čá5;ˇ‹8´qąĐuťÍäM¤C°#ŁÓă„ѡfďmÜ“×9ÚÇoQĂ~\˝_ ÉŮś×ÓÔ–Taѡ;ěă+TĺňevĆ X!Ř’şfN7 ?Ů®óaś×Ó¨ňĺµo]O^o¨^…©Ä::uç?„HČĄ‚Á80ň ţ˝ÂÎHK[v(Ě7Ý€–­Ł#KXŢł LáŐۇ§ÇŻ[“č(YżšÖIż,É+’׺'ŹH0†SFQ˘k˝mwDpwæÓw.óËâđ%šµrříŐ¸žÍ5kQň˝›°˝°NŁJrň´÷ůěVZÖTÔŻu^aO”‡ć„˙ ď÷9´zGˇ†äĘQ}făaŤq| ăőmŮ놼ÉÄ"vÎ^4śŢ ‚1”!@Y>;ŤwR,„OoyÄŇÓ\Fö‘u (C8vD†ýö5nÁBđ–˛ů€Üú…`GŽŢ<Ë j†—w…[j×ĘĐQňŘ‘w5Sţ§ç^ç»ë7É—_—;EôzK"Ú÷Dó¨#ă÷o%`g_ŘéC$‰éź’ b óˇ=뵸ż´ë¬;Κ†&ŃEo^;Éá1x/ŇáI;‚5ČQ[/R(ŻýIŐŞ-ŞüşďťN„ÄöŻÚm “*%ó‰ő€HňŘÇÜÁôSy>ĹB7~ ‚_ŰűĽĺ^Oăö¨ü© ~{őˇí5FżŽn7űéą7řĺ XU I;µĚWµÂ˙'_č;Ó@„'X€? 5ŔC†ę*ýű?˝›@>Ż1:ďÝ<Ë,đ•‘ä±#°Ôě A{fŰŁ–†ňpů†ŇĚéĎľĘ?'±üźÇ~Ćő<·étŕC°#gı8ĐŢ/ę(ôCáŃI•‚Nö‚FŚ0(ĎV>+=óű?-Ë'‰éVX®ÁţŁý/€#˝ńOŹŕIŮN;S"qä‹\žz]ë-Žůs€ß>»é0–v—B~$Ę}ďó2Ě™$v>‰^8¶[ĂăpŚëiţúáŻ`ĎÂŰpÇŽ=Řz•ĹäYŮÂ$±#§ď\zCl:ţË“ ňúµăĽ0ˇĂżşű9.‚ÁńŢKLŮW÷<-Š˝Ăżąĺc±ęGc>hý EąßÔęúś65(Ĺ"aš!Řx•?Ön…,ˇ˛ F°C­ĺxĚahýÉĺPÜWؑ׮‹Űq eŻ­¨§\Ř11vdW˝şN;YĘÉĚněB7©”ńÖD8v„ WSEüX,4}>ćplvŽ€n3vdűĘőéié°Sî«§1,4(´Á9µĹ ˛riĂŘ:Đ99?M,ŕJ§hٰ#w†ş9ÓEeAInfŽY¨)Ş‘ľĺÁŽLĎĎLĎĎR i±4ÂŻË·ľébÉŮiç”#fe§gR¨”N“¨Z°#^ ‚;byá#vä®t_`G,_–‹wEšüŘË{mMv„ţdbGĽÉpŇŤk,Ü<ŘťeDfÚaěH  „č^±#&â<\ô`GDŢŽ`ě˘KżBgĺv$[§'ᯩŎ8@?tFŘ ISXç2B™ž„ş“ĹŽč Ď‹!Ř ň cG˛ÝűĎ&ÄĂ Iz†„‰ŔŘd(łáIOR•—‘ž¨öľÂŽH8ס©Q^h†Ĺ ÁŽŚsb@M¤~@äޱ#U:®ů‘@„;B0ţJÄéą™‘éqž,& ÁŽ`E𱑭_† Ő¤"@n]@$Iěń'xĄ”K_B0 ĐK„ĂÓ(IěHšÚ™TS–jiqNąqčQ ’ăÜ#vDĂDĘ݇ăâá=aG4L$‘lَl´¨©-®rň»P ™ŮŹ—€~HtďŘňţýá[“Y±őŞ'I€üłÎŃ«d" ô‹ ÄŽT(xGbčB°#ť&ÁC‡ŚŻ×)`ŠRň:”†çĐĄŁ#–F°ÉˇĆĂöá^·16Ö)Ev%v«jAféŔ¦šÔżŔDˇd܅ڱĽ‘ěţäÂD(ZŁS|/Č ==äŻ!Ř‘[śÂ+ú¨%ÓÔ#<ĚËν=ȶÁCěpř¬?_]vŁ 0 ~}ś°#ĹKç=Ň“.öjđD*Ďěd’0ßÝ©J@ =;‚‡xÂą” &bi˝Äç’*ËHíú“·/ńN*¨®Tq„rËöD’ÇŽČ8k vOĐGąéQś4)ÚżjŰőţŰü+XP’a¨žGX@DÁŽ@ ĘXčÔ–ńĽHú‚‡XłlC±#Eą…ŰW®—éý&"bLč’2˘ěÖ¬˛‰şYŐ:ˇĺĹŽŔĄi^±ZÜŔ˘‚OÄQ†4 €Hväl{âOĐź„ÄBć‡uĄ+°69–`ëUKGEöń…R&Ë‹=."ÉcGđ'ÇđLDhއ.Ş`˙ęmo];9ďŠýšŠ•ˇ?ÖzžýÔ C/Á7”‰ÄŔŽ@K” W9;"˙AĘň‹°Ýö3:Đ_Z˘ÓžXż˙|÷őľ1Ç”h,ČK7Ő­÷!Ń9&`"{ŇĆ;‚ý‚ «„`Gđ§áhů±#ęáÖGřsvíŰsphͬ>xŻ\~ĎxČ_ď;Ň\˝Š–vŕC˘ä±#/_|›ý™ .äŤkÇY§mđD–;˘˙”UŠÇăˇęç6‘ţaj±#´ëzÓyč`G$L¤Ň Ě>$J;âÂDbGôĂý;ň¸ ů7ń0µŘ(=)á¨ÜÝ=ő+>}rĂě=eŽ4?v„JěČ6÷˛<ěw6Ź)ÇŽ|ďôŻůÂüśňŔýFJ`˛« +^˝šĐĆŘ‘§7B;Â0‘5 Äň>$J;ňFËqvZŕ?»IŐpVJ®ňĂç6‘0‘@ěČŽ•vÖ'Ş ÁŽ@ĂscP9)y‰Ń‘„ćÁŽŔ7¦h7ŤŘźRwph€HÂĐC˘ä±#§ď\.„ýMŤJT“$Ź‘˛‚°#–|Qp\;˘ţäÂDlť˘¶¸ ćŕ‡g°zČ_“ÄŽtŽĐźÂ°#/n{5°B0Kodڇ˙íťďqtDaA•§ń­÷47?źx(ÜŹä±#ňOŘ IT›&Źď+ě,TĚE9Ŕ^ !±#ë«Va‹§“9Řj ö€çDjéřÝ;v„N9,çEťvd|vJň¸•üzhrÔ=ĄTĂsź8:‹ĹŞÝĂ:‰ÁήAe,vdf^gwG ŁHYěĄĂśŻ]=ĆňÉŘ‘Sw.±źŕÇŽPjýÔbG ě'Ü#vdoă–ýí ™bLFňď ;˛ÎM1’BěJF’ę{ĹŽ)F&"c÷Ž‘ZěL1Â0™ŚäľĹŽ‘$±#ňOÖGÄŽ\ňD>>ěČ÷OvdgÝĆß\IĽđ˝ ŘăO÷‚ˇ#Vväg~Ă÷E.väźEŠ‘{ÄŽPf?v^¶Zˉ‘şGě§I!vŔÁń±#ęOÚ ˛Ř‘€Hj±#ü§bG,ď(+väĎ}.;#+µŘ‘€Hj±#Yěĺ&#!şwěÖ vsżv$;#S®ß$±#Fj¨ű;˛×ÝÚHěČęrµôÚ†:— ;˘Ź€b~ěČÄ씻߹Wě>Llş?AěĺM[~bG02Ĺ9ؑɹ™8Ýü„ˇ@;’“‘­ŁÉ‹÷vdŃF3> v$¦’‘|děHléÄü9ÂŽÜ•"ěóđÁÂŽ¨ň‹Ń)’âĆC—c„qčăČ;™Ńń;2:=Î}Ľo±#p8¤ú}ĆŽ`ŘůřďAÄŽtŽôň…{7vł µÉcG°"XŚ—;ŇPş˘obřĹŽ`: «©ÂŽ@śÚč-ä;rµ·M[폀ůťóŽ@Á6W­J!vD^OsßćąO°#ŤeµRó˙žcGN·»×Ó|üŘLÖ‹ŮQ·k0UŘ,OŇĆˡ‹lřk’Ř‘ćęUÇÚ.đO>něHEAi}IőŠQ٬ß{ź`G~‡Ľ#‡Vď¸ŇŰaG’ÄŽ@8Ěo}BŘ‘ß^ý€Ýă;Â_±#On8 uT’Řx’rM}$ěȉŰŘĂüD°#GšvÉŕ°#P |Żč}‹ůĘîg±öcG°Ď‚Łő{y÷Ćék®Jŕ°#X°rr?>ěL]Y’Bě¶˙rň—\ćĂŽ|ďô+|b„‘%v´gôťh)ÄŽŔ!üĹ…7ĺĂ;âţ)5Ř8W_†2ÂŽ,'v›řĎvÄ eŔޤ§Ąfç§;˛¸°x_äY&ěĺIÝŻwÖx vĢd8ü'şłĆ¶ăžňiş.eg¤©0¶çÎ-â0‘Ŕ‹l’ÇŽĚ-,¸}ľłOb^ěH–ľžĆŔŽäxٰË™[—5V’€Ś•ÔΩŔŽĚi޶µÄť5ér(ţ˝bG0&ó°\ě HX,”Őű ;‚ư°q•Ś›ŹěČ” B}ě gÄE6Ńť5ü'şž†żR‘%Ä TV‚±ô†ś>0vËDˇ">ěH`Ň9”7fAbGčzË‹!@ ~…ßŘôÚýpg ‹ÝŔެ*_śĺ>¦üÎőQbG0\Éa`G 4J;‚VAăq™ěH÷X?Gôď¬VÁ^EĆ×Q9-ăν¦x zdJ$vőĐi‘ÄŽ`ńB-´h7aG Í®÷%š‡B,ď¬ňˇ¸QvÖÍ Ţ$°#Đ{. Ä˛> vDĂDf ěČ­vĄ0]ě¶4·:±#. oÔ˙ť57Pą;eŚąŘ%%÷ŚńĂD¬ ‹l.őÜ`— ;‚ ’z8µŘľžFbG0¤aR‹A—iˇ%gŤşžFĎŁÄŽ`$”!;‚ ’H>?vN‘ěHvĸž†°#ĆE6÷ŽąŇ{Ëą˝[`G.t]ggˇd0&;˛µvÝĐÔcGčzË‹!@‰{=Ť"ĆŽ¸Ů|,Ř‘ămxďBKHěČţU[á:Ř‘Ăkv¶Šëi\ěĆć˝cG`iT%vş÷˛€éŕáĺž›˛r?v¤,żý Ľž&PBtŹŘŞÍ:š(±#’µ•őň ÂŽŔCxďćńđwÁŽ@C ±#°ěµwÝî0v+Wʶ±TS]Á ±#ĐN2`ZěşžFźăKě”4l:Ţz~ĚU&ŚyóÚ‰…ÄE6&vZż5°#ŹŻŰ+7)!Ř‘wEŠ‘@ěVy;ňÄúý¨ÜŔŽ<łńđ•ŢÖŰ®ŤcĆŤŤÎż3ě¶tCbG %°˛¸|vŞţCaýwÖŔɡ,Qv$đzšŔ‹lřëG˝łć­k'—rěHŕő4Ů}"Ř‘Ďl} 3b`G("Ë´BW`Ż…'ĚĽË” Ţ9ÚÇ»}¬ 9ď!ŘôZr¬.*Çř ŇĂ1eyĹM‚!‚,A«0Ę  ri‡`G0A,í …b×Ęł€ Âú•OJr * ʦ˝ EV•ŻD%ŇbuůJ}†>4ěÂÂ0Ń5&±Á‘î>hě`3‡=$şyk°C©#7¬N±=)Ű몠—Ü ş’×uUŤ0yX/<Ş )Ű!ŘKĹcns˛¬A ,T¨ěŁ{ÁŽ`ŹÄ’PťŹQ…ŻßŇ×ę”Ö+[šËÝ7Y{7č'ŕČáaôűdýD¶y 4dŰ “PÄÖ6}DF:Ňp” 0N‚ÁčqŻÁ‹N—°Ďd‡ňťÓ¦Ň“L¸OJ1bŕ(1ąM;‚&fřÄ:ëBFÇ›«WIŽÉcG®ö´ň©,,èâ땞V.°Ąf­ôťB°#ÝŁý]îa7Â&-KşŻ«ĄíŠ„´n!رLYŹ6Ăľ`!p€°Vśł‡`G,}tΛIIEA)ŕ†“˝Ť[důěÖ¬ŁBmĄ© ¨ů”ǬŻjÄs˝ń$Šł;ĐKŻqÖśB¨®'yěČĹ®¬´Á‘€/]x[[4evÖol®ZőŇ…·ŘĆéô$ëŕpľ+‚źßń¤˙3ŻňÉî#k÷Hż"yě–3ż-[|hÍpüŢé_sBŠ|G¤'ylÝ^´áfűŃ[gé úň•=ĎŃömţh˙g,5Ao ąNÖČ>áď%Źę~ďf˘ ¸WÍ ¦u5!E^ąü×€ÇţU[árČ+^ŘúÜ·†`G ŮűÂO^ÔĐźťu5ĘďĺC°#hĂ÷ő8Ó}vűpäŕ«°Cż=żĹ5I;íý“9»’ýGű_ŔţâýÖs]Ďĺ >H”üËÉ—ŮY…&” -;żW(@…Ç®í­ë'ŮťFů/ízF˘IŔń?蛹ţîťďÍşďä<»éLŇ?ý1ďň]ż~´ˇżyä«0(ßéIţ÷GľŠ-´[@xˇ/ đDňŘÔŔ I[Ď 8BäX™ŔJ?!;ú?űmţ ˇÂ^çOÜÄl9™Ů¨˙şęő"ű›‡żŽPŞ$B±XL €đdB°# oý‘ĺ†,źŢx=hÚcmUP“'sĚX÷väDŰĹáéQ e7ęýËôüě{7Ď0vÎ-ţôľ µÁż±sÄţńF»Z/şöÔ” ’(;Ł?57CĂ3K»E9ŔGěßă‹quFçbGč4 ž‰ëµŞQ…Ĺď$¸ŞĄ#€´µiém›×"ü“%·ŔËu ÷,*YV„eÔ‘‚ů® /˛°ŘÔĂÍ5`d0ňÍpř!(ŹŮq^1u§*±m›bsôK SŽ«Ş²ĘPĺç@^OЎć9u|áŕhrucf8J«°ň@>yěȢ˝H‘ ßç·ĽŘ‘4ßOS™H\ëEO,;’–&!É`GdáÄź"ěČŇ”JěĺŹĚÜ ł=˝SčNą”K&,Ń˙2GáŘüiŃ‹D1Ňś¤Çś«g¸ľ†>Q1ú%BŔČCI /¦ěĄŐ÷H÷'&–ˇ ęÉĽZ°©q{QpŚ‘ Ăz6Đ0 1“á‚N’ÄŽX:fĚÁŞó † hŽ ‚v‚‘l†ĺ˝-_ÎcňŘpśtß™¶X+Ĺ–\ľKp|±#ŔIŕ€î^°=éjОóńďi1!ŕž°ä’ď+ě&e\äMÁ(ˇ/R Ö!Řť$:ž‘ 1X+TĺIë˛4vÄRť1Qez3s$í”1NëÄŽXú€ăý™Ú/ˇÍ ±Ć€Čá ÇŽ`Ç5pÇÖJ;?+ornjŃv\,puňŘ4•ăĐŕXś[825Îz•@!–>(aq’}$ŞraČ>Q, °B±#sakĘ!äRV±wE3đ¤}ÄÍ~a+­545Ʊ<±É—“ÇŽ@ۇzX™ xQˇ$˝ Ď”BEJWÜîáí%,ese ÁŽŚ©pn1#ăÚ/ť Ą˙ľ9ĐÁ!˝tŤĂbq9Ú‚Żg;®˛}Aˇ(ä\lRŻňŔâ\î·J•×öŹąí¬Ś,yviĄ;s&5X}xÂľTÁ#äĹč#V&4îztŕŰPZŁ`.w.ńP“oÓ;–Pě{7Ë !ŘK˝?ŞîٱÝf`EK]vg¨ ™˘ş@­A~aÚR˛ˇ@! ™Ú ?„]žIŘeuŻŤd‚B8~űoz)$Öë&ý‚=ÝżzţÝ6ŘŐćš!Ü,©ęéĺه&Üá]!Ř,@‘ýBi ´ ŁňkvŕßĐ–mZaŠ‚Î^™#/Ešßo=7“Đ0ęN·ëýn¶-[…BĄ«™˙±¶ Ě őĂ%ŕ.7}C˛ěćŞU.ö ś)ńĚĄîśŘ}l®^ÝŇŰĘŘY™”Ë ĹŽ@Ep+[/üÎŃ>Ţ_hP:>›€ŘüZ ď‚GµI%,i€˝~űú)~Hv\z­Ź¬Űc@8ěČôÜŚĽ˙ÓąŃW¸pO¬ß'7k!ŘĐk-ÇŮ­‚Ň«/©–Öě¨k–z,;ŇŇŰćdtso»ĂW~uő0;g‰#Óô۱é N:‚ĘźÚpPö1y쬆D †î±~ŢćĂF<ăŤm/vÄҡYö˘1ą=ČĎü‚3Ş0U›DŽ+iěĄďób×:3-ęK‘m…Ŕ*ýňb"’MçţÂţü–‡Ą×šěe^>äů ‡âldâ–ÓČ$Ch±#–Ż`‰©ĺ‘ÔH…ţËyu,ď]MľŞŇ F8v$®ŕWq+¨2Ô“‘îĆ2Ó•”Ë@)=hď7řXüĆT%ŹA“´±h†KsŚQ%RMxźnčßä±#–W]¤C¶žÂ"vÄŇ÷°ČQ•s#JwÄŘěäR˛Šć“~_aGt%KI̧*ÁŽXŢkkoNFVˇw¦Â±#XĂS٬‹$©+óK #ô bGćĽp&[Klµ·áŘh‰ľńEż:ńąrc)%ŹŻž±ţ„‰±=ÚĽ¦¸’–|H@Ś%Ń…5ôÓ'aF‰¦k÷ŃXĽ!ŘKÍň´oTťŞŚ k¬»aG „üv˛QuťNjb%ŕ á1Î|ñ#XřwD|Wxa“Ŕ‡ţ·gÎ łóyTouK ˇ,[[RelB°#–>‘—XI(Ě‚Ý:ÔĺŰ(ůÉuÓSÉD’ řŞglPoˇś…˝áHÜčX\\4+Ň´¦˘Žtť›Ś$@GűwMáŘ‘řââŤţöE;ŘĎY[Ů`h×ěĺ\[3můÉVD*úöf{Üč#l7oG¦Çä˘öö1—GµŐMFÂŚ°ă5TbvÄň^[cP©›3t­˙¶ăůFdh×ä±# +Ý·f}NŃÚJłpňŘKÇ_yŻhôҸ°Ć ĹŽXZ$ŤęEIßUeaŘ,Xyţ. bO§xLáŘ8]ç:ŻĹ—pď·­\oXěĹ×Öé/)LŤ i äHâ %Ł’čÂú|YÁA&JŮM•őt]SňŘKż]-Q’’0 ¤]aĹdÂn’îc:ĄQ±ôĹŐí^ŁŔŠ «Ň@&…cGčÚš@WăÉ/ßV•¸:Đë„AK¬qÁ'Ú.ř¬¶CĆ…5V(vÄŇ1ă^qCś$UXźFÁk=/ß=ŬÚfldB°#–ŇĚ­fä©jUůJRŕőÁ­ĺë’­ŢN»ÇDö&OŮ’Ü"™”`ěűB°#–÷ÚvÖolđj×ä±#–ľíBf@”´»~“ĚŇd-#vž_”ý N#ÄĚp“ÇŽx®­ńZ[Ťˇ9D/ 8APĽt)SňŘK/C bdSŠK‡^şđÖRÇ/ĎnŘK‡÷¦}’>–ćűó…`G,ó™3gŃVoBř×HňŘKOPBv¤$ݰ0;Áę´PDĐK¦LׂFęňéÝhă·áŘ*ŕŤi©Ş°f«}~j8vÄŇKĚ‹}qZXQPĘ‚ý×94v ĽCĂŽ±\\ńJµ˛°”•vÇűgމAŠ®)¬`•‚aďđ¨h]"á_#áŘJčBĂ.' T§Ż"˘ŻłÓ˝ăN˘,QµÉ«‚\\ŮGH5«čÝGŹäŘšcCé ćŤÔ76ä7C _R 9čȥɱˇ¬&Ç+üáŘK›Ś.˙É‘NiSć[ŕáŘuźÎH·˙´:/3WnŔ 0¸# e› ŃŐşŞ|%o< đ­ť $Š;"PFLĹşvŰ’ŰC]×TÔ1Gá­Áv•‡Ă;úPżţ¨|J°#PąŞŹ>D¤şˇĚäěD CAe/«ô6FápěÔČŤv^‰L0îÍ 'dnłC°#–† ů‘(¨¤ąj•a»Ă±#–Văńž†Ňšjß4…cG F®öŢšť7Ń6(&^a}8Ľ$Ć—]î Ŕ…@K¬Żjäĺ)˝Ü}ËŹD6ű-%ŘpĽŘuĂĎ"!ďÚ¸3ÜÓn‚ŐŤb\čśě.©1ffd˘d…É1 ;bi$ tŽß­‚ÂŮŕsȓǎXÚ˛Ľ!Ö>ł†tÉĄ-/©a‚ËńŮmŹł[{ń“óŻ›>¶2XOşĐ1Qa °#°,?9÷šsŃŹ5X«§|S‚î}ůÂ[ł ¦2Ů´bÍÓB™@áČ a‰˛32Q†·Řîýđě«ý>4' Öw>mś=†cG,.Äĺ¨p ü¶oćČV™_úĺÝĎ0ÇKKŕB4ľ$ă——ÔHŽ_ŢőŚaeR‚±´ĚÜ9ăWw?gp ÇŽX:™–ôf™ŕÖJŠf«×äĽŘxˇ_Řů´±yÇŽGšA;ŻÉďoßoŘ łí*•©©)©Ü,^¶§m™;’‘ž®ožőh»bG`µáKÄ]Ž–‹Ŕ¨-©\)]ŰP›*Řô´´Őĺ‰÷Ż`Ű»fć ěHNfö겕Füeٰ#–ö÷hd`GŕaúĂ+ˆ±ôv՛ЭJ‹ĄÁĎáćřâ"Úo[¶ÉLKĎÂM5€hNöťĚ¬ŚĄŁ´1‚”ťžeŕ*R‚±‚˛0Ä4Ç47›Ą#w|&,sݰ‘ޱDŇ ăţ’vä®”zěńĎŤ•H›Ë$2h!›ŇÔUuWěUµ¸h{2ŢÄĹËĹCŮN«– HATP)>ĂşěU%Ă 2ă$ť}„WZP xd,–™–8b)ÁŽPăüĹĺb™ęŞł6¨ÔxÜ9¶S¦%]] ĺźî”`G,=×pgGGP1¤qč;bi™Ç8PămGËgúG ˘55?ÍF}ô×fÝŘęăÄěOB˙dfJE8v„hrv î‹kÔpÁ?đk€»bG,=‰hŹ*Ša˙8Ş(vÄŇÇÇ㪏ŽŘcŘ1G~Éż+vÄŇšdXßőC_1\EŮůóěqÄ8(Ž6J¦cTýµŤĎNNĚ$®„t•ĺę Jţ%ŁL2ŇҰfý¸ë°#–·Ă/dŰW óşűć]±#Tţ˝{R`C Vä—ú•!Źą&ŰFú’łŹÖ=`G,”ĂgÁŠ z`rd|fŠr`€–F™ŻŹĐ$(Ćbź‘–2~Lu7ěĄ'š:'îö‚ęď#¦fpjTÝöEѬôŚJłaÂö#ƲJ Z Ő¤Eb*šGµ(· ŞŔ\Ýtç+DÚĎCęČŞË;Uż2Ľ+vÄŇŹîŃ>Ć'é|6ĺyA&&;biĂŃ;>ŔÇč¤ +}}Ä błęF:!JVýµaF„@U+Š* — ;G{ťp»ľĂeěx‰Â±#D˝ă#RŃ`T”SPăăuŠ ákjˇ Á±"(’ěĄősçhߨŕŞü"mĄ;b)ĚL÷hź„Ő …hÔ±#–öpşĆúĺ¨bvęK wĹŽXz‚đ?V&hR}iŤßÉĽ+vÄŇKŁu°ť8*“pěőńöP7í4 "Qę71ŇŰ*7O‚ccY­ż¶Ž‘^*6 Đ$(fř °>7űŰŮű‚–XQ\Q4Ý)ÁŽXZ/µvň‰8Âjű§j°}¸‡UtqNţęŠ:˙ŇĆČ÷Ž‘źKÇzl(«ńűBwĹŽhŽ#7:x¸ ĂKkŤK1\¨ ’ł rc¨¸ߨB’1Źě™@6UÖ*“pěqlěę ?°žĆ SÄńF;ŰP¬}T¨L±#Äńzß!yŃęśŇ«}pĽÜs‹×,8®«lđ{ŹÄö‘Ţ׆˘I›V4ů'(UŘ*EÁYť ZÍUŤću®ń…‹Ý7űÝŰëŕK4–Öřa‚hUKoßhSť‘\ÚáŘK[z[{]‡Î¦»ŃÇQÝë4p‡ˇ!¨ŠÂĎńJOk§{3seI5DÂoµPěĄ]hTÉ!«Ťé«/©Ţ콾„č®ŘK aKßmĺČiÝs†ŞüŰ´»bG,˝×;Ű~•5!,ű–ÚµAK;;B}ĽĐuťArh”j g•ěq<Ý~™Ť#86U4ř•‰µĽŘKGUˇLX/çÂÔú )ÁŽX:ŞúaGË”ëVa¬vÖ(ĂłWŰ;I pĽĄf­ˇĄ;biźđb׍VÁŠ×HŃd9ďř^ˇÝ˝­˝—­µë·˘)ÁŽÇcmçŮO(U™ę7ú]_%¨=­lµŃ¤k¶çűčă©;—e‚>BŔq!)ÁŽG¬ëÄBËÎÝô˙ł÷ć˙q]ÇťčínŤ ± nIwŠ4Ií˛/Š,;ŽçĹIŢ8Ég&3żĽůĽ?"ďó~J>ďM’ĎŚcĎ‹ŤeK–"kßIQ”¸ďűÄJěűŇýľçÔ˝ŐuĎ] P°nY–şoś:kUťSß[UłĆ»¤Űî}Ţr¶wŘI…>î_»Ý+ɱlp~á{!XÚ÷ŻÚěőaĚ v„čł›g ÜuÔŔ4ADĂŘ6NľPÄă|F:FUľ’<;BtäćiŘÔGűşaÇŠfďY{FěĄ {c;*oďę­%žłÉ|aGă±–sśË†ˇ|o‡hľ°#ĺuşs™/'WUÔ=Ütż÷41#vÄŇ×ď]úŚMGh´k·ůâBć;bé+ŽCöšcZ!(Ľş‡0ůÄt`ívăR Ćó;—Ž…fipɶşő[—i^°#–> }|í„IÚy˙gďŞű|µŐĽ`G4ǡŻ€c+÷qďę-F¸JK"?˝qšáű(fh+ ŽK(I`,Ôă«­fÄŽXZëľqRr|dÝnKQčŤ#BŹx8Be@.±y Ť¶oÍÖFŹ0Áf<Örm!Oo<ŕ˝çś/ěâŘrîó–óĚň †¨—ăŚŘ]¦M*GhF/Ż~D“Ž«8Ř´l-¬/DZ#–q|ʆbK‹ËZ»Ó÷úeˇaG,}~rWÖ‹nNLX`Ţűvč2X/Î!:VUTľ˛˘Î{5#vÄŇ÷*·zö’`w4,©[RhZh8G´ tA.9Ŕ‹âĺe5†ŞŇ׉÷úFčî'¦ňÂRß[ŽlbG,m™ôű^4¶śŻß!›ŘKO7†”nc˘>zĂc ăk‹’Ă۰éÔô¸S•Ąoi’ą>>_饍ǬxÜßK;_ŘË}$ˇ˛Đ­Jëűötš!2>GfÄŽXNô†â[ŚjáÚĽeľâô[cGćť4l*«ŁVˇßrq•Ń˙›ąŘ,Şš}«¬€uü8bůÂAľ$"ĎŚgŮÇy$ňŃú˘g~oň7łf|{_pâ 4> 0~[ÂpĄu:óąW…ő Hwţ~v,ďUÝ#X´ą‰ÜlîGpô5%Ątî°Ü™ć¦•öÍÇĘ™RĐĂÔ|­ČA0;ÇTĘ×Ţým -‡%ęk¬»8:.‡đb¨*7‘mĹ·˝áĹF'Ć’ąyáŃGÔ6ăĘ™%GśÁňgâ8­9ćĎÄq–421ę ů„ՕЧđbĂŁA8H¦INR©×*8ęĐeó°$°gSłŕXŢ‚zfäŘ;28f¨˘ýľ€ă/‰čVËë12{¶ÄŚvÂlú8Kš GX/ăĂ^·ĄA)žŃZÔDąyѰpF'ÇJ=h¶/FÝĂ}ľ‘/@ýŁC°pćK ÍŽă ,´ů:XÍa‚ ľ|á _"ǑހKv&C̨Cç‘fɱs°§Ľ°$›—÷|]Y’`÷BkĎ(0!TsŐ+4ŮŐž‘°›q¸Úî᳙赢Eô<Á/fÔˇ=Ăý(3/ćń,9Ά`´ăŕűšĐ—Dšă°/`wQpĽŰßé ůňčN_'G] "X/0¶}AÉ’ş‡zKü!yÔ5ÔëzůËŁŰ}PUáéM3_Tź$CĚ‹eލÍűšÍăŘÚŰô’€ä&ČQýeŘé|qlém ‚0a¸ŔqĆQť%µőwy_–X,4«óKjşĂűűh`l¸(ŕ•i¦éÔ4ÔqĐ{ÂLچś—†Í#ÍĆS}"ŘÄŚ·vÓ©”o(O±é«˘tYv[łŔgd*Qýî±#EQDEQDEQDEQDEQDEQDEQDEQDý®(ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}ué bGŇV:fĹćÎ>íü+¤¶´•iaX1Ő»U±±´.çÔPČ© ˙‹i áiXG]HWX[JTćJ§lvÁUŮŤź©Ş)vq0ŚűBM)őO*¦JŕźxPUT’ĘqśNĄřs"î_•®'5 Ž–Ş*¨ćhŽĚ!ĺâ¨Jń¤Ď±™účpôď# L§3s9¦¦ń?{¸A}śJMcÄP' $Ô$ů#ŽSÓSh:ÄőL§ńŻŞI„pśžBm`‰zÂ8¦¦3}LäpśžR}Lˇ]›Ă&§§2UˇiŁ:ĺpD >NÇ”ćŠŮpTµ%‘‹…ŚęÄô$ÎKäú–ˇ ˘ĎqĹŃT1Ače:…aĎE/ý8bút±Ib‡’ľň4‰¦§r⠜܀yD^öAU#ŠMLM(Ž9yąÁy1GAÇu=Dą‰Ü`Ž“(Iő$sň‚ŹqžžN$y±€ÁwsĚń]öó ±rň8‚–}Y„c“Şd:…zň0“~1VS“(†_Ńřüܤ?Ç©I^„ `ŽăŁ“ăřP› á8ĺôQ1Íń.pġ0 $őó–A“Ƨ&G'Ç4ÇüdÇé©q=Ź Ĺ.Ż  ŹăŞŹöĘ Z«šăÄČ„ęca^K—#–ŠáZ6A+gdb eP'• ây䯅yůľU#ËlŘŽü9™›—đk<„óř,8˘UăSăX®yŞŹÉüÜ ŽŁô!­ÖsŇW@.ŤMŤóעĽ‚Žă¬ř s‚¶ö°ĂŃ ćŹöŁBüŠ2EÉ@ŽXĎ( vX6A»cx|thbŠó Q&ăřč„ć›,NúVv¬ř°ň}%9† k~h\sLbĺűsT[íZ,ă8Ć&ŘůîG4‰ö5QPUšăÖvvć[lp|dtL§ ňň só8ŽLŽ Ž©>–äŞ>úČpĆÎĹŢ» µ:86<˘ş9]W@‚ÂźŁŘ%ůEľUˇ –4qDmAŔq‚8ŞVůîGü:,8–pÔ’ÄVî`´µƆř3ć+˘Q8ŽŚŹBUĺĺ—ćűV…Ä‹0D|c˙¨bZZP\Âq|âW´Ş¬ #ŠŤMM@UˇŚ/Gč”éÄç˛üěY_ŽcÄq|$GőKü9ŽŹNĄl™ÄÖčc˙č ŞJIG|ˇIA»–-°ó&(€b}#Šiya Şňďăäxßč ţM’d6ŞRŐ.łÍ‰ňÂŇ€>Žł€ŕ âŘ;2Ŕ걂8˘¶$Őł$€#¤ÄĐŘđ¨î#$@IŇw¨ŞĆ‡§¦§KtUľv €A--‰9Ž g&(7d'ôŚô÷«n.)*-Mq¦Ď0ˇ„ 8˘„!$áŇÂ2_ŽPë(¦řŚ2¨ĘWńAđŽN8‹0‘$L —Řú*Ń÷†űůsEQ™o-ę3K"ă[&„ľQĹ)ŘA.ůö•Ś=‡Łż0‘Ş"Žüµ˘¨Ü·*%íDzŽÝC}üâ+#IK˘Ęâ`ŽŽ˘_ş‡zQę»Ęâ%Á3â Ĺ|«B™ľŃ!0»ň‚â )ץ8˘NÔS^P0Aٍ ˘ 6!ę© ŕا8G” ˛÷Ŕ‘?qV!0ÁłŞxi Ç‘AF=(ıs°‡?W—řWEŞŠ>Ăt)®ľ‘>ĘAUůr„MVS°CĂ|í=p„”C……q%Aâ őô*¦“(°¤ ÔצůRD×”Tř÷Ń1h-mqěĽÇźQĆ·ńłäUeŰíi5\AúĄc@p, ć8ls„V[Vęϱgd w¸|•**…hő-Ö>ĐŤ’°3QĎҢ2_ލez†űórrPϲŇJŽĂý|K˘µÁ‘?Ł6_ó‡Ć3´4@D㽑~¨ŃĄEĺ«AŰÇÚ€ĆÝ˝á>h ËJ«‚” ´ ta¸PLKü8âWT•áXVĺ[Ő qęĘCmA"eP!™/•EĺľĂ…ÝĂ}mý]Ä®.ăŘđÝţ.06 ź8˘ ²­TŁZî«ÜÇU{QíA±ş˛ę ŽŽť¦AvÂÝţNţ\Q´Ä÷ü2®úË8Bq`(ŔĽĐ° Ąp§ŻµˇNÔˇđ5Č1¬řФ ŞŔ’ś8BÚsěŕĎ(ăËÖËŕŘPÚć¤_ŔŽoŰ`řZ&(€b·5Óĺ5U‡ŔÔéă,9ůZ&ıµ·źë—, ă8ępĚÍ Ňh]C=|/Ý4ARŁ©oUŕVÁś€-vAŠe:‡zĆ''P Şd©Ż-DQíA± Ž(údžP ŠqlÇÁ{¨łş¤˘şx©ďáż¶ô¨bÉ\p¬hćČg4Ρh9MeČą–}n^e°\ş§ő d ‰_ßbö¤F—•Ti4eä@[ÁČŃöFĐpÁ<Ă$’‘ë+Čt˛7lŰŹ“h˘ĂK0Ë#­slŹaşŽíúZU™ľIuwh÷ÚwGéTˇ: ÝĄĆÄmUĐĺžľ2ť´´'7®®ýopâP7Ă)uI vA—´tŰ–Ç1·čÓ“`ŠłjŽň^`‚Ý”öżä*oBŽďĹW:ťFm¨JyŽtmľUađٱäkł„KN± p;’'×ö™*oNŰ1EžčŽ|ĺ踫ý]rÂ) rX§…\WXŚĽąAž\ËqÜĎčß·Z Q`ĂBęáÚćçđ{Iż5v$íţoČ‚Čđame\ňľĹŘ7–¦ĺĺáč,>Ä$îďXMĄ2 ~SŽc+%Úe)ß˝§ ŇĄméű /;턞–ă›Px˙«vţěŁMMf|{± Wč¤ňJ˛Tňń_’çŐwŻCqZ»–e!r(Ę–Ą5; &°ôPř:żĄŔW±Ď›™˘ýIĹŃ 鬂ťŁ[…ĎŤ©AwvĘĂ1=ÍŤ÷ťÄٸČs)ź`¸ňs’rŹ`j0Vruá×üÜęÉ3ä­­ŰąöJ‡^{ńZE K¨ŢŃÉ)ç*Ż ČšÍµWć‚&ŕJ}„őI}ä+É/4nľ0V}ŁH«Ľ Ôč&xńą‹H{†JĽb‡Î˙ôąÂďüsŞw¤_Bßr /G‹Ž—ă|ŘĂą=đlĚź}ĎĆ´ĘÍQ] űFíKŰšHă¨ŕ뀡C#QĐaoĚuŘK7,©őm|ÇŔ=^‡e~·˝Řł]˝N”ĆnĹŔk-ď@´|}äó*,śpś“jZ_żšÄôu ÷Jý‚JjJ–zÍhu Şn´Őh%s“uĄć=¤Ä˝ˇ>ąý--Śĺ ^C=šŁىç,+­4.Vp ęUt5éŰG, öL`˘˝÷qó¶î)ˇ­ CëG×T˘wúÖ;c÷% —•VHŽčcűŔ˝!ŃGüZ]˛Ä+v "n÷eVÎşęU–á4ËgBĚrСýbÇ ţŚŐĺ+»Ŕ±Ą·Ťżn¨Yí-v‹›}KŹXŤß-í…öëô±ri­ď:Ĺ­ž»üu㲵ľŤżyď.‹/ě¤Üą¶«üyUĹr/G;}ö˛×s„2 Kk%­m  'vi™€Łq÷ ˇµŻCžTQÉĘ%u†”Ćšż;Đ9=ťŮh(°jér/ćăZw+{&ŞK*ĽßĐł­˝mŇä€$G7 U‹ ’"ÎŇ‚3îĺxµ«…×!¶ŹďĹ7 \éjáŻŰWlđ–ŕ˘ë?1ČĄUjT36 T˙Íž6éвԪ¨3®0`]îĽ)ő ěĄUKëŚĺz·ż‹®™–•7,©18^íjeŤ`ic»Ă{ă386|±ó¦ĺt`÷ĘMŢ>bHĺ5®ĄuÇęŠň 8^č¸!­Pp\S±Ü«m±/ęÝA#¶gŐ}^Ž Ű}<•ËË«W”×řűôćiţĽqŮŻ$é¸ÖŐ*­/ŚçĆÚµ^Óý\Ű5¶…ŔÎ+L° Qţ-Lč8…qź%qăŢÉ­Ú°lµäU…2ŇzÁx€ŁˇűŔëJç-ŢţP˨侺&cŁu ö ¬ K«©z•·Ź§ď^fW.xA4Y~ôńµă΂N?иӷ d×­[`bÍo]ľÎ·Ř©;ŕ8HZkëŮ(€]vęö%iă4±ľf•q¦€ĽiKK»eŘłŤU Ţ>žĽ}±ĎŮkŰVlđµ0űFOÜľČU=˛î~ßĆcŽđ}F=;ę›}‹˝wů3®jűŠf\:ßvÍč#F̰.wŢŇöRćĐѰd™ˇű Oßą”±ô’ŘT»¶ĘŁ ~ʶśăŻ_ßđ5ßĆŁ »9×T®X[Yo€8ŰvmP`Ŕq[ýŻß±g¤˙ó[6ÇĄ…Ą»Wn6 ŔЏĐqón‡|ŽGů"âĚÝ+ŠG ľ×8żęh´çţarä悡€Ŕ«ÉÍŽé7ç>ćĎßŘô€ol4V hĎŢU[|‹}zó#QšŞV®«^i€¨9|ă´4«pF۶b˝W‚A)\vv7¬ŮŻ­ŢęËń“§”-¤«Ű·f«Ż >ą~’ż~űľ‡}«şÔqó)Íq˙šmľĹ~}ú}ţĽÍv_\,´C×Ođ×?ŘňoU°ĐŘHDőZ_Đ,Gnžfٕ֓ťőÍ^,,4%ľúÎÖÇĽěNßą|µ»U>i®YÝĽlŤ|©u´ĺĽÔÚŕ¸wőVĂ‘1'ßš@Ě‘<1á×Sw.ˇdƬJ+m5ämŰ‹'ŢćĎ5íňúí !â$Çş˛ęűWn68~vë¬ŇÚâJ«Ë»A˙ëř›üůű;žôťm» ýčtpéŁëvű$ěr”Ú¦ÚĆÍuŤFš×NH 3ä*lCfbůťh˝Ŕ-­®X oipĐűřęq©C1(!f0íĽ÷îĄ#üőOv}Ă·ń9ř‡>Ăč}|ý^ßb˙úůküůń {}q!ŕřöĹOůëźîţ¦oUX‡ĐČęSÚÚ˛|Ý–ú??űwçcú‰ ű|O8żuń»eýŮýßö–ůĽĺś:¤ą”…5oHi¨ă÷/Ö#€/óGÖí6,d—źß:ëśµUU5Ą•Ź®»ßëÎyăü!Ć…`nół˘A˙ňéŻůľúéŤ| r¨ě“Jk+B3 ŕ\ QŻĺsf«aua)zkű‡_âĎůµďx ŕHőéÍ3˛Ş•KjlÜ%/jŔńĂ«GŮ"Ú»zËfGíŻťűżţ‡}ßőrÄ.;|ă”úäđĆ…0ń^ ýűŮQ!•úÖ懼¸Ţşđ‰|· 6áĂM» ˝í¬ĺĽ|{ßčăÉC~Ý·zŚ47ÇN“—!ŕőTó~/4F[&»6ů:@˙ďÇ/đg(_$ĘťţN©†ţăä-sđÚql4úL#ÓëŔÚ˛ Ś hyg‚>~că8zű:_:ý.}^^VíŐ/ăSKňÎůěkśüý‡?ăĎĎm}ląß1Kúł[gčNíůî¶Ç˝e@ż<ů6ź°ć÷x,XˇŻžýPšUšoo~Č«b>˝qús°B“ľ·ý뾡Şn;ŘBXöŽ=Żśů@^‡ÂČy澇˝Đ,{0ĄĎ8|ýáŽ'|9BU1Ç?Üţ„ď…Lč_śxËrćú˙xôĎĽe`ŮÍ!Đ8ČK-Ěă˧ßkíÍ«ř’ĐŘÚ`‡böͤf SüŮ-Ź@ hFcŁílŘř¨űÜóćĺÓďvŤŽ0D {ň kUľém…uč…†üěčořڵۍýcCż>ő~×poŚĽŤ1u łĐ{ÜĆŇB7- :Ŕ"ü-ʰń1¤°TÉŰB^č+6lwš`‡şvBť8t9°ĚÍÉ\2Ôčő{wN´žź"Ż.‰5öFÎieVµ9Ő˙p:öa,%0?âBľ¶=ęÁž•Îóę⥛ęÖzÝm'Z/Ň»(ŠóěŞ óH;<>zľýúÄ4MŞ ó¸aŮjăRjQ5žKŁÇpâ3nr®uߦ«*jWN<ľĽ¬Ć{˝qď6}F˝¦ÝaRU…yůŢËöT:u·ŻkTűhâ±DU± ›ÇB%÷±.SxÁârĂĐ/9ڰç|qň5Žäč#VŤžk*‹ÇĘ J \ ¶–«Âg8.Kś Ë JĽ—{ _žš˘BľďV.9ŠbP›o¸9°Ŕô•# U¦¦0×íO´Ň„zá'jI'üݦ|?† ‚ŢŔDUú˘@ő2‹ác2/Çüßôę» *€ö'†Ă—âX–%ç(č_ŮǨMZVeŕ¸ĺ˛Bo±Ż2Í;b×â‡çČüúebGµd4Éň 51#vÄą;“íR˙Mxŕ#3bGd™9ľľ»(kŘ4i\xő$IřIo!bpŰ.r»fşOx›ŽqŔ†ş‘â9šä}ëk‘bGĆô«ŇŢ?Dm¬ł1AĐdľ»˛ /ÉbĂ5"n7ľ/V’,äyôGä[ — ž·Ę {Fěz.5ey(™Čó˘+ć;Ň/ŢfÓý±˙‹eăĺ¸H±#÷†űY÷‹yJË·d°’ůöŮ śą§ y/ĆUˇ€ĎŽwż§ÂUA:ÁŚ6öČĽ`G°žý8*yX]RÁ˛.±2ŘÍ7Ď;YĂŽ@˘¶őwĄ\ÍţŚáb‘µ‡­ĺ‘ŃŘÔ+Ę« ťŽGڧݮ-­4ÜB3bGp$–zŠ =ĺë¬ŇŰ}ťŽpvő ®¬š%ązEXÜýqY,0ďa;;‚źxÍ#†CĎ&vł;d 3µ$„{'%_é}żjbG°ü|%j[éq.4ěäěĎ”2Ć–O_7şo/c®+‹ĘŮI%{µ«EBÖT¬`AÝ1xĎ~AÓ]$pSőJ㼎GTÁ´¶˛žE4vk»xA“ ű¸ĺ´ć ;Ă×ⲗ°sš—eÖĎ…öĽĹ$AJđ¨Bz_vą˙m‚A‹…ÁŞA˝ĺجK´»ťľÂR:}÷Š9&ŞSoş.CgÄŽ´ô´Ém™Jň‹xŹ€×É;—}96U5 7›Ř‘ž‘Ë7˝…ĺ·˝ľŮ°Ţñ#\§ś>J#˙ß´¬‘Żí0ARĺ Ž‰ť ™ăŮ»Wű…3ž«Â1(OÜľ(G••Ű}uMĚÔbrTĺ ¶{° ;ťxęö%ď_ĺčábzµ«ővćÍĚđC){}Q ;Ň5ÔË® ŁŹű×nç%qĽő‚ٵ3ŘKźvÖo¤Ď0ţ^;!ŹĆ\ăoŔGć;›đđŤSŠŁçłkĺ&>2#väó[gµWҬ … 82účĐý+7öÉ"ĹŽŔhaO‰‹śDÎkwöI„Á ô­ źČs(ÚŢU÷đ‘±#];n €‰+ëŮyŹă˙»—ޏNľA˛ł kď”ßÖĆqďéŤřTřŃŐŁMDbG,­·®Xoüm8vJę|ű5/GH'ąÁßľxŘ–î+Ŧꯓ5ěL-*MĘM$žÚx€MVHÂËÎň=P}d¸lÂ7Îň=ko®k‚~”Ź"ěčÍ ź¸ rű?>‹÷Ő3ú^ŁAEňŰíçŰŻC’‹íŞrąßŰţuĂŰ‘MěČ˧ßďvΡ‚6Ő®őşŇñ#X„'l^.s2_Š”—N˝+ŁU1ÁT0¬…±#Đłgů'xâtüś.ŽąŰß…ŢVajľ»ýqf•qËĎs7 ‰úŚŁ&¦&˙őčkŢ« üŃ#M»ůĐ3éÍ ‡|8ćäţá¶' żc6±#/źzOßąŻ>‚CĐżĂ÷úĺéMÖ¸Qň3bG°$ڶ,_˙`ăăaÖ°#8výěčkă~}D…Ćńj^°#ř‰0^úßżö㤖MěČű—?;î%­XRóG;ž˘Ď8|ýÓˇ_úŢV=˛n7ä0Qa“#Â’9y?Üó źŃĽŔ˘ú%5Ďď|š9ţăÁ_ŕß^WÖ›¬0>±ŔS2'÷ořľqżŽÁ ô§G^U1­‡ĺ0řö}±#Żžý°˝_Éy‰‰i3€Ďř¬_řWŽë…5)´0$aŚ]źŽŹł(YřĆݱYőÎĄ#ÚČ‘ŘK_ €5vóx­ű¶l6•-É/ô*ŽpěN»ÚŠ`ǬS[,ýÎFÎÍž»NLbGđďÂdţ&qUËďheÖďÎj^°#©tęz÷•+@đrp-ĺ|廫SŮNmžęšŹ´őŘ]ˇŚRétç`·ľ·őGś|ŮŠ}Á‡z餎Çc…ĺ†<;‚>BúúĐĺÝÚ 8&Ů˙Ť[±˘d˙‰ `,›—›“ă…}d ;’¶ŇSÓć :fÎ$.{ŕĂ/ â¸můú&˝Ě`Ťg\űći!ýÍÍł†ÁŻ^ä+µ ęříĘ…­űę™\ż‰Ď{VmYS±Ü"÷Ň]_ËD˝§ńĚ–Gäť{„iżz/źhŢG:ôеF<¦âdÁw·)ňÄôä/OĽăľ ÉÔEh C˛†Xţř*omS[aa·”!ŘXţ/ťzOFU‘µ>ظ“6tÁGWŹůž ±üžßů”ĽŇ ÇŽŔř˙·cŻŚ  ŽyU˙ę×.Čäá¦ÝšăđĎŽľî=°A5PťŢŔ$Ü@ôIO±)‚.'×WŻ2쫬aG`HüZşöÝăúě–G)¬„&„ c+…cGÔŻ§Ţő­ ¬¸çăú%kؑůˇÎďmsˇCć;ň≷ZNľ ˛Ý…ÉvGĽ>ôKßĘ--%¨NIꏓ0átöWűżKg´:ô˘L(/Cq´‡r§öü۱7¦źßů4q„™D¶™w;âTű7ţ>˙·ż°9šĺҰÁö»ŹáŘX/ĐéŚ<€ĄĹą÷YY8;B`5™óB€0bßßńÉŢ׎ |Ô”T~}R¸şŻśţ€|˙v˙…MµIGkĂńóhËy~n‰ŞđvŚ[ľě ŞŹ®Ą»#;‚˙mZ¶Ö@'‡cG ĐµCÁ;‚y¤ĆÓk!± n„‹©g«+–S€Xbv ‹}˛;’'0Ň˙2/ŘJ9Ä͑ؑx<ľri-]Ҷô´M§§˝ŘKżĹDGŹ±É‰Îˇ{.DNŤ406#GT8vD¤łJON<I‘ΰ6łRe;â±ű¤kHËs>%ńrDžëX D#NśčIúĐŇţÔ´“*MT8‰XÂđ4‡`GĐý)çnZçgI:O,zRčvi/FěČčä5ţĽ 7IůáčI\EĘ*2‚Ž`0ŞĂNbz‚<*áđ€^Ś XcŤá™#fc841ÂŢ# =˘ŽŁCĽaĐ5<—m(Ę+ĂŽ‘AG Qđ·ăĂöĘI«'Ĺů®Y;v¤gd€ĺę‡Y­Ě+ceĽO°±#ÝĂ˝śU„5€^óÖĂB*+(1‚ŽŔ6ÂDČ4Ţz¤tpÄŮřş¤ Dĺ)t‚žaYV»C5†`G°eŘXXZ:cÎ Ëóš’ ąM採ôŇüuYi%ÚĐ'"6ă V/ÚĚź§{¨ŹcyCŹd;B!@ř«Ě”çŐ‹'ŘŹĄ^g1z葌ˇâ =‚GŮ5LxIl¦LJĹpělqŢVĘř..DZמT•,Ĺ×Ű";F]YÄEçPfýSč‘îá>ŽłťĎ©_R â8Ą1ŤŇ¬C°#2čĄ}źPp2…Á‘7'˙®Á^–*P¸«őmďŐ®V1* uko‡|"˝ ;r»·CKf5ö%ɢšŇŠŰ˝í¬ĽˇGvCÄą˝sőt`»±Ë–CŹpĐKk˝ĺˮ߻Í^OhôĘń’䀮AĺIlf6t"7®ŤÜíďdń˘3}¬‘çŢ줍| ume=Ú ·…Q tîŃÖ€__ł K·'łŮăĆ›(sÇŽ`îصæ©şăŔAsŠm{ęÎ%¶ jK+Ë K.wŢ’OjËŞŚ #ÍËÖŔ±ńXiű ÖVŻvČĚňŐîV”L;·Ô5AG°#°\/©¨-ö#ôH8vÝďsf ŇűăĆę›BŹAG°ż°T.tÜpž(y.‡7kجů[÷ěý1µ±v v±#˘ÓqťCđ!Řčů¦VהΠė…ŤU Ř2č8n]±ţ¦HLáG޶śgEyŰTŐpöîŐá {5˘ž¦Ş•؉ě&±ÔEdţD. ="Ž€ăöú ×»ow:[Ľöş=Í ;˘‚ŽÜąÄ'] vś/x‚­ éÍń„ …7Ô¬:Űv•7o~NžŃÇ…iëď:ďčLV;„j[7ŘżflNtBľ|cíÚc-çů,@ˇGT@á†_W˝ĎŹÝ:Ď–ţJúćŽÇŚ>ťĆ`Âî•.ŰÍuŤR„cG>şzĚ1ÓXä÷Ő6}Ör–-Ô% á Á XĎSÓÓ0g„YŚŘtÄRq,vôŹ«ŤŕĐŤ;¤űŠcG nŢşđ Ĺ"©,^‚eɧďťőÍ2¸]8v?±•Í»«~ăG׎±H„:ĆđŽLŚľq>ó=Ä 8ě@M+çF2ěk6ó ť_żW'¦±Ebn"ńôĆ`n˝~ţcÖ฻aóWŹö;Öę1tnvD)Ě+xbĂ× ë· ^ĎjŹÎkç>ć°©Xę°>¸üą¶IŻŞ¨»Ąk›d;by˛y¤ôÖOöC ąyšE.¤ÄžU[ 7XžĂ¬Ą%^Ë(éĉQUˇG"ěH&člÂňeű×n{óü!ű0u ˇRuňľ2Â9ĺćĹo¬Ş—AGŠ“!źÝ~gËc°3ŻtÝ"é ›äŹvŞř/{ŮUŚcÎkg?bŽx"˝éáŘ‘ŻBľěëö˝}áÖ ŕřÇ»ž–ĺC°#Đ\9Ę_ż»íq}ůUáPđţ•Ď5GešA.=Ň´űMĹ1sľř“Ýß4‚Žě[ł Ś^9󞤝'8t@_ 66~°ë›0*.‰SžČ«Â¬aGdĐ{]żO81 ž@ËĂůégŻňź<¶~ŹĄŐ÷O¤> ÇŽüäČ+lҬ®\ńřú=/ťzJĐŇŁÓ\łúń .©’ěTŢĎŽţ†żBâÉŰó#ôČܱ#xţ≷X@vőJ=Ž'2sMÖ°#ohŔ„ÍhI dČ˧Ţç·`wýh˙wŤ #Ź¬Ű ™ůÂń7ĺäЉ¨ŤkţŃţďť»{ö÷úŻög´—N˝Ç6*ŚĎol:đoÇŢpN…*Qéó;ź†ňO‡~Aeđ珪 Oµ??ö:süĆĆPjgď^ůŤĂ1™Čűó˝ůěäŠí_řľ|5;Ž˙üÉ‹F öTó~ś¤ŢĽxhBßşÇb ~±Qdń ÇŽ€ŃJM˘*ńPă.Čşž‘ň˘7U7<°v ĽxňmL(ý2=yřú)†ŔôÂÄF…ęrĹy…OnÜwüöE:ČÇ”cÎ6r´Y5NžĽ•uÍ5kTNC}~ÇźbTŤĂZvµ”ĐpŠÜ$šŮu·ż‹°#ąI ť,‚ÁQ÷ôÝ+ x˛ĄŮ'G-…ąÖŐŞó©'EyůP8Ĺë›ő,©nr”%e7ťNQ1ş;‚VJŮwG±eĄRKÎ;BAGRŠŁj.,Oô]żl™¦ˇ«,RˇGčEGĆ–`¨amö 8ó¨$Žş(Ł/–íQ-/,_á ĽŽ`A€}ŐOě^ç¨ě3ę’TF"ˇě6÷X8ŕ+Žß^}RµV-‘c‚ÁzcgŞĘ#¨9v öL;ŕ!ţĺĘ™;v†>ďŽ)“š{„™B§¤ź#Y¤Ś*‰üPç )ůłÁ|Él;äĂWv(ćv*űű‹’…4Ş"f†Ęp)…gv»†ovĐ_âئĘŰRc%Ż}C°#ŘőňeâÚ˛*HżÜ#ÔŹó j ýHŠ8b‚Xc@ĐŁÖľv^TôőóŤvZOĚS‚éÉd˘QK‚ę·E$”Ç–ąŃs—S>--,ĹJĆ4µ·6–Ö–®XŽŤ@ w®_:2väB;Ő ¦Ż®¬ ;˘™ň2ó‹µŔ°#7îÝá°Śé’Hşt /Xčx]€E.űx_]¤żĐ†ţR›Ż Đ dęWXç dÝlĘÄ k*WH›!;˘@! CIä6ëë ”g ´Ľ¬úrçMulsF ‹‡%étl¬Ş—çŽÁ€óF[¦! ŘGÎ:QÔĽlőT*uEřű7×6B·©·IěËtĘnĄÎIŽń„®lη_WSw©V>ŞÔU‚sRĹRÇJ€ŮsąókyLĐÄÔ„Ľ´E›aMÉH$P2O8vDF&WoĂ/QĺĹnÚQß Ő#Gig}38bű·Űł–†žj®É\Be ;r^aAlť%±¶J9Ĺť JĄŐ02éFv¤m ë¦CAďî×NńłŞĽťsѨ! \C­Ę>Ł0sŇY»©¶1?7ď¨xŹKş łĂ÷>¨ďŞ-E†Bˇ°žŮ͉ő€Mt˘ő"o4z+ôSńÂś†dĺ‚ÂŽ\ín˝Ąŕřc(v˱–óĽ1Wę‹9™Ą»SM*5.™!nAaG ôŘWŤEHŢAéČĢĹRń>®?ÖšY'ŹŻß{WÁP®É'–^´,QżL1wěć—…IN,ţ¨v«@&půş˛jyG‚ÍđŃŐcη4~ÂÖ»ÓßyÖŃ0i[żWcAěßaĄ<Ô´ >»y–í, ™l1bG —xQá\Fű Ă …eůŻ8v’đxK·÷ěVĺ98Öz-ĚÚ˛J9 !ŘÇţý쇬.ńW™ŘV%’N?·íq¬(¶U`¦Ň(a‚şťĽ3›ČxÂ[›žXĘ÷ŽS}úÁĆ]EyůŻ ÷ž`“âÄqÔŮ&¨ß“ěH&Ťö…C¸ˇG2fţĂM»rąŇ)]Á)á8ĚŇ…yßÚü äěÎDc/c4驍ű- ,ŕcŃfUľé—'3 íőÍë«WálřîĺŚx|澇a+J‰'EÉ'‰Ş ęř1üřŠcG&¦'ĺ‹ďŹ4í†mëâ}ĺůł=Ď\Đ †_X፠‡:ŕ&ţęŃu÷Ë'PäŹüÉ‘_[Ž |Şyż4§łÁYőe!ŽžÝň„3Ltś¤zô§÷KÖ‚yář›l„Ŕ„†ŢÇ׎żÁ7EĎn} –6é z9ł09ŚaŇ<żó)®3;ň“#Żđm$<ödőŻNf"X<·í1)ŇC°#Ř E0$ľ˝ů!Ëqîrý0 ˙ńĐ‹ú›2Íö­Ů†'„2ä¶ Úđ¦đ÷˙ĹŢgq~Á6á7X°ű°$´y¬žá쉠†÷Ó—$脼ˇDŮÁŽŚOMţ÷O~ņŮÓ›¬®XqýŢí×ĎeňzđůSw.Á¤ŻčÝŹôĽ`fYGÄ$Ă1; ţÓ#Żđ×ď(,H5¶ jÇ~čŹeűł‚㍀ă…”xŃ]^ęĐącGpS>Ź˙énµőţżĎ˙ť5&ĘKK&kŘ‘řđç|‹ř°†€ ĽÔ€?Ú˙]‘^O0e8‚˝'2ÝÔëě6ĐĽl|˘%”ďćď?řß1BZâPó˝ó/\ŐÓ Ň("‘¨6ţ—‡«’í<ú?˙ K/BNb…ú˙xçÓ/ťz—ŤĎ¦Ę†ďlSkďďŢţ1Wőô¦$h2;‚sÖűW>#m27ů·>Ź‡Żśůŕ:ʼnĹp ŃA‚ţąŽ™DŢCX;*&ӵ㌢€č€ÝűYËY*“Lä>ŻőËŰw QęĹKâťKźv öR]Đţ°`P,ň6>Ü´VÓ»—>egócë÷ŕz­«őLŰŞ  >;ňᕣcSăäzm¬¬_[UŹÓĘAŐx;”É'î#Qvä–z—ŁŤz]ś, eG×ÔxşXřĽĺÜtjš†bEy5¶áŐć¸qŮZPb܉¦bß©W¤H™Ć ó’ň^tîŘ}éÚa9aPÖV®Çâúx€†Ž‚[ĂŔ!ĐÎݵZS·ô´§,;pË’Â2śk”}î  ÉS ß®DUС*̉Ń:=‹Á $ĐỈéŢ;2¨3+©B؉t˘'—5Ł$Y”ź›ń,„`GІá‰QvsłKNşüĐTXöťC mČ!Ç%иÚD"Ž1g_2˝‹Žzl­§0.~ł™NĄR™-vN;í¬.ňÎŁűLŮ_/üűÚ»ďöďóg;â:x±#!EIJQč¬iÂçŽMNđ¨ę¨bEĂă#I·ŇCâ!† ËCVNj ěHq^!Ö$3mw?AmƸńŕ‡D!Ř#a ”%żµ¦íɡ›#vÄHXSQX†ńQ3ń6Ň8ÍĘŤ¶č°#v=gčR¦ż~)ß~ FÂD8CŤ|u‚jŰ„Ö& mí&L;]‘ěLXŁ3Ô”8'ÄC e+vVo¬Z ĆCě_v‚âÎaIđÝĺd;‚Iäe‰íIó¨Ї•h ë»2'CM‹xh¤­ ÁŽŔäĺŤĂ´ďC˘ě‚ 0‹”ďCJXcé*´_E-äµM–˝ î]]Ľ”F×LZĎ‚”9!Ř™°•Ó˝Ćm÷Cś…¤çx…¦(!/]ć(ŁFâŘ@®#‹Ťô—,(ěV¸ăĐ"¨ĘPŁłŘÜć2FÚš…AcXˇcIP ęˇDŔ”—Ýi¬jŔĆ ęşx¸ľf¦Ś·*ţ„Ö*d‚ńĐľ×TSlg¨‘Ř#mMv{–Ý~śˇFf±ˇ‡Ŕ€äěňňjň¸śĽťy™ŰH[3wěČ ˘©z%™@ÇÝ!Ăĺ“ďŮČb‡2a ä őŃ~¨»DikděhlÚÚxČJg}őJh™°†ZF™!;‚=+§Ś2ÔYlÖ׬F ś°F…ÖĐ}YlŇĐG2mMÖ°#'Z/˛ľŔźŻX˘jřüÖ9J“öDB°#X„5986LłçÔhcO†TÖXĚyw·{¸–¶Ć «64l*5MÍ;yႝĂŔŇň›Űčă˝(cŔŔŘ0#3ňsňHbŽŤ@YRµXá(929ÎŢŻÂĽ‚xL%Ó°]ú#mM¶°#™„5ěX§H öÔę"Sî0ä˙bŘ#?Îl°#™,6vÄŹľ8vÄ’cúŔŽXa‘0ěHN"m6°#9q@$;بśË`G8CŤĺ‡ÉÓYl,7vubciŘ;ÄÄŽ`xĄ„ZtŘ#ÄaG,@>”ŘL±Ł62ŘKßČĎI*ěHŽ &˘±#–vWgş±#¬¨$vÄrDfŹ)ËW0;RâĚ/v„‚4Ř‘27@dŃaGěźÜŘťˇf ;B0ËŤ!@ÉŚŘ‘ňü.h–Ř‘’d!­‰ÉsD˛€Á*ĘË7ҲP !‘‚ÁîĂXúq;Ň.‚‘Ě;"CŚ0LĸÍ;‚ă4fź8JěHĎH?;~ĽŘĘbcą±#K KÝ‘/;‚u…®ˉ0Î]>$ZPŘüäxI3ŘKD¬…Ť‘ľjĆŽÜčÎ#ńbGčĐk`GÖT¬čĽÇ•ě 1ÂŘŚÄ‹á#;bDřĚv[FK›ŔŐŃů*^î;R[ZE[[bG jËŞdĘ’,`GŚ#„±ÜÁH ě1˘6ŽÄŽX*ÓDƧ›5ěL ÁŘ'Éo‡‘?e;˛ą¶©µ·Ť­/ĆŽČ 5^ěe±±ÜŘ;™ĐaÁbGV:wp;˘pTUő2LˢÎ|xĺ(ľlěĺř´ćŽüä¤xYŔŽ üŐ®VNĆ0Śä÷ ;Ňä„9ě”H€H„ ÇŽX ’ńdĚ;ňíÍáj`G î°˘ŘöÁŽH;ňúů|ß2Kě™%vdßšm˵“Ă”ä%rNŠüG ;‚5O˛TbG(CŤŚ|„í'ĂćvĂÇWŹGŘk&ěČó;źĘKäŘ‘'š÷‘`ź;"]ˇŚÁ¬AŔţ±#Ézömú˛±#ŰőęĄ#€ÄŽh€H†ăÂÄŽ <U»{%v_ţńŕ/¸;BYl,7vô7ţpQ`Gţ·űżŤă‰yvËŁ¨áKÂŽü­1b`G4@$Ó‘ě`G|a"2É—ŠaÄŽ0 „(;Ř#ÄaGđá˙~÷'ňˇÄŽŕĽöWűŐV•ŘÔý_űóŮ`G–,“1ź;‚N0ěČ bÄrcG,ŚäďŢů1eěČĎŹľ®›1ĎŘŽOC4{ěČŹôpŘČj¨’öÁn;ÂĐ;#®ţ$vdÓ˛µU%KgÄŽŕĽ#/úf‰,˘X¤;˛şbÜf‰©(.Łx«;B·3bG°H¦S)%±ÝŘ‘ˇńçĽóĺbGâńÄZÝe‰±ô^ž;Rś,,Ę+T™sÝŘKiĚÎŔŽäĺ䑏IbGôR©„Ă `ě­“ÓSóމÇ⎌“K`G†'Ćt´j­‰ˇVŘ#ĄCv°#S±1vD%˙ÂŽ$ś";˘ýűväwCvÄç§ůĹŽČc‘bG’9ą4Jv$ËŘJOc-ZěČ’‚RŠaGřsv°#XH´ö"ěH„±9~°#XtIaG"ě}ť%vKťR›EŘ‘;bEŘ‘;’ů)ÂŽDŘ‘;aG~7Ř‘çôO‹;ň°úi©µ8±#›ťź"ěHö±#ôÓübGt"›î;ň{Ś©Őéi¬E‹ůŹ:+G„É>v„ÓÓ,F쥧±"ěČď;ÂŔbÄŽ,/ŻÂZ‹;’ĚM6č…aG"ěŃ,±#1gźFŘ‘ąP”łĆç'_ěH”łFv6ĘYăË1ĘYĂ_Łś5D_…ś5č{™ž—(gÍĎYóĺaGfάLt$ĘYc-lěȥΛlŰĚ2gÍşšUt 6gŤ÷ˇÄŽpzš…™ł˘Ăx(±#*=ŤöŻ/Ěś5ĆC;˘ÓӨ댛łĆyř{łF§§Q[{1次ô4V”ł&ĘYóUĘYS㤧‘ŘňČEŘ‘/)gÍcëî‡ŕZ¤9k¶-_ߤŐbĚY…NS嬉rÖ-Řś5ŹŻßłR-‹1g ěĆ}Z_D9k˘ś5v›Łś5E9kB°#ó›łć»ľ Ń˝đsÖl_±LŽyÎY3>D­šcΚΡž»öžý}ËY“›ČĄAžeΚ/ ;ň…sÖ% Pm”łĆŠâŽĚ-rěH:-ŕKv Óîg¬­`ěHZ¬ĽtN<ÇrVsÚ)źvÄŇۆ úbGŚý–ě<ĺ`G0,$nŔš;žĐH~„I*rĚąő¶Lt0Óń´U0kě*×ìŞ;t «K–/ČMĘÉZtŘKëŢ2čúh#A 1q2Č„;BÁHF'ƸÍ.ňöŹ ń^@ýW?ěHY~1ž ŹŹđ^%-‹‘gލ_]vÄŇ7­üŮ;"}cÖś±#čď=Áݡի_۵‹T»0 ‹;‚=Ą¬%gЬR”RŽLő”lýd„kđbG0‰ř§k¨gĘqÇbŔŃl o·ňmŰ *‹–Č1 ÁŽ`˝±3U‡Qײ0ű&§9IQ‰ŘsÇŽŔ@(şzľŰßÉâ3…>Jŕ0Ę ä¸ ůˇÎRd;‚ůb ¤7)1ĽŇ U0Ź"ÄFŹć7…·şx©ž!ŘěľëÇŢ'Ž2 ĆJž7B°#Řő-b”prĆŚC 1®ă‰ó j OZ/‰z}Ë€ b9ŚÁ:iíkçE…ĄŽ>BÝÜč¶`i=AŚ„(;˘Ź v}±#(_QTvŁçî”ŁŞŠËË J±ěo:.7PĂŇÚT*Ő*VNcU=:ĹgKë8éČ\PŘKű*ôŐôa‚°xFň#S-”ó…ąq/b{– MňĹÍÝ í×řÉꊹX䲏÷Ő5Ašń$DŤŇőîŰ\?–ĆGaAś'ľŘ‘5•+¤â ÁŽČ#X„´d0íĺeŐ—;oŽNŘ0M 12ťJ±'ŔÁHćŽÁ€óFĂź×ę»W h^¶ę@‚¨¶._ŰČÁH`ˇ–:ŞK’…ÔÇóí×ŐĆÔ]BĺueU'o_d¸¦Rârç-Öň ‰© vűY~Ř(Žő5«¸@vÄr‡i¬jŔäÁHvÔ7CőČQş_;Ś[zÚÚíYKë`$k¸@Ö°#NE şâq.(•VĂ8 ÁŽ´ taŇgH*şÇ9«Ęk#0­TƇ^0˘bľŘ‘MµŤůąy2ĆćÚFč2¨ż+]ö:Á Ů»j d«NěMň¸`=3ňë›čDëEŢh K–a#ĂćüTÜ{ę`$Eą °#W»[ď@)hFPŻ[µęXËyŢŚäŕµ|ÜPł S MĘ>$K_[ç Ť¶ °#z¬ÇkË*IČKG&-v·|â‹y|ý^láóBD“k‹–2´ĂV9;vóˤ 'ŹVd—Ż+«–w”!ŘŘ ]=ć|Kă'l˝;ýťg #ę±ő{eČ B-|vó,Ű!X\íbÄŽ@.ń˘‚ů´Wűö08,¬ÖU»Ęű#„Ç[2@gµďXë…Gř`[ÉYÁŽŔ.ý÷ł˛ş|`íll«ŚI§źŰö8VŰ*°źŇ.ęĂ7NŃF#‹ŠSĆ[Ű;ň`㮢Ľü×Ďg\ÚxŽ8qu¶ Ś(cLB°#o_<Ě’ ’dSíZôHşBnÚ•›ČE1~‚]Á…E{ÂĆѦ ó ľµůAÉ1;Ř‘ă­xC]>ŞEîçń±H#iúĺÉ·ůškĎŞ-«+–CÚĽqá×óĚ}ĂV”Ó‹AýŹ äÇW;21=)ß}'쬋÷•Ú˛éĎö<3 d»Ť HäҨbBŮj8°v»1bäľŘ‘§š÷Ks:;ŘśU_âčŮ-Ź@8ĂDçČ 0ţŤµ‚yář›l„Ŕě‡FĆ׎żÁ7EĎn} –6é z†Ç©‹śQMhŔsBř„cG~räľM‚„Ç^€¬ţŐÉ áąmŹI‘‚ůŕĘçĽŃ`Z|{óC–ö"sŹP?ĚÂúkÍQ™fO6ď[Ąť‚2ę¶Éŕř|âĹŽÔé`$XÚ ŚQ,ĂY€DQvŰü_´ü'ď!ˇÜp<|çŇĆŽüĹŢga÷~Ör–Ę' Gűö…ĂC÷čoÁKâťKźv ö†`GnÚ «ěŤóŮŮüŘú=8^ëj=Ł_ŔŔźÂ¬2 řěȡë'‡Ôĺąú˝±˛~mUýÔôÔűW>©s6Ę3]vä–Š Ú‚ˇ‹(2,BzcşldbLßŕŮaÝM§¦•wcGÚş;le+ĚKĘ{ŃącG8tv„ŢN„˝Ŕ  ˛ZzÚSVŠţvIaYi~‘˛ĎěHUqyAn>ş,ßDUС8%9ţŘi±±!}§ˇ“·ĄwdP˝4«‹ˇ tÉC.jFI˛(?7ăYÁŽ  ¨đW9ńëX€t„`GpBĐ –´®?–ĚUˇxx1…nHÇbÄŽŚNŽńPC’äĺŹNŚq/0ˇĹÉ"‰d„×I^]ËÚŕ'ů ’‹ŹfD| mVXB‘׬±Ć¤ľA×”ľ™eסQ3!ĎF2?'O¶%‡7;ŐĹ) QI˛…í•“VZ¶8ß5 sÄŽXÁŔ}$ćŕč°Ę’[âž…E‡QmîĹöŁĎP˙X90•xëá ¬RťĹFŔh4ęHÄ_Q¬čK˙čŕł)Ô`&‹F4ĘŐŮʼnębW C°#$ě·ô`ZvF${Ja±Ém2wě†]Ř/°˙°´$@ .ÖZ5*úfwőMŠř+Ć,d;‚5)»†_ós’]C=¬ÝĐNB÷:ó´¬´OřJ›z…ř‚GŮ5şá…ĚńDJĹěĄ]­Ľ­°Ú±D;‡zdŇ˘Ş’ĄřJ–=­€jÍ‘CĘ[N†™Ĺ}ÁC,ËAÇ-‘Hä¬rű C°#x.GµZdŕ™†%Ë0ˇxÂn¬˝Ş˘%řĘR wuĹrKąyZyp g––´öv *“Wc ;r»·CKf5öá+–,»ÝŰ>&‚­>QkaG0D VHčWş‡űth%ý$'ŕË ÁEłqf,4úĺx©ă&×Lý¶.V|x‚Ő‹%Áë×TÖC5𲯠5k$Ô&;isY€!hŠĺÖ[[©@! b2pŹŤÉĆŞ†®Á^Úx"ŻT¬ůŔŽ`î8˝DwĂŇş…“͵ęô~ęÎ%,rLßĺÎ[ü¤VN şe>ňŻŰ6ÝĄćek°Ć°xµCO5VÖ߼wgЧ‚ă–ş&íÓwݰ=‰=Mq©ó&?©S0”Ě%l8vÝďsf Ŕ¨bÜX}Cűc› ć“w.sýP+ËJ*/tÜpž(y.‡7kجů[ŕşrcíšöţnçň"Ź'vÔ7K>;˝#_t^UQ‡ oÜ»;MöXZ]bfU$ge˘ŔćşĆ¶ţ.Vmx˛ła#8m9źQdůĹ«+—_élž°W#ęiŞZ‰ŇńŹ'–Ž;ÂO(CŤĚbšńđNg§łőđdŻŰÓĽ °#P. MRĽ`¸°µ!˝Űgľn¨Y…EŘ'"Š}\PŘ‘6ř°u¦cËňuXR|í_ł ç 1)Nl]ľ#ĂgŠ2I(ÝđPľUĹKOݾĖĂĆڵ҇4wě8Ę ëkVç&Űo0G¬p)LB°#–†G8¦c–Ć溦·/°e‚z°zQ@†d ˇ-!€÷ŻÜl„ŹZtŘČp™Nk‹~wđ”Č3ň`ă)Çľâب ëłai-–%źLwÖ7Ë´\!ŘKK6Ţhź_[µőđÍS,ˇŽ1Ľ#ŁośĎ€°g ó Žµś#ŽiĺďÜQ†…wĘŕ(ô NvĂ";ĺéŤŕůëç?fŤYYĽdWĂ&ĚTżc}ˇCç†`G ˇ=†šnÚŤŐČŘwć×Vi‘{ňöĄ^[$¦ˇĽd 9+[ŘčÁ÷XôľăŃT«öÉćýtGnž–"wĎŞ-`ÍţBµô¶:F‰ ZčŽw/ŃO4 Ą®IÚ{_qěčÍ ź°Aľ¤ ô‘u»ßżü‹}:Đ€0wuňľ2‚ô†¶=tíßŕaŹ7VŐź×z’—Č}răľóm×(UZ?ůŢöŻK‡Gv°#–ZĆo±IßTUßX˝k©'#„ K&;«’W{žrC>ă•B÷ę&bXţh§Jcń±7†ó»©z% ţ×Î~ÄĂkA áŘ‘ŻBľěˇĆ]ÇZ.đń ĘĂ‚Á1A†™y¸i—Ą%­ŠŞJ’EďŰešAČ?ŮĽ‹„Ďx‚yśšüףŻńEΉ[–7˝rć˘'ťćšŐ2« •-ěTŢĎŽţ†ż’)(!†¨Sž°ćŽÁóOĽĹÂä‰ć}ř·Ôă‰Uâ:4kŘ‘7ΔŠěŮ­ŹĽ|ęý.ç v׏ö‡Ż:ôK>ŁmŞ] óű…ăoňČOşC?‰é&Ĺąů8ŔDw†=XÔt3IÍŔyť‚AďúFŮÍŤŁ7f|xrŚ]r(ŚU7>5iß|Ƭ¸jXÔ:ś1=Ľ*ĘH,629ćL‡şlGmcö‹úŞÁđwd;bxĎid¦S)ÉŁ 5Ň_OĹŇiéߏÉ!µÂ±#nL‚;ĹFâ"ě /±,÷[ćf;bég6Mđ5ę Áޏ•í˛!9n7s8vDüę3ľFÂ+[ŘËÎP“ňŽ•ĺ$¬±ôoăZ*ů® ŽD2ťšžpNÂ^ĘĎI} ÁŽ`Ž©WrťË`wUaF/#vÓ'c~DYl,íĄ¶QRţ’…4ŞĐŽRPĘ(§áĹDË$2Q$K¦(IXŇÎłfÂŽik\”VŽc›Ě;b¤­!F˛y†vYŚŘŰ.qHBö°pş q!ŁŚÄ‘H°D»`÷řČ$ő=5ÖvÄr§­1Ş2ÖXó±ô…—ÄşIÂZŞÇ ‚Wf¨q@Žv—˝čě`G,7epĚŘv«°ůL~§ŻcJ`% k¬P쥭đ ™c$¬±fÂŽ`}ň»\^jX˛Śô#!ľ}Ť‚„[ZŢęi“âK–­r'¬±B±#–;mŤ1bŕH× “:nŠĂ1m”«)­ ©9ÓĐǸ‚,—ĂBĂŽ8iküŐ±‘°ĆZ`ŘËť¶Ćn–C¨ę‡Oo?×ë,6–ľâKg°ěÉ-ĺx±Óɉă©ËHXc…bG,w†8‹ x]hż6•Jů3ÖXópľŘ‘ÉűcôrĺŇş ÍŃČP# Ússm#Y;2mŤ‹ŇvÂâ(ݨ˘˘ĆŞz_F†7ÇÄ–ş&i_…cGŚ 5QË•ˇĆ¤dNŽLXce;bąÓÖ¸)˝ÜŤ±B±#–†ľń Ł4đ˙˘ÜŠ÷Ír¬ĺĽ Í(‰#‘č 5W=żŰµîjŘDZR¦­±K8Ś)a qjôÁĆ]Mf¨1ČHXc-NěĺN[cŚ…‘°ĆúĘcGÔŻ"C lą'µ_Jp ĂŽŕ׏įQKE?:'#®I*ČË'§5 Ş×Ď :15/[MŽ ś¶&3×Χ§70Lµěx˝vîŁ ŽśĹćfĎÝLŔ0ó´ţćć ŽŮÁŽXî´5nJSÂK[Ĺ2ÔĺŢ {VmYŁ‘čN”źŞr9ĎlyDŢąGŘWÚĎEŕ·î{°şvâŞČy*‰ßźžÄ 9ćşQŁ‘°ĆĘ"vbů㫼µM…mÜR†`G`iżpüMçÂÇ0÷ ŞvŇF.řčę1ß3!–ßó;ź’W:áŘ˙2[“Ń|ČC„`G,w†PĎĂM»5Çáź}Ý{`'˘,6–eÄ[ ­ßiůŢö'tślµ)‚.'×WŻ2쫬aGtÚš÷äŮ×gu$KÇ3ô Śc+…cGŚ´5ëîyƸ~ÉvÄr§­1ČČNbÍvD˙ú–Ś5+‰#‘0e ;‚#žLee±±ÜQF ÂéŚýÓˇä ą¸ ĹÁĘÝŇwÔ2mŤ›ŇĎď|š8ÂL"ŰĚ»qŞýňôßţÂćh–KĂŰď>„`G,żP0;ň‚<€ĄĹą÷YY8;Bik8śe‰OVěű;ž Ů{đÚqJ‚i0µÔĄPĺ×5¬ R÷•Óď?ĆxËţ/…[Ó;ß8ÍĎ-QţĂŽqË‚A ŤîŽDłí 7-[[ë–®!ŘK±µCt™Ćqş[uŻr÷JJp´?čr«+–S q¬śÖľvöÉf–^†Y¶Vú_掱ś´5î&Ů_âńřĘĄµtI‹=¨ßuć´ÜŇJŽS©iŤŰ“őd…ňÝ[ú:hČV˘¤ţŁľÓ´™ť’ŇIŤú ó 6;bą˙­BďX>k'`Z0Ë4 jťo¸A]Í‹™ k¬laG,wÚŃ0»V^6ňâČpŠIE¬PěĺN[ăőŻg˘ŚČVąËyq_eZôŘzÄě×Áޱ2+ŐÄŽ *ĎŽ±2{Ă_ď.˛˛qBŹřL:Ä În3ĺ-w2ÝŤ«ě6>×Đ_b6/;˘›=ű$_4Ić/ ZŚŘj¶Żwµ±jÁ ŤŹxĄ*ńĺeFąfř'.MřžGŚ€Żg‚‚Ž0G™ďFĘuB±#–öfůö1?'éťôącG,wčÝűżX6^<ÇbÄŽXÚ˝ÇI7ä=e˘ˇ/XÉh’w±$`çńŠŮm©ű,/ž#;b„áŞâŃbě‘yÁŽ1ĺŔ±ş¤‚e]ßč`¦Ź;â :be;NińĚţ\%2Ń`í‘ ĐHoĐk&ě;1QšjK+óÝr5;béӗ݇ =e7VéíľÎiFi˘ #ôY†±I—U™n<‡ípěśűh( Ďć˝Lv×U ČWBoő´ů L#čµđ°#–^~ľoĐkáaG dďxŽ8č}ĺĐ#Ćî€ăó3ĐŐ®–i?”Ćťé†>c¶Ň şëÂľX[Yo€ñ#ŕxYEÎđáHAGč3v«/8 űBfi!š;vÄŇ×Á|-.{I™hřë…öĽĹ$QĐúl„a‚A‹…ÁŞâÔë}ˇk\î#,ĄKť7ĄAČ´Ęą•` ÇŽX:$’ 5ÄDAGŁ ="©Igş‘O˛‰é¸,âX0aůmw±fÂŽ@pťrúh86-kd0Ś.ßkhěÇMuŤĚńěÝ«&*WWUWVµşbs<ˇ˛eF••ˇĎ2ô¬ ·{° ;˘BŹÜľäý«Ł…učŐ®V‘,/3üPĘ^_ÔBĂŽŔ¦ň`ˇŹű×nç%íďK.ěĘD㤵žJMÉ >–(‡ńŻr«†yÁŽŕŚsřĆ);ŕ­›v­Ü$S>Y3aG,ťď¦Gń2«ÂÂ`a˘Â«}tČ:b-Zě ="Ç"'‘óŕÚ†}aGp}ëÂ'ňʶwŐ}ĆÍ~8vôѵăÝ~ÇśĆĘzvŢŹLŚ:q,L‚bü`d·q7ČĹԊȡąbG‚F3kŘ+‘¨"ź…eÍ;bé×CÓ–ëmT,zofÄŽXvV§i9ľľŔ+‹Řj9TŁ1A¨Í`:ťšžtĂGń8ŠÉBiÍθ‘ÇP@ yޱ´§sREĚ´ Ť‡eďťńEŠ!vcS.˙kž“«Ś S–Ë[!ť&éÍ‹4⤳I;í‡j1V5ĆjĚí …J(đp„Íä‚řĹbĹy9žU=#vÄҺʀ:ŞL+~;/ŘKű83uŤ#ß5¶H±#*™ŃŘđ¨SŰ ŤQĄ(,Sbĺ`Ëň‹Ťn‚×€;ĄčóŠťpěqěvIÂDyA©w`ç;bi ­’ JL“cBU†ě>:Ř‘’daąßrÍvÄŇ{¶k°WÜ|Ą)¤ž!°üĐÇia ĺkÔ‹Wa…cGcÇŕ=—~‰'pňNĺŚŘ( {C}ĆM… čÚ’ŕŐa§łI;spŠ0ng°ž»Ő<:}L[ŘAľ} ÇŽXzI`v䙓Xă™J¬}5™ÁŽ`ÍW•,‘Ńžö{\…_«K–xĹÎÄŽXÎąK>ÁůŢä.4ěĄ'čN_‡˝ěőˇLĂŇZĆŃÖߥFfŤűql1™ÎĆŇR§hcŁAJ´öµsF0K/ ĚQÂc=†cG,}Xmím“Š’Ý4T-TŢťţNy–ĂöÁŚ{9Î v„8bˇjłÖ¦Š˘˛ĺ5îüŁÓ7{ÚúEţ/´gEů˛ ÷^„q Łj,Wő2Š+€ ‰ÝŕxăŢť>ÇÄęŠĺ^m;#vÄŇ"â®;¬ÖCv ˛óvµČČOฦbąWŰf;biřȵ®V©Ca ­«Yĺ5Ýñ#––„—:nŞ,‡™>Ć!(Ę ŔĘp˙®Ęp„Pm¬j08b‚ÜáaŇ ă~Ľ®tŢâíµ ©‹nćPÇ`ĎŤîŰÂÂLci5UűôqˇaG,˝ËÎÝ˝*­čb „2ÎX:ň“ĹŠ{Ö;ŞÖÂĂŽXZűźľsYĐ;Ś!0ŻwßÖě2‡Ž5+ÖTş\S©) išV&ÇÖë}™Î;biŮ{ňöĄAqŤŽŰę7ŔkŘKëb#vľ„8s÷Š&óŰë›˝‡ľEб´r#ć5 ěĄ}öF|…ćšŐÍ"B»Ąá#‡oś–Z[q\˝Ős@†uŇŮAďjŘdśŃNÝą„…*±#[UźuޱtX87ÇęűWn–ń+ʨt6âJ«Ë»­,bG,-”^;ÁͲÓÜg/,żŽ{Źzĺń+oŇa…ąqF` i‚¶xM…;BôyË9u0Ř,B˝uüţĺĎzÄ»óGÖí6,ä–Ţv‘ÎFU{éŔÚ^WG6±#0ž!ęµ|Îl5¬./^Ęš ;bi7í§7NOLg,Hr|yşÇĂ7O_°oڎwŁÍ±ô.ł±hNóQľ÷>!;biQ˙ć…OäY6áÍű8B„/5‚ĄqÉűÜ}|ăÂ!Číy¸i7GpF@1y~îxŞy‰Gkg;béh ŢĄerżŰ8±!ÓŮPż±ń Lââ8vôńŐă2 čµ;Ľ0A+‹ŘK__Ľuń°ĽÁŔÔ|{óC^3/Řͱç•3ČëPđz˛y_U±y‰‘MěĄqZ\ţ\>r1N8î˝~ţ sčP¤Óěot[Ź`÷ňé÷ě›IͲJ'¦1.î]?il´ť őp|éÔ»ňMpÄkpwPLPÇ8<·í1ďĺj8vÄŇŻ†ţúÔű]Ă˝ ăČĎÉYčŐˇ3bG,=‰gď^•Ř‘Đéuâp°#8ĚBf+Đöë’Řk0ď #çôťK8„JěÄ—÷cÍ„±´$ąŘ®3í:ţČę⥛ęÖzÝmáŘKĂG`±ŹL’‘ŁjC±lŚK9¨EŐx+5Ű îÇü]9ńřň˛ď=íĽ`G,ç’–,4‡x,QS˛Ô¸s›ď´“ÂvV“qď“؜|ËÍ×>Ó=#}v˛$*Ź•d€#D06p®O«:v}ä?ňşŹĂ±#–ť¦`”ŻhbšŠśěLX`úĘŃv YúR«0×Ěů€mëň'Z*ł’ŻŰ4kŘK{µ¦•ë^:î­D"a8|SʿϓhʆoĂfÄŽX|ÄCń+Ć-—z‹}•é·ĆŽĄ­ôĽ %Űâ!µÉׄÊ©ž¤%2Ńź÷7Ң9ęĘěÂ1Ó° |ŚEšŇ1».˙bŇę qŠeb"…"rŇ3cM†F7µĄ¦S)ىŦ±;޶D<ŇGé/ńzJŽi ·™Žkv!p"°xŔéŞ$G´‡®J5ź>‰$‡cä$n¤»×{eĚUP2ˇNń ŽÓŞŚňřä(ięĎŃŇľa(üš%‚F5Ą'Ĺ0‰0ŽÓši*WóÁKŮ}÷Ë^p s¤†z)ŁÔg9Á§„ ŐiŐÇiXr9şńAC1Žň•YA§T`!»XČŕËWd‚´,Í5}Ž+ŽţŁ ť=©Gő!Ě,}†]bĂŞ,˝ěQŰřô$ě<Ô´;2ę?Ófé$XA™dG5;)îcÜµŁ«Ęś7Ľ€6YڦöMPUSý695™›“«mţ}tsĚ 2J&ÄĘÉ÷Ă—Xz®ŮE‹mÄĹ`†NĄ¦POľ'¨R†ŁÂ™M~.hĺL¨ČO)‡c`9â‘©ĆD±¦č3ç/ó)¦— ř˘@An2hkâťĐ›çAŞÉ>bĺŚNŽé…š´rdt+lŤ éF=ôIR5̨9NŔ>F%(˛iˇL~®żŤŞĆÄŮŘíaŮń´ěQ…đE&Yn`ełí‹jEăgÇ‘đ‚´ş‚úČůćÓ:(”Żř‚\’HG_|‰ĺ†rbq”×ńáq˛Ő” Z«XĚ”jŤĘí”ŇL r|bP1G¬pÄzÎWGŽŕĹŠ/d?ŤŹ|őÁU‰#J˘’‚Ľü`Ž™×Pr.Y*686Ś]V’, ÚÚŕ82ˇ¶mq~ÎźAJap|xtB÷1/iÜóJŽă#XŐ Ä™›ÄF&ÇŔő„@rĺîđŢóŃľ¶9ćĺ‡l4¬| ÔS4°eK [ą'ťˇ^’o†z˙D„Ćާ”şľUań"L*éĎQcC‡]™ÖÖ˛שb¨[##ú84>Š Q ¬ 8HżôŹ O(@Q^ˇq#ipěLbkcmQf*e L” RµŇcęĹhA>łř’‘ö ’°éŤĚÁĚĽWKL¨§oņ) \PU’#çŽôV546Â._Ř«ĺÎ8 ™ÔGĺ +?hQ ˙(Ů•_TP8B ŽŤ”䣏EAâ‹Ę đ’ÂR_ą5;$şĄ˝&™ Ń(FE4Ě‹aŽ‚VG0ŃŇRʱ÷QUĐ1§g¸źj+MyŻJťŞĆHZZÚB &ŕĹÖäj#ß Żć82‘YÁ3ń • âŘGžÔă‹ö°´PetoľßŕXęA´ÉW,íŰ â8"8I9FrXŁı_¤őĹ—XŽâ Ď«AÖ—ş‰DaÔSđr‚ć_^p s„ĚAÉ2ťŞ2ă … A1ŻŹŤ9öébPyežÄ—‚ă(Šá@± Ą C?˝€ˇ9töBÎ{Sm2Ałt öâßŐĹK â‚LÇŮĽ€JÝ {#cßČĺB8öŽ*a˛¤ 4#¬PC…ĺZÄUĄ…ę ôcMIEya‰ŻéޤöE{XZ9MŘÓ÷%"† ećÂ1óZ‹÷é™ĎtIQ0Ça›cZA+9˘a­¨h|Çž‘~Šá·´°ÔĆAQŠ' P[RŮ~e$Wd&\TĺkÓ‰¨®ś)Ř·XŰ@÷ĐŘđ˛˛ŞŠ€Ş@m‚cmP§&ďŤôµőwk­W¤ 8 ÉÁőřľdW%  µ´»;Đuo¨őT—Ů ôŢ™/•-Ťl#¦¨Í‹/!‚fG™îá>ÔbAZ[•ů˙Ů{î:’#]°.pá˝!CA$č˝mďŐRKÓ’FšŃÍ›™ť÷Î[wöĚy˙bϞݝݷoĽéiÔ’şĄiŁ6lvłé= CH@ ĽjżĚ¨Š•U( —·ÁéŁaăÖÍ›‘&2"2ă«HőrËheAY(Guc&vh|é<öeXĽé„’óq”€ő’ś˘Ŕ ězGc ł*_b9ďŇŽwzČÄ žůů±wĂ>Çśů<p$UĆqÜĺ–ć—¸űů\hľWŃ&=Ż˘Yó˝PŽ(†˙ŃĄ˝ó5^•éA=óq´(!čHFj:_ě'x/(ăpĚ-žo+§[Ő78Žţw´¸Ź=Ăýý]¨¤,Żd>ލŠ÷h™yór釟€:C&Č#öiéó.íɱ~}ď ĺŃödç{ůĘ"¬ŔŘ0şËSâVa`áVAJçó -­ľÜ?#ó©qÚżč=Z&ď|Zb‘[ZwۡÝ}`: v‚&»ů¤Ë9;šťF«˛ć9;R‡{â´jľ÷ uňź’’2ß ż`@°]šĺ`‰ŁďĚhĆĽgÚ*R ÎäÓŁŃ´Ô´ůvÇt–‹»ů˘!¶mOϡY3©))!ňŕhÇŢđ_DHnţŞ(ě’:fš2ЦČ#¸…ÄůČ1âŹű(‚ň‘¸p¬PHPŢ­-$Zm-.ľo ´@h™Ĺbâ…sřwI_;’¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤”ÄŽ$)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$}u)‰IR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIúęR;’¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’ôŐĄ$v$IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%é«K_>vĶěI(GŰŽDĘ1Ž4gĎa¸l?ŠĄDR*٦>eU-ČŃVbdëBŹßŔ˘ĺsss‘HJřPĚ©NÎĄ¦¤†×6;7‡SSÂ͢ŞHJř¨bäÁ4şÇĹĐçŕ87MŤ.ťcâ }ś™›Ĺp…÷eđ:=;>ŹëY{6-%şÜô ŹÓâ1Źłsłčfz4méU-ž#ć(#šž0Ž3ŞŹńá453“Ť†«ß©Ůi¬íĚ´xqśĆ-Ŕqf˙&r'5ÇŚxp„<ĎĚÍdĄe.˝* ×äôT\řęGü/;=>'¦§0×á´HŽcS)))™ńUÍq:;=+ĽŘčÔxzjZ\”É" ÁLĆqdr K#ś#Ö,„0Ü(ŚOOâ߬´Ś87q9ŃŘôţÍ]ŹĐ¨U(Őpť-153•—™Îqxb®W\ÖăäĚć/Ä1ń441‚ኋ ‚Q+ČĚ /68>˝/Žř7g!e˛šŔMOćddÇĹőM0aءL ź3C5ŔÄô$şY•^ŰŔŘLUnFv8G¬¬ đáG¨¦˘ěüpŽ5ÇĽPŽ‹¤áÉŃ™ŮŮĹpÄXĹEab¦çfŠł ‹őŹ BŤ‡sś™ťšÍĎȉËn¨t0+=#.ĚĐÄ(ţ]P}őŤf/Äq|z*ş$§pé­‚/ővqQŃ‹ä881—HĎd1„!›/Í-ZzUčăŔř0´DxLJ§fgV,ÄńÁČĂśôĚpo‘IFúÁ.Ü(ŔpŚMŽfçÇ…ăýáţśŚ8.’ —đď‚ę+Ž”xŽ‹!ř˝hZ‡Ľg¨nŃŔ±t¨8gŽPăpČËóK—Ţ*ÔÚ`8ÂťU¨qü[śł€}éęEĂű¸HZ$Ç®ˇy9qáŘ7:€ĂŤ† Ĺr3sââ'Ä‘ŕ OŽU¬/vođ~z4˝4†Os­,( /Ö9xľÄ‚Űś8RçŔ}° ÷°ę(Í-ŚËŕî@O~fn8Gx/đ`Şvľv`şŞpex1*ü»"·8¤ †ëÁđĂü,ŚjŘĆ ±±Ş.*_ŁmYeˇIp„†Á1Ž„‚éęr\$Aě!‰\hqt9 9–ňíض/†ąÁ\̶}vnvTťä¤…ŻYîmĐ„> ß/’y, Ž)‘”D}/†®ÂŕŁd\6ˇčLII‰K”vŃqá…CĚBW-ń‚Ż&}ně-ţ;ß ůë ‹9§Íe+„Ś2Ë”yʨ¨ľ[ĚR‘ű€C4 źË'ó…ŇˇŹ¸]©ó¬mZůüqľ}/Şr»©Ř͇< ŔÔ„±iv±Ş¨aţłB ÂĚě¬ÍłdEŇ‚jÎťŤWUĄFŤBŕ…b<ŞÝ0?GÔ3=;ă‰`ż$›šŕżç;`BU`Jµa¸ć300<•i)Ń@«€†Q‡(ФQTOô1‚ŞüSIA#–j Wf4=Ĺ@·đ,§tĚžăଠĎÎÍŤOŹó;]ókLâ;ŹŕXt61:9Ž]1‹–F~ĐAí¤>GŕŹóíۇô›ţ†ZšpЉ2#^(†ˇđëLµ…yČçŰҦŃŇÚŇU 9ŘŤLŽ ŽéĹ9ţy„.ćŃ^]TáŻj|jâáŘTRśSč×ýcC˘Ź6„pE^±iCŔş‡űčo” < ĂşĆ r9*Yin‘_göŤň ˛´&Ätű9˘ńăäK2Ň2*óçńŢŕ WŔ0;~YĹ2D1°lŮó2rJs ýűÇé´”ͨ, 8Á öŽ ĚŮΨb%–ť;ŚOO`ÓČĘdýŠŐţŞ 6=Ăý“3“Ô.´gE^‘_ź I1VĐ]ey1řwşůㆲš@Žh+¬ť’śBż‚#ä™9Â8VäŻ0ě]×ŕŻî]™WâgŠŞzÝŐŞÖW–éwűhëbUe&ÇąąŽî1W/a¸`_尽﫯ąEóiąk]7ůďš’*˙~Ę ĂĺTe+ĄŠá ¬­­÷îËÇtĺŢ ţ{mÉ*ěđý;vCŃŃGpDUţ¨&¨g¨…écZjZMIĄa0\ÝĂ˝˝B/gT”ů&ÝC˝ÝCÎŇĆb\·˘:°ń7ÜáéưŽ< Üxp‡?î\µ1°*Hş†#{CŮšŔb×ďßfŽůĄ>MźŞc Gj{ >…ˇ˘±4Z{;ا…á@UţÚžá>(vDˇ% Ô ßŢęëÔzÉQ' ŐĹ'Vś{÷ťŞ2s6®¬ ,Ą㙳Vq4—6tNs÷-—ˇµżf«ż*K•˘Bú»Ş°l>3t˛ý2˙ÝPľÖŻp %ZtPHŘŇî%UQ@m׺ZY“]ŕYa{_g—;×–6| âăŤűw¸*p\]TîźnĐŐ{7ÝbŐE+ý†Ö§ăać‘>¬A$Ö–®ňŰĐ;ý]w: ł +gkĺ?;Ä­Ţ»lC15›ËëüËôIëy׼ŘO¬Űí/şÝďv—Ë1o{UGĐĄÎëăĂ´i‚¶¬ RŔKw[řăSë÷řË`í`¸ŕ*ŕ`Ö­Xí_¶Ě÷JdXm|ŰÔ} †Źm誢rżQjěicsŚJPĆBnëë„–c‡Ľ0+rčçxąó:›cKMwy ˘ŔµőݵtË T1×ţ2×ď·C$ś>ÚĘTađŤmÜTČóñAúáZ]\QW  ĎŢąĆ »Ŕ2Í=íwúďńGp„2ôsĽzďFż[MĐšbS¤;ď·>¸Ă^4ôüÎU›Łßi<Îď[łĹá#MŇëct]Ůę@;Ő~…‹ˇUţą†UÉá'Đ–(fXmpĽÜŮÂĘ#€ąö«&Äő·g\ĎaCyť_5AŐźl»ĚĘäë[žô·jäĚíkăÓĚk6P5}ÖvIŮ]ݡµŰĂ“(đŮ­‹üń[źö—é¸ĐŃĚáˇm­\hqů#ţűđÚťđBj8~ëüć¶güe,%`mřýŤh_š»Ű`řČßC/Áî@Í6˙Ž N‚R_.ýĆöçüUaů\ľwťĎLŕˇí®nđ/m¬Ů›Â€ër°v»Á.ÜŮ;ŤĽc·0H…ŹăýKť-ŁĚ1-óĐÚG ˙zá×ü74ˇżUĐ–ď6Kމő>eŇŢŦgÜ‚ô¬#uÁ˙űůwůďßÜő’ż8žďh¦řqÄňŻ-©ň—üđúéîVnsĹş-•ëŚpó ]mbˇA ˘ÇerUű´¶v„žŰ°ßĎôAË)Ţ<>WżßďĐ‚ăů;M·´R%Ş_YéöW‡–}ZÔó|ý@Ž˙tćWü÷óşÇ0µżn>Égď«e°Ů!‡!ŢłzsŕŇţ‡Óżt˙´_ÜxheľÉĆUő¸[Z¸Đ›Ęk·WŐĹ`§Nßą::Aą ŽX¶ţĄ}úöŐ&íˇÝłöů'Nď»MźQU+óK_ŢtŘßr¸%¨Ťý^¸Ç¨ĘŻÉO·_iěľeÓ@h˝ÍVăŕ[ŞS·Ż€)}D{v¬Ú¸ą˘ÎĎôß®}Ú=ä¸LÔťŐ›Śpž/Üm‚}ä'ŕebpÄFî%WŽ(ă_h _]=Öĺ6lWő¦]AO´_ľqżťźl©X·«şÁÇqŕ˝ćj¸l‡ăÁµŰý„_^ýű˛_ßňTŕą´ŠńÇ˙áđwüe,íś»ÓHĂM}-Č(  –o:Pě™ő{ «=93ýnӧ쬂¶V®‡€ůkEC…ô7d~ďšÍAe®BE3Gtđĺ†'Śý 8ľÝř sÄ`nŻÜ°wÍm?żô!í_0b(°/¨ č˙9ö#ţű[Űž­ňť™ŔôĐr˛ÓÝ ăŽĘú}ľ- Ľ8Ř a×OŔ@˝şů‰@Ľă˙ýń?ó߯o®ĘçKĘnfů©ő{ýKű|GÓ‰¶K“j ŕp|fĂ^Ź‚o?şq¦Q/mZXŚUűˇ0Q›SUŃĘďíz9°ĚąŽ&ć=ÚË Güď @Żţřü;–ËňOź˙ˇż*Đń[Ůű‚ő?ĽvGP™ p'ÇrH…Ť˝ŢŹÎľÍ˙Ë ČńźĎţ[‡»+ÄJş5bĆ9rŹ™–}d+ČĘăQĄWŮü Ă%wˇŘ9;˝ávř}č„aG đŃGźä@źŔa2Tʂؑńáqźä@$ cĆŞŚv¤otĐ·m4»4·ŘŚxaGî+$Á”ń1MiŢs¨±#čfÇ߆âśÂ\úęěĺ4UĄ9¦¬Ě/1NľÄŽ Ś ;!UQ•ĄŹŹY0`ňş†zĄq!‚‡­‚±O vQŔݮǖG4%ZŽŢy\;Ň3ÜďžnÄŞRĂ•WbÄŽŔYďrŽŘląlˇOäAg÷PźÄŮ0Çňücą-&éěµ|„]‡Ü}a§§#—&ÇŐĹś\z©­ŻÓďŔ@Ű XŞ×Y;r»˙ž4 ¶Ë±¦¸’ćÄôT{Çě´¬šłÂ¸`G Tčc Ý뎊Ֆš1€¸`G`‹oőu(üźwô!Ňň|ň,!Ü4”)v…•´öŢńw,jěŰŤĄýbG FZ´ű• Ś{}Ůö` F[Űi0×Ňjˇ’ú˛vˇF»[cVŰť&ظ˛ĆđLÄŽ4ő´ńQ©ä¸ie­áŽ&;‚…ÓŘukÖç}Á`5řŽ&ñ#¨Ć®VZ‰B˘mh‰-ëŘ3A«÷nú9b­ó©Ípě8^˝w׾Ą±#–ÖK[«Öą‘ÄŽ@ü8¶Ä#qő‡™—v뫹§Ýý~L“Őćž6Ž-1A±rŮľ@^¸Ű lT…;«7±ŐF=MN4ËCµ%U2hzľŁÉő¤9NÝUÝŔá žżÓčß €_řÄŽśëh”b Ž»W7°Ť•xÖáčéAŕyh8vď™;ŤĘ·ôúíŕxpíFřă™ŰWÁѱʂ˛­"~|óAGko‡Ż˝Ąr}•ďÝâpě„ůJç clk]±Í'üáŘ8§Ú/ůÔ´Ä~NGł !Ü&„˙Rg t—QÚöŞúroĐwAěHÇĂnÔfů¸ąÂŚĘÇ;ŽXţÂpÔŻ¬1&;ňiëy örČ9{IŤ>Q·ËŘz,ÁşnryIÚ]ÝŔP'ı›ç=[‡ăsőű9ąÖ>ŠůĎPŹ\h°łMÂäqö¬ŮěׇáŘ‘ÎÁűXh~ލGĆrP¦ťŔ^ňHQMÓ@4;+|ęö•Ž%•ű×ę+;[öaËiiŃ łrź­ßo8rqÁŽŚNŽżßrŇĎšđ9ÇDbG 9r©Čť&ÍĆrSřñ#ýcCď5}6-vľTöҦCüšęKđrţ•[ç:ÉŘ>żŰxĽĚÜkc ľ±ő)cʶ väâÝć‹wÔבşťlµáńľŁ8ş rZ^Ż4aŽpo°¨˝»{E¨ŔxŽÇkü„2Ž0Ůšă«›ź`Žđm°´5GéîYëËÖ<éó±#pP@;˙Ă‹öőÍOńů*쯛OÄäŃÁÚíÇDbGŢĽr´K BҢi(Éu8?ąřž˙3ôÝť/ÄŽüâň‡÷|1PßÜö,sěřůĺý1ßÚö¬ń0.ŘX–7.`r´•Ë!­Ěéö+§o_őW…łÉ‡) ÇŽŔüuË â(ý/ÔóÂĆv‚ ^ ˛ÚŻnyŇŽ v §QŔË2˘i/n:ı™úÉ…÷ün,D‚wL­: `ţ6ě¬Ţř´Ŕ|ĽÓtĽQ€˝\Žé/m:Ě{|p„-cŽ<`+rŠľ·ű%ăôxAě¤ ţŞźă÷v˝dX™xaG~tîmTe8Çŕř[»_18&;ň`äáĎ.)±§PKÄŤ6·÷»sqÁŽŔ k=OŰ Gş1ř˝~ŔJ8v~ ăaµËŽ0vÄŇŕÝýµ[ŤĐÉ‚ŘxqşwtŠč·ľSÁ”ý퉙©&uP0!Ë€gnzvCEo0adoÜżMĺQ˙Ŕ‹–L6U<ţ©))«‹*Ůď…‘şőŕîÔÜL,fŻ˙/3-ٶ¸Ęj-âUaŻX“ÔS#)•…e ÝĂÔŔĺŘkÄĺ ?{#ć›HěČřô¤ŽŮąÓě¶?7#K.¨yDă l$‚9ňñ#”F>!Îiéţ7|±#Ď©XÄÄ•}G“gű:=ëťűŘÉ gtJoĂÔ˙§¦ř,€™Ł‹/,“ü )‰µĘűeA")ÎŘ‘đÚxžć<ĹŔ Ĺ;â?“…Ť—vDăĽl˙y–ĄO|H•h|‰é¤ň ¨Ć™ŮY˙ťÓĽ”TîÔç2Ă˝A%˙ꙬJ?3Ś™ZVŘ(š±É Ű×xúśť–A3Ąň®3.Á[s”#N{ůe#8Ó†{3?GnŤ*&q|*_biÍkDżÂ±#ŕ8$ňFăpś™öź\0GążÜ°#‡Ć9«ýH¤8;ź/Ś«ˇaľ‚öĚ!Ě,}xDxčÇz˝C ^Ř7ę"aŘ‘Áńá@d’.l&P ÇŽLyá L¶Ö+ó }°#c:iGCĄ»J}ď ,;‚7NgŔŃ©pě–ˇÚö­3Ł4Đ_ťß@WzcĂáŘpĽűĐ8ýŹaŠ±Ď¤ĄíÂAň`śůĆ;‚Jđ?ďi°Cy9ƨ†cG Ěš5Ş‚‰4N´Ă±#0U·v»1SC~˛´=Ňp3¦BÍcĽĹŽÇÖŢ»ssÁĘdmé*ŇuŘ´čť^€Ž†2G´Jf‘TŞ(žy ÇŽ@Kg^Ě…yTŰľ$Č(ئÉ04qÁŽ´őuzĚ‘ŞÂ2CĚâ‚iîis\&ßč×”T’ˇŇţY’㟤¤lZą–Ľ/L˘?ěMTś]`ÄřSěD"Đ(`8*\\ü%Śů¬Oě‰őÖĘő´·ďUř’NłM†r3°*1M`g›†cG°"nÍĂ1/3ó(ź$;Ҩŕ ćŮĄ&»nEµńĘZ8v¤ăa7«/O0A'FćXČ9ńŇA4#ţŽąó°‹ţf.c¬JC̱#ĐKśyvéţ“ôe…9>ŮvYě=ýŘłz3y_«BZ˘4LÇ7.}ŕýÚůOzjÚë;ź' ¬đĹ °šĄÁÜĎnđ¨Żpě8JI–^ßŮůť+J|‰ÄŽX^\ČO.Ľ7ß핆#†÷ŽąĐŃä‡ÇWŘĆ…üřü».GĂÝł°f ď=;ňńÍsî6Ç42hĄŔ™š™ţ—soÇ™˝a Ž ĂŽ´ô´˝qĆ˙+[o¸đ›WŽňÁ xhF6;ŇÜÓţŃőSUă7]\ČĎđ%DTĂ‚Ä;ňłKtúű¨ç€q!Řn¨¸xĄEÓ~¸˙5ÁŽůŰSż`Dľá˝ľă9ÚaWňĆĹ÷9b‰ýÁo—ŽÇů–v~fÎ8řô7ôҵníAt fŮPě•ţęł7&} ˘ďě|±ZgÄ>`>ŽtčŰô·/‘ÖěŕɆcG`z¤˙)©ÚW8.ŘŘ;ňüŽ(tďoí~E>I$väŤKďßĐq}/v˙ĹB3 ĹqÁŽĽyůččôx$?wůE"ěä0…cG ľ®?¸íÔbĹ@ř·ŞČD™‡cGt*”fOÜ:ł˘ś|čúýŰ÷•96ËPľÚîak‰ŞčÓŔŽŕ˙6–ŐPĐk_7ž+Šá9ŇSÓ*śsL±ÚÁ‰ĐC'Ęr‹ Ź(;241Ň=Ôçm’ó!=-­şĐŮ«ę7'ů{nąĄĂdĆf°#łssn˘M;’‰€5ťŰOĚLA@9ş@~Ž™łmż7îX$’•>o”6;"“—HěĄw TŘÍt ę md‰T $RRMĚJvDG˙íůFÄŽx¦IěČüô±#U¤çÉ%ŕ™çWľÔ#KÇŽäÉúea|4$uYaG°ĆřVKEfí\‹®Y±|‰{÷ŠNpÄ ý+uÁ >NŠ·ŮÁĽÄ$Ń×Đ8HN/){Q׬(Wî”樞S®!ąŐD;}©S—vDbńh U:×űMMIÉÖp‡Ń©Ř ŃJÍ$ŹÝ3őĺ/(0ęném‹]z˘…4ü‹áÂPOLOqĂEc2<9ŞR=iJǤĄ¤Ęd ĐőéŢL3!ŘĘyeą=G Hě ’Ô4â84>‰q€śČ™ĘËČö —vŤáQEËŃŁá‰1îcvzFvz>öŹ ňC´S6!潪qžbpÎą’ŁËkZ XźuڱB$ ňČ '=ËP&;i—p |eČ˙ŠÜ"©|±#pÝX€ŃA )`1“ë7.ظ¬ŔäĄ'yKw\°#]śS]ĎZZ4:0;cĹLy“…aGĐ}5}ş±+xŐpIoŘz¦ŕhBUvÄpĐ”ŚDJ6'RÝ…cGzGbÓMĂŚôŠKO”sśťŹŹ{ř!ţ–« ʤć\:vĘá®ęŁŁżŠ˛óffgyŇAkŠ*¤2 ÇŽ`¸DŢřôśŚl™ţˇ4·HŞ»pěHßč f {± dž Ú‰n¸ÝßĹĘ+ŠBŠYy~‰T>áŘ‘ŢŃ“ĐU5y+ íĐnőŢŐ ÍÖr’ !ż/ÎX+ňW@hÁčÎĂ.~X–W28>,LIJÝŠjéŔ„cGn>¸ĂK» +˘Ő-8®)®ŔZ€0ë«3ś•eýŁŽÂÔ7‚­Wy&b—ŽÁ:ĺ>˘/ĺĄ}#±,D@c˙żtěŻĂť>őĘBAĆŤ9bÓ»•­˝|Ł –gqvţ=÷<ÔŇkRť|ý~;&đ#Ěňféw°¤Ő~±#đŽ®tĹ[ô±é GíëŰ…¶V®‡}Áŕđűx!ďxŘ=ë:4đ%heŞg¬b(L A€l”ćOڶčÚôŰŐEĺPzě™ ňíU¤E ÇŽ\ęláăżŇÜÂě´,±¦ěŤ+×Ę-w°#°PŤ]±ř2FĎíŁťM7¶B°#°eç;šŘ†ŇéŐ}•“Ö‰wl®Xe-Äw`ôjKŞŔ‘/LG÷‰B°#ŕxöÎ5滏'=C1ogĎšÍ2őH8väĘ˝ë°ř4ŕĐ +óKnőĆ"jŕkÜ-˛¬°#P€íî…)ú&”j ˛Ľ•† 'Ű.±Ű ‡Ť¦ą ~lZY‹5'DĆŤPV.ŻJĘĄŰú: }ek˝„yĽq˙6sÄâĄ8Ágŕčę´ •:+çĆ g«“SohBö†r¸'.GŻĂu;ĺűI!Řřüź¶^5C+®XřŇEĎşˇ TÉ„l°ź€î±öě\Žc­çÝËqěJ ‘!"aqvž@’é Äş‚Á1z Čťą}Ő}ŁÝ†Ô,Ň?€Ż‘';Í ­ŹłgßZµs ŽŽ&ĚĚ9âM•‚osôúYÍŕ+řEäú̆˝đa l 誚Ćî[ ě@ŰÔlł´:bwn˙ĘĽRëŁkß^U/oË ÇŽŔ^\wď8 «j®u·Š{p Ť—Ń—Žiéioq9˘ËWÖ\íşÉţ ôˇaAtZ§«µ¦bÍz˘n§ř†cGÎu4 ­•»iĺZ<áĘוVo«Ú€Źď4~Ę×x9Ú¸O ś((Ŕ:J‚Ýń+ OX Vu‘cśůYyP€*—Ś;ë$#VvjđŚűF;8î]łĄ±«•ńëĐ„/l$CŔż˝´éô“ñ#^?u§ßqH`#`j!„Ě €Ő†› i—ÍŔßň–¨ďî|5ď§îŠĆ|Á~AYźŁrC«„`G`yĄ´ă[rňY o×Kŕ±?Ů~Ĺĺ=P» ˘¨^†Ńĺ0ŻzuuvdxrěÇçŢq?Ůj·C 3bő}÷+pݡ…ŘOPWŐÔn?qëŹ l˝a†ůç3żâ3IláäÉ‚ëgÖďŦŚtęg!„0%lÓŁi?ŘóuyÝLvűźś—ÝT^šSdXř!ť÷ĄőşÜy˝×ĺ—‘ó»űľ.{±těĚÓű-'ąGB¸¬˝®Á…Ëńűű_Ăď7źdC†±Ú·f+~ĺ$ŃnŚ±ß ÁŽ`!KŽĎׄÇŕřľ‰?~zń׼Q‚„AqşŠŔnżöL–ŽÁše %(ŠŹožĺo_Üt°ˇĽ;©ż>ń3^VO­Ű“$qĎxđ7°Y;Ńv Ľč ]UóńŤ3Ľ—ëßÜĄ’Öüĺg?ĺwŔ®Ä3˝´é0Ś8ţĺgođç×ďĹÍą—ĘV›Ż?>üşFĺŕcĘßBK¬Ň„aGH9•ÄţňÝ–>7Bźź™ý˝ž…¶tě,#äśÂźĐ„ŕ«]­äVáŮéYŻn~BV‚Áf˙ŘÍłÓsł…Çć‹N2-·łOŻß#Ł'áŘĘ1IUeça­ˇ<ăB –PŘÂCc| ¬<"Ě€bůŕô»?x·vĎ©}–z–ź‘C'9ęš°Ůi*V Nr˛ŃxĆs¬..‡íCćî6—ˇRŕŘ“ŞĂv].I5Žñ#đǦggűç!;-S+HR–[ µýLcK°Í ťš™!Ž©‘Ś„$ ;‚  {r‰¦¦bă źSG¦Tc1ěč>L łűÍá]®Ö_îÇñ#nŢ‘ˇË¨Í «âđ0ŤĚv!ŘŽ ©¸°ŽD3¤Ămę4ť÷„ 5¸×')JUQÔ۲gfc5ŰA‡č˙7:„cGćč€Ńtx`¤ ÇŽř Ţ7MťŇ¶‰*ů*R<±#ó!EŚGs¤3=˛/OÎR±#łâő,Tž˘eK&0R÷,+ěČôě¬Ű5Ť'FÁ@€/ů„’‘¨Ąî¶żGßDăľ{­é,/”LALRŁS(ÄI3€ť‰íŤµÄÄ=”TżĄKj 5fGů±¬°#h Lšľ¤†®°a9Ńg¶|ť%'- : šW2XČÓ§’JiF Áக, 1™eI Kj Óĺe+ŘN S„¶ô±Ůq™á¦Ęˇ ÇŽČëW˛T<>c+{„ňhΆâ!ń„ŤĆV—,7ěHŻ@-¨Kj4>†Ł}) đQ01=5"ŘtŠϲŠâ·đşb€ ťŚëE„í˘ěČdď¨ÚQł 2Ő%5ę Ó2ŽDX´ßîâ&ş#ç1;‚A0‚ôvLF•X§+äG¬ŹKÇŽ`ÉlĎĺů%XY ĚB”x8.;2éÁ‚X”˝–—ÜËÓŢpě†ÔŁvÂ˙ĂXŃÍ‚ ‘m®Ö©Aŕŕ˛2ÁlĘ>†cGä­Ř˙ă·č,§QˇO0ż’#˝ŻÜ9xź•–’ś÷ĄcGŕ‚‹^§ÔęËM:ş™# Ëű&C°#Byř^U¸"KořëN†Nñ#ŘDz},ĚĘĹęŔŕČ$·5%U*7‰ŕÍX`=tEh@µ«„cGnőiP+#piT¬őe«ˇ—ÜmłRÓh&şg¸ŹÇÓ Ů–O( Ě„L†Aţ‚s@!­[±K»ăa/LŘ ôSĚ’€ťpMq%ÔHË}˝ýÓ=ÂČË|TKÇŽ`ńÉ –*Ö8Ę×jŃk‰üX:vDBÜň3rkJTe ±ˇ…bô¶Y%#Áŕđ˛J×·¶ă#G+ˇ{·T¨WEŻßoge˘!&žíÇ;‚îń­ęŃ´­şŹWşôýâ®H`"ŚÇa H­:xaî\UŹ…Ăń?K…¦ę ĄXüf*ÜH&?±µo.Ż›Uđ«Ű ©˘C°# "bŔŰ«6`a…şF–=ýŠ5žň ÁŽ´ô´óŇFęWÖ(@Ćm:łV:asEť,‚¦’é‹)j{©óú蔞Pť#vőŢM®®F O»A58«ę˝á±y±#m~Eöš"Ó:šyY­.*_-!Ř׳:âHľ­r}AVŢ­Ţ»ü%šdśń-+ěČɶ˼?Âϡ(Ś#GęvÁhr4Âr“‘`ŤCŠŘ{ÇúĹrćŚb(°wÍfLĐ'â¨}SůZ¨ŕ§Kj ÄÎu¸”TŚ 4ŰąúJŤ8~঱µAÝa!0(¤R'#Áč‰ôű6äjçÍ+±QB™Ę‚2h!Vw0ľ_óĆBB°#B—ÔŔü۵O¸Ŕ ˘©ňɡZuI VčőűäÉŘhŇ‹â*+;ň^Ógśś Be‹ŹŚ°tÜZZ´ěŚ+üä[źÂo]ůX[4UŐÎęMőÂĎ_:vä|G#ßtŤ÷JĂKg°`!Ç • 6aŘ‘ź‡Ű .©YY L…ßńFľC°# Ž˘%Yěy+X(Ź-˙ßź~‹ź®ÝQ·˘~#/LxÚßßó =áŐń[{^Áó·®e$ ŚŁ ş‡`GІ>űo|Ôs‰EÚŘŐĘĘĆ÷;;_¸©@!1ĺđC ‡Va]˝cŐFô§ Łd$p¤e‚on}FZ‡ěv§b 4çź_ţ°ĎÝÝŁüí‚Ě\hˇknR“u+Şĺ˝HKÇŽ čîőźţnAV.|>€N~B°#żşv [ Bż¦ĹţŻOĐŇV±»×¶>#•Ďұ#ď·ś|0üÂźXhűk¶ÂC€‚µÜ 'ś‹ ÁŽ ĺę)B7ˤ˝¬Ýň䩳Ć^ ;‚ ćgmÝđv˛Š6 |ç@ \NFüÉŰjŢEe2ÓŇ©•‹tvŠĆ ł"Ĺĺ{×Ǧ&čIE~)Ś#¶`4é`L°Ł™ť›Ut˛©Ľ6+-űY÷ř1’—™ŤĹŢ=Ô缉¤§F©űř!…đTzo&ăěg†&ě<9ʡ~ë›(;2<9ƱäŚh:† ~ťsF§'Îņ`G`żl7fš’’‚fŘ:’Âőă ˝$ď&Q—%)ěČÜ,‡kSh&Šéɉi“¨4túĘÂ"Y‡cGśŞ"ś ˘Q ó!«úĽŘý;öŔ­$‰I,vD?ś31AŠŚD ˛ćřbGR•XšŘ‘Ô”Yí˛ÂŽLÍ̸˛k§ęô!–;Ő-”0ZĂ)ń0SĂ#\´—M4KGéřÝAzȡA[WN]“8 ­#¦ÝR*¸‹Ô·ŘLąăcD–vDľ.4ŞE‘íd§Ő—ˇ”˛)˘ úĹąŁ ¶GĹCş¶†Ť“î~8iđJPqtAÁ‰iO´ ÁŽ r™ ť°Š(/9˘GpFĚ`ö‰#ĆŤeŔ¸¶fYaGđŐ U42ŁŽóC;ya j(ĐŁ4<1ĘÇýx¨27Ś„%™tŢ$˘ď6† ŠbŔ=žłô-•X0öFĘ ŮţÄ`G௰ :§Ŕđ24łP Ä#;2>5!/:ˇ"†K®é‹/;‚šĹ”Y´VĺÝÉ…Ţ“ˇÓĄcG¤ł5Eűaůи¶&;‚îv1–N Źköľř¤É>bŔ+ Tw0Îü qmMvD}5Ë'Ą-ݫ༰*®B×€qăyç‡DKÇŽËN˝†Ľ‘$Ü”éC2čÍ`˘ě÷‹âëM™–cť÷ÝÜ쌯ŁË´p$ü""ĚR|˝OĄ4…cGśč¸V‡>^’oŇkĽ? •Ň;´§Â®‰ńpĐKŘza§Çę ŁM›Xůи¶&;"ż˛ôI+=äŐIĂö[_X3A­_‘[D@´n3F=«céŘ‘›˝,TśÄ’ß·´ć”Ő.;r­űf,SHn v_OLĆ_NŮćŠuĐ˙X>­âáöŞ ť÷yT!Zü6$/4~Hô8bG®ßog»ź§j¨‰=tô^1FL´ŔEă/gĹ+ĹV}Ůš±é ™e„/ %îĹ–¤˘#-=íd/lr WššńĐńjTŽyr‚ÁW2“3ËŠ‡6– !~†Ľń*ĆĎéŤ÷-7Ą €HvD^X›ő›âm}ť]˘°ŐĂ-•ëNµ_aż?§d°¶¶¤JÎ{v¤­ď.OYŞ\ÉîÝ`3+Sî‡`GčÂËpJ;Ý+/,7rQ,+ěČQT۱Ş^a˛çf?ááúíaůľ2]”ŢŢ× eKý€§­ŢWîhf« y CvAżOFˇ91kŚ&±őއ]@ý2N1Ty˙˝ŹYsÚJě«Ů*/¬ÁěS¨rÂŞ€…`GđG/ %čuRőPĽÂľ{uĂ©¶ËCnĺkK«H7~tý4o¨ €Hv$vaŤz[=Źîoîi»ăÎ;8âá‡-§DĺŐ¤rݰ˘"¨‹ĽĚě3·÷`?·a?vspQÎQ}ÉűćzvÄýJÍ-ňUŢiü”5á®ęMŇl…`G %´žQ A¦áŘ!ęÁ¨Ęx<>RĺüĐÖqčéą­˘ťVĽşYaA ęu[·eň…őpěČ/ŐqąóĺÁZ…‡đ®¸o…ňÇ%bGP9_­˘kŘĎÚI†´é!L vD}Őí|Ą÷Ś^hMÝmňőn©ľB°#ô8~Ą’äÉň¶Ť1&ad-|?Ęš9áLU¬ňŠ:RG?¦‡şk·É|N!Ř‘sŤ2ËČź>÷űTţ3M‘«iéŘřHüUz4ťć]«m^[“0ěÝšDń;lgháü×O~¬żT±;ci/;!Qq4ÍrKĹzr!ȡX!ÖŻÜE†`G.Ümľ‹îëźq˘>ňí©łŕ+[‚ŃŻ 41vä™ j‰ž*› ď€O…Ч*We łśm»zĄdr„ʬP÷ŰVÓ©=ţ§c^˝ręŞ/«W/1Š„%–ľ&µÇ14Ş•0÷±Ü˝‘HAf™Ş¶ŢÎQŤ;ÇoŤ3ĂěúHg•„!“ÚŻ˛JZ!š…}¤3jÂŽđ’ ŠřDôi€ –%;‚čCj§ 0"$‡fíD| łó&g¦ĆŃx]CjJ*aAĐť ‘__†~B°#łřJUĺ“”z$â<”±ď켲 X:2‰=ŚâW:í`GhćT¬ÄD0Ů ÂŽđC˘ě!ědF‚-rÓł!źŚaÄŽX^€ČrƎСˇ—€‘ź‰[B1ę”`č$!;‚ Â"’Ř‘2U]Ř  ÄŽđC˘ěÁDř#@ŕ÷<"솉ÄpN~ě~Ű-Ä;Â0ůĐŇ{!ţ;;˘żŇGcócG°™d±Ô0µ‘Ř (‰ Ýâ±#5:˝‡Ay, –p†‰J–ŽáŻ$vÄY4v-‘©h(ŘĂé݇_;˛Ş°ŚÔ‘ÄŽ`: "ü0ƹˇD!Řȧs…ŔŽX:Í—ˇT4î ƎXúa LD>„`WÉZ$v„ż’ŘK‡·›{Úů6:ĆŽh@Éř#ÂŽČwô;˘¶— _ěČĺ{1H vu˘ĽÄŽlÓ±g;˛©\˝‘釉`1ň‰ůż3섍–¶ÄŽäedŻ**—©b;bé—Z$vV@‚´üŘz(±#`WĄő†ÄŽ”ćÖ–ÄâÖ‹ÄŽŕ«Mú+‰±ôŃ'—Ov„“![;Ҩ"Łź;‚áâŘ3cG ™ÎĹL.vDžłbGř!Qväę˝ücGĽ‘ĹbG°RHKě,ăe±~—-v&ď¤HÜBŘKżo-nâ{m¬ ěĄó«Kě,;˝ +±#Đ˙Ő…+ůJĆŽX:ĚÉőŘчŞ;z¶~˙ń[Ů 3L$PB´H삉čP¨ÄŽ`‹ńô†˝ď7źä.3v$ ň ë ĆŽ´>č] ±#2AťĹ9ů;B0;r¨v‡DŇ/;˛Ó…‰Hě Áލݔg2/v„JěČ~•PD5FbG |ŕäh{áÁŽ(€tÔçÄŽŔýĐňćÁŽX:dČeâ‹éő~Ĺ0‘HăËÇŽ€Ĺ­©$vL9t‹ÇŽĽĽé0ü4;uÎ@4ĆŽŔř6ąf‹°#&ĂŽ`¸8ű,»“Ř‘oďPA8;ňüĆňla‘ŘŽ €¸UrMQĐîÁp˙GÇ/Žţ$/QbG  ĄsľH솉lµĽŘ (‰Dâ‹aÄŽŔĘ?)¬[b°#ú«Xś•°# PrÉ (‘ěČ?„"ŚyWJüŘ‘ŻoyŞ8;ßŔŽĽ¸éPĎPź;rńn‹şbÉűhńŘJ(b`G^n8ŚĘy[ÍŘ‘ PŇĚ ě‹|L±#«ôe4_;‚_y8.;ňp|Wńc‡ˇý|ÔŘZńÂŽŕ+ŮZ‹ĂŽDuŠë aGŚýŐұ#îëţ_ěDťFő `GęJWő ÷%±#yŮ(]¬©GŤńDľĘŘůŐc‡Ń_uYŹ'v_]_}.ěVesOŰçÂŽ r<üĽŘüŠŽöüŘ‘ZNńŻ5vÄұĚ8bGÎŻ>/väŘÍsĽC\$vUÉK÷‰nˇŻâ©bĎd‘ŘŞ3^Ř|uB©Ż$vdaěĄ"±ň‹ÇŽĽ®żňcGšşo±#÷y±#ď»WŰ,;bD‰yZ}Ulů°#–~ śźZěHVz&‰ÁŔŽd§gIŻőKÁŽĺ8iň?/v$˘Ň·x‚€‰ÇޤĄ¦ŃŻľvťšUxŹř`GTE ÄŽXţżľŞôď˙ΚyňŽŘňľĄÇ;"Á‹ÄŽd¤¦ˇÁnŻ“yGľ v3%1ŘŚ!ޏskqŘHť›®*nŘó"›E`Gř"§ÚÇ ;Rť?>51)®§Ić±>?v„.˛IvÄZyGř"˘äůÂwÖbG* ʰ4ü×Ó$;‚qăy_ěH»şžĆŃ˙‰ÁŽ4őÜâĚŚÁz‰]dłhěÔ`“đÇ ;˘Ż§‰ĹžuŢ‘UEĺX› h`ěšqĚ˝ČĆZ\Ţ8üO®ßyDŘu‘Mí¶Ł×ĎLÇnq°#'Ű.łź°Ä;k]޺Ȇ?>^yGvŻn€ݎěüĚsw®}^ětgŤő(±#ó]Ołü±#Đ„tŠËq©yGPĚgÍ"±#ňΚEbG^Ů|DzkKĚ;R–WäżłćŃaGö­ŮJZ”čńĘ;{ 6vKΗ1î¬Y8fŘ‘š’* †¤ŕkĎpźĚW!wDKÇŽ ęŁÄŽÜĽĎz*TŽjv?‘0‘µĄU0Xú"›ĘAF­Â±#­˝wŮĆAt±Řń±őA ęđĄὊĄU‡<ÁŽ€Zî·[–3ýk,=u‘M_,vXSR Mĺö1;!GH/Uľž¦­Ż“ŤÂâ±#ăĂ2BżIÇ$vĺkŠ+5Ld‚ZŹ˝+É^sO›CÝ#<‘q˛ĄcGĐťXŠ;‚ -ŔJI[:väúŰ,ĆŘLPZjšaŰU Ń&ćq{Ő†Ŕ#Ř0ó¬a e<ţqÄŽÜîżÇb™§j¨±ĽŘĆzçc\PÝŠęB•ôk˘©ű/̆ňµ0I7E›ýŘaCyʰ©E=´˘ŻuµşęË®,(“'§!Ř,‡[nÝŇG¨–;˘“‘¬ĺ ĂŽ¸)F1vÄMF˘td[D!Ř‘Ž‡Ý|.‰•E8§fu‘Ťž5[1&—î¶đB ÄŽ Ś\Ú!Ř‘;»řÔŹ±#Xqě}aaJI ÁŽ@/ŃRĄ?X»&ł#ď:ˇc5¦ĺ±L$ ÝR±®4·ëHľ‡ !‡¶‘9?v sďęÍÎ1Žz(šxćöU^Đś0 ą)F;˘Ż»nćúŐn8>,ď˘čµÄŽfçďŞŢ$a"š2y‘ žHI ÁŽ@$8óşžF÷ńzO;Ď»”¬n€–čŹaAě Ln®X'ÝČEbG —HH ´¬ „;Vm<Ńv‰­@ěĆ‹á}(Ś8AŤd$–Wa~kŰł4Hři¤őů°#?»ôéëiÖŕăN|T=~fý>鑆`G°l§a"ű,/vD'#‰ˇ!—Žůä湪$ ĐŰŤź˛şc@ Qb°# <ăM1âĂŽüćî—ŕ óÇěČ{&ÂŘ‘żÉH`ő`_Ţ!mÔ€]­ů˝ýŻ]Ň0>!śÓ§­xˇ-;e«”‰»Ň^Űú4T+\™»ë‡ľyQÁD»ĎŘLďµáaN!ál anČLFB‚ąĐŃtASüج)hr 8źí ŠŰIě~(řěČÇ7Ďń6n?©/‰AáÝŐ ;ňÔş= |L†‡żěHKO»ŚĐ˙É‘ďZ^ěHĄ./±#őe5ĎčĄýOg~ɇ™‹ÇŽ`“¨ăĺÎ@˙§'ľgy±#(‰ÁDv$–ŚÄ¶×í”éұ#?»ôaç ŁL;ňgÇţ…E‚ ]ýŁsďđO~C§1°#D` ÁŽüí©_°[v´Q’Ř‘×w(Ó&a"?<đ­üĚ/©Lâ‹ńĂD,o2’Śhfíăg°Đ¨ËwÖP2‰yqÓ!¬>lÁţę3ąEŘËkă;ź“‘čňú6ĽÖTŕH†LbGÖn;$ŕ!ŘěŽ.|˙ť5ŐŢňKÇŽŔ»řPl:(ĹÄŽT»€˘„aG޸ô>ŘŔŽüWgˇ©Ř€ú•5\~éŘčuz<˙ť5ŘřH§(;őuý~»!ßž:‹ĺąMě”C°#zŘÄŘ‘'Öí ˘ĄÎ9#NľĚ)¶oŘY‡`Gč`AbGęJW•ćÍÎÍb«(±#–Ţ;ŘX™ÇĐD°Đŕvb~&ÉMϢ ŁÄŽg†!ŘŮ€#;’M«.,—Řl«i.đ,ć—…±m»•pěćtbf’±#üć6žL~~ěČśmŹNŤs,™^’7°#ňÖ ĹŽp\Řš;‚î Ůzěz˘"ţsY#ěČěÜČ3vD•aěH$’Y¦ŘŞ$‰‰'vÄ zOýú‘;b9·Řé‰?v‚:çÖOB)sćXz%ČňË ;"“… %ذá#ć-úĹs# z­4+ÖgFjšB“Ě87ÝŞFÓ#ZŮĹ4‚Î2˘~¨»FŽbs "`(iÝ´ÝŞtz’čJąŮ\0‰”iYaGPOş Fŕ«”# —29YI‰´ČŚf $zÁ’†^ă‡2 Ć9;=ËÖ*;ÖŮ´Ěhj*žĚĆ8F1řUě‡}‰š9c©¬\čťţˇĂĆXŽI8vdxr”!G4ž7ś 4 Ţ?Ż„ĽŚlĎĐÄ(÷“('kYaG@}c,˝g4¬y5ESR ő™âţ <ÁhŽłA6ĐHŚ„vb0'g¦‡cŮběŇś"ĚoďčC¶KąéŮŕĎçĂ%1 V˘°#ăÓłA#)±vż´JÎBvúŞG 0iýŁĽ0Ńe)iKÇŽ@evtB÷‘_Wš’c˛těj–1/­žˇ>Ö X…‚cvÄŇOí÷¨żs2˛ŕVb@jm»HL\×`lT+ JńĽkđs,Ę.n_vÄRq¸n^ˇřUqNÁ} >¬,(Ă*ŕ·íAUepą$GLş\MKÇŽ@†{†bš 7µ,·XŃB°#–ŠQuňKs ŃÍžá>Ŕ®ÇąB´0;ročü!ş… “mÔ­¨Ż›M‚ý¦ăa/mŚUą8 ÇŽ`äG\MŽu @OY„Ŕq}Ůj•žÄ‰{©UŠîäffßéďbŽ„éW?t$RZŁcBí"Ž'™ÂÔ†`G°ghë‹ĺĚŔaeÝę»ËIË4R¤jYËžcŮ×–Tc˝ČL*ŘţI3´tě6ś¬CŔq]éjTxÇŤűŞá]ąFU/;Ň1ĐͲË^WZ uÁ§–‹A›Ů†Bła ŤÎĘ«:jJ*ńQNIž°©ĹV\Ţtđ8bG0;ś5ę…·NřJ×KH‘Öňr <„ĚsšńÔ”´öâĘ=‰Ń©*ĘĘkąßÎę úł¶¤ ‹ť¦ĂÖ·”×á‡×ş8×˝˝ąbťôLB°#XP—*ĘĘäj×MF?—ç•Ę& ĂŽ@–8ĎakŐz°ľîd'˛éÔ^zŃ!ج‰|ÚVµ?DŻ'g´®¶Ő‹ÔPk!,ŔÍ•ë°Ř%”g÷ęÉ1;Ň7:ŘÜ&ĐK‡Ť]·X}­/[#1¦!Ř5Jm—f\?Ô ¬Ucw+ăö`Şč˛¦e…Á(1˛Ş4§pKĺ:ČŹ* ý‘ş]0šR źP&ď63$ |ÓĘZXţafZúŢ5[đCăÚ,aF“Ř:ńŔ¶ĘőЬľ śŐnÇĺťč[+×ĂXźľ}Ĺ1ß¶ŇK#üŠř!¤ű¦ÓíWř‡űj¶ć W3;ď”ř!Ş‚_}˛íŠ„ˇ`ˇAÂoÇšš~°flż;néS{é'„`Gŕ´źŕQµU,O´]â­_ýĘÚ5ĹM’›™łoőćž‘~‰M|rÝnüđ–S®wdoT?¬Ľp·Iޱs•ç 9;ÓŁ•żÜY˝ .Ał@Ń=_@îwB°#ť=—4A)ěĐÂH,vhsw9F …ÜÖ×ÉÔÔčKÂĐż§b6N+°¦Ô;®©…¦ź­Ě/‘çŃáŘĚ‹|E?„`°ŠFS_öBm–Ž9ză,+@pÄCŤ3 ăůŠxm×Jv;ŻŹDČů™ ű`>Ľ~š-–ž´ň!ŘKAšŽŹş?„čî®n€„wq2§ĚÜçę÷C_É«¦đ„ ÄŃÖVHŃYMbiřÔşÝXgcřNĂ…ľyĺŁé,ŐCö>k»xoŔá·G´¬Pěôű pž^żb/Ő!E~~ůCć¸ËÖo˝ČPN(˙ĂŢRväxëüD?\·ă¸…`   !yĺcVGßŘúLá[WŽŽ¸?„q$€QvÄŇaK>)Ú±Ş̇-§Ś,#šäµ­OĂűźĽoÍÖÍuXÎlµˇí1k·v}*ÖřöĽ*O)C°#X°Śĺ„±#“înB%Y±úý–“Ľ´×—?Y·çĆŰňę±ßÝ÷ É1;‚őÂËŇ]čĘÓţĹÖŕ!8E0·ÝĄ ËřâĆ0 ŰFS˙Ŕkrx€yäŹP8pt߼r”oX†î=ĽvÇĺ{7>spfľłó%ř*˙*âýßŮů˘LX‚§÷“óď± …˝(É)úÉůwůt ć¶JďŚČD­Ő;ú0fŹlĄÇ¤=Z:vňvŃu˘Đ¬PěŮ•™pEâ÷tB‘??ţŻ,ö bRłőW×>iëu<:4I"¬PěČűÍ'›Ü-ĽP| !µĘźův˙ß§˙ť9Bz±Đ0é¬L ^ ’ă±#Ř€üő‰źń›O­ŰÓP±ö˝¦¬Lŕ@Bučô$źŃŘdDÓ;Â?„ˇä›—ŹĘľ¶íéóMś” Kě??ů}p”óňҦĂ0÷°Y|ÄÔPQĺ#3‘`" 3SŽćÔířć¶§e2Ý켠?) © ~tC.Sť-;öw§~AŁŽďď~›»ż9ů öÇŕpJ 0ětö„+ň­íĎÂŽ»ţŠÝA÷ĘÝÄұ#=…1Ő,‹˛ňź­ßwwŔqr(VHNŽlá|Ř´DýP˙,ššv¨–|ű+đí©łŘŮɂьÎÎĚÍ.d}Ůj°ćî6ĹZצ v źĘDSS·şŘ‘Y{–ĆŢWiąßÎXgxhÝC}*ˇz†--ĚÖěÜěE‘ÔFˇ0+űPw»ŽęĄ)¬Ç}UáË(íŻojD ŤÉę˘r9A!Řxb„î%€&%7# ű,¬YB+ĐۉpČŃkÂŽĐńűĚěě=ť"…~ #"ʱtŔË=ÓŽd¤ĄĂÁ‘Đ&Â=fçaT'F¸( <žăĂplTĺMvÄR'„ălŞč<Ą#Íâ危†`G¦f!\.ĉ ĎMĎÍp¬ZD˘ěHŞľˇ-äĆS|ζgEôś±#nňřĘ xvÄŇ—Ý8_¸—–HDA$v»‰˘ĹcGřŰ$v$!v$€™3F1ďlygÚŠvÄČ2b!¦Ö2ĂŽ€‘‹ŰpĆ\âlP'áż°e{¨—K×™H,'ËmŚ9S†…€#ť˙:@ŠGHĐ…tÍqÚąěĆů*Ĺ›Q&ĄĽ+|YaGŚo)M wJr«LĚLĆ.˛Í>ćdd§čÁîžs3µ|ňĄş™HŚ,#FUPÓdƧ'\|O@±ĽĚl©Íñ#0crĚąŹD2ź¨Ad1şYÍsťÓ2ĂŽ`G=Łš2'î˘"h§Ą_lĺy¤îđ¨âcIvΚ3ǧ·–?©42ŁéäßčËnÜü4:ď·\w°ýŇ)±…±”ËŐĎaN·‡•(__¶B±#–Ž”Ś É!°ŞĺŠö RŹ-;biŕÂXG§ýp‚˝—бô®q—¸ş+çR.´pěćŽĎÄŤŞlíećę uĎP“ŔőóÁßpp=C±#čWżČÔ˘9Ć–pY^ )Ř®ˇ^yů”%Ś)>V­”—ޱt€C€)ÎB›s]Sě·pěÁÉÝO6ĚÜŚPSUîŐ3DáŘ|{7–ĹÄÎHM—PËâś c`=ŮhÎkKޤ‚ ÇŽŕ[u[„Ű ŁŞ•)DqÄÖQCľś…j«+­Vmť"E%jŰŘ\YˇŘKOßŕ¸§Ź¬ü†¦tŐŹŕś»sMÁlďí¤V<°#Pkčă¬čă´0‚PŞĆ_:v9„NAĘĚmj ĚcÍr@βśb,f.RÂ×ď·ł2!·G˘67‰ălëńÄŽ€®tÝ`7ŐÓG[]=KGöĂŁ×E¦8fôb]©s“X:H#M#ÚZąú˙ň˝ś2PéŰâ '!yc…bG@·úîr:K IŃ—-ëänąn7qüÄ ŹŮzK"}żĘ‚˛­:„|3vŮŤWŁŘŢ5[$Đ ĹŽŕ‡:ŔŕČ(Wĺą˝oZˇŘĐŃëgŕĂĐoiżĎľj¦·¨űFO Uc4u’Úw˛ŚÄŠeŽSrM]űëvIŽÁ·2U{¬*M`g8EKÇŽYF ŽPă†4&;b鸝´/đ»FEŞË—6’®c8všđlGLEÓ+üqwő&ňčŽÝ<Çn^š{ CŁC‡Ř¨ľ-DÔ¨ Ţ8Ĺ»[cds1wÖ tŠ9w'ÁW”‡Đ„ôţ=LZ.K¨5q#Şý´{ő Svű˛Ł7ΰ« `JWÔ1…`G@o]ůîU5ҸtěśI(Oś1Ź~tH°#Pri«QťŚÍăÁµŰ %‚A߸řż'Uń|Á‡yF§§G~…Ş‹Ĺš°xëśdQÇŮy†kťŤ2pż˝óyyüŽ‘9E,íËWĹ^n8L.7”<[í4Uą-“ą~së3p_ńC™xŔ¨ ş×¸q/;bii—‡34†ě˝OË?ĚşXhvŚŁ.珉†`G,}ŻËŃfŽôUNF6 °‰řĺµcü“’ě™,Vĺ&YÝ ŞLvôŃő3×)ͧ¦ĽŚěaq(ú=_ĂvŢţ?ťýՔ땡Ěäě4o:tnŹÚÁŽXZ$ä;y9|´ařť˝ß ýĹ?śy‹YČ2ŠcţŠomVÖątě6_wúÍX«2sś¤ z `°  đüXi}bĹtAŤńśĂ„`G°Qb<Ą„3GŢ= /ôÍn‰„—ćőŠă»×wBRčŻnąaG,ý>߬m®´47›7iznFŽ?Ť6ϲ:ŚĂô¬éTńýUüĂ'­HŚ"Ú4¦x®ˇ˛§g§ĽH Ą’4Gł Ë ;aśž2ű¨’8Ą{ű87>=1çąUÉÉţ$^ŁĆHfZş •ˇDV<u73%úO cĄk¨JÄ* ÇŽĐí9FÁ ÖZöcî70Ćm5Çĺ‡Aď<›Kzŕ™ÓSŁScÜGú:(|‹Ş ř%_‘m/4‰Ż)!Âp‰†±´—ŕßÂu6ś3k!쥇>!«Yé™C;Ĺ;˘ë™Ň~•VťžU•çăěĄ>Žćm5D bG ˝ĂŤ3¶4ŻHb±®1V†íĂŃekŘh›ŢŃa8TUP1ą´1Ë}±DyAQře,.ŘK¬ô:c źľŔ§ťÂ±#–­®ˇŢ™YŘ1'# 9ĂUX;‚öt;WŢÄ49LÄU†K!Zčŕ´7˛™/Ë+28.G4É€WEA©äť=F^4ČjY^‰Ľń»©^oČíÁ8řĄ:;˘9Žw<ě‘n•ĺŢV#‹a-ó0ÇŞ‚˛<ßć$.ŘË{sŤë}Ą`­+NŘ8B÷†î+  1bŢëŔ&±ď•oĆŰZýÖWI«Ť±ş7xß@ŁV”‘ë±ĹŽXÚ–u™·ôpU–Ë( LFë>ĂQS\)Ý h‰›˝†}A=«‹ĘĄ“Ś!íôśVă[”ńGñ#–6@+cy^ÉębS™';byo®!BëV¬ň…pěĄ3'µőÝóÂľmL, SŐŢ×iŔGŔ#ćW&áŘK‹Ä­ľ»<ŞdŮ0AţQ ÇŽXúu®kÝ­Ćń+<¨V?ľąaG0Ş+>â´ k Ł*• \˝wĂpČWć—Â`É>¶őu¶;ŃP§*|»ľlŤT¨äJçő‡^H4xAĆ$Gč·+ÇP¨ŰjVx”ÖľĽ±‹86TÔůŐW8vÄŇBA5rÄq鸥ŻúÖňk8n®Xç7áŘKű$Í=mBG,˝siîiż7x_z{*÷rőFąĐ —®tÝžđ€°ŐĄ3«6F}Ű“pěČ´âx«3–đL<´]Ő ţľpěĄ/Akt“C0m*_ËH;âxąózŹfŠý×îŐ›%GčłweĆK_sł˝ŞŢŘ‚-ÇKť-†ú‚ŠŰ±ŞŢŻčâ‚ÇÓ·ŻđđÂ<ř8& ;bi#{ľŁ‰]G4á¶Şő>Ž `GŕžhżdĽ Pš[´§şAÚPýą;× g"!óśŃÝ×˙Yzw|°v»\ÚĐKXe‹f+_îĐÚţ]y8v/Ţm6ŕ#ŘÇ^»CP€ă™ŰW•ÂGŠp/÷Őlńs ÇŽ€#–ŹĽ ÓŇ©2ŽÔŁą= ÇŽ€Zî·_čh–OĐ«÷yřqÁŽX^DsÜ]ÝŕW­‰ÄŽŔüřćŮ|DO¶{q˙ÉC8vÄňŢ\C•aw ‘ž 8~tăŚpČŐPV®ä«qĽő‚±×öG¬E`G°ý˙´ő‚±Í‘}vĂ>y¨WütűU÷ěĹiÜŽUĄżŤťř©ŰW řšýDÝ.żëŽÁS5a¶şĘmëf‘DʵžÓK;¶jsÓłźßxĐžŽA’ˇęŤ¸đÚí[ĽŹŢ<ëÜ\ă/„_™' ;BőĽŰtÜ@'Ŕo„úĘó臏`–źYżOÚP˘pěĄ=´Żź28Ňm5ňɧ·.¨)p„˘đsŚ vÄŇŽ±ĽţĎŇ íŐÍOĘ’0@ď·ś”‰˛,˝…ůÚć'üď|†cGŕ®ró<ÁGřX }„« 7DFţşů„L7bi_î…Ťý—Ž!Žo]9:ä=…9~q“‡Łş€ććYă·O­Ű#úřnăgĆË!°z/5’éśá÷Âß08Â…~fý^ÉńDŰ%F„Đ€á[”Ů\aâăñ#–F„üüňGĆŽ ő@}ŁěĄőŇŰ×>1NČŤŰj‰AŐÍ5;!|Ąá łâ„-€ä´+C ;«Ťöľ­…°#–žě|gfg%v¤ˇĽÎHČa-„±´ …‡01=%q!đ{ëWÖF˝ç*·z; ěşÖVśúb‡˝žFBÄ€éŃtěM¤:6=b¤ yü±cÂŞ”çc*ďHżÄŽŕŰň‚Ň"ź‡Ž±´{ Ë2çÄ ťú°ÁA7i[n1í-ÎÎ÷{/‰ÄŽĚÎÍ «ŕ‘ëM‰W !9 ,ę,_HtAěČś=y!üŚ´ô(m v„âÂîiO ;‰žŤŮw‰0p„fś—FTĆÜ”ŔüáŘ[—1:ăŽX‹ŔŽXĂ Ń=Iŕ—>7vÄŕëŃ”ŐNŹS…ľ—(bE¬ČĽµÉpŻTÁ$×F Ţä6:Ňěć«Í©JłŐ…‚Ä˲mgą‰«ë߼‡Ižh§DRGŚÖŹ­1k ˙q*WE·=©[´ŽhĽľnjN…ş=!hąęŞćśE«oĆR0U–®Jg ˘‹ćĂÇČ3Žů 6š#_y2_chŮΕZţ2h’dµŹ±˝žn»·»§ç3łźÝĎgvţŠýe?˝3{ôt÷ôékěV۲,ÉÖa]¤HŠ”xßI€qßw¨ýfĆ{Qńňe=R,¨¶^ŘŞę!+#ŹČČŚď‹4 s„ĺŁĎŮŹ6Ăť%©Ç …śJD†}fnfÎë#öTÖ†ˇ##ÜU±$ħPdba>ˇg'ŰŕË\ŻÁ (Ѭȟ‰ĆgŐ)uSť«(tľV‹HCP Ćäh™GUÖő|nĽ Ŕ îđa‚Đ6ŚjB—µŹóęÄ_ˇe"´Š%ĂeEŹ-hěŽBŹ)މ`˘"ăú§l®žć8Kúň`•ŤľšJ©>¦“ ŇVĚű– Ʀ'h­A?`¸¬CAP'Ąvŕ˝qIJ}Ćpý]G/Ťń™)LĺÜÂI µŞ˘†ˇŹĹÚű´rśNÍ0ŘíŻHÚçqLÁÂ2ůí­˛ Ĺ;:39­(SVTš´Éę”âčeöVŢł…#úÝ8ćubjŠ4B+X ㉆±2 žťéŞffR) ţKT–”[ýTě%ôZ[(N`[GUbÚ4GKXÂŃŰ’C‚Veá8812­u¦Fě•TŘ8b•Aě±UC ĹŞŞ «úBΗ^¤r/YdŤÇ¶j&5;źžOƓط‘Žw?jÓǢę’J+GTĹę *ÎZ•ăGŃŐ”Vď2GĚD‘ŁU«qÇö,“8ş¨4›^•Q4ě´‹l1‰XDCŘbs}yM#$ahr"¦4¬ÖďĂ_1ŹŁ)Ó 7ëę÷ăöjłČ*ޒɱ­BaßÍ6| qdL!VP¶Ő1ŽŢ©Pyq™]SÓĂ“c”xłe¨“qV´5¬˛ŠZ545†:ˇ”PĚŠ˘Éäü«ë–[ý=¬ ľ±ÁaĹ1ŃX^łĆá#sĽ6pe đ«Kˇx+łéU ;ŢÚl˘=®ęކ&ÇĘ’ĹĐ9km©oĺ+j­@g襛ý”ݱĽvm˝čěPŞ<ía¦őŐ­x0Q{˙͉Y×ß "‰ %PţĄWG‹Ńg4).!’áęuő+­UÁNµ‹hčŽ,ŔĘ+ýťd‘ÁuS“}u¤nip´:«°łĂÝC#đŃÇlĹÎu·Ăźť,‡#TYżÎ­†őÄę€&‡‡ÜTQßTY— ZŤbÔ*ŤŇ6yŽvˇˇĆQ^=ݵ®Şc@űäŕ՜̍ĺKcî1ŹMjuŹ/őuŚ{ÎjSUŐoW¸đŢëř@UµË­~ű%ŐŞaüć ÚV[9Ţîh˙˙úŕMĘŤÚ\Ußָƺ@Ušăţ gF! ÇkśAyòŐÖóŘë‹=×ů«që ÔWž,łĚăÉ®‹hŘĚ\ ú ' ZĄ—jĂĆĹ66šů ąŘÍaÜÓRÝŚ@;zÇű˘9΢@Kuٵ4!<ü›Ôa_¬QíŃB…É´"›łTÝĄďčBaîkŮÜt Í绯Â(` `\ęË«ł™!™‡iłÂľ[8¶÷߀;ÚŔhEu#ŠY9biŁ \…†ňZŘ©l%Úţˇ5;¬eŔîĆë™T–”Çł·Ŕqž‰JŞZQc-†Đ´M´µyťucućÖ”ě– µˇµŹ(ç`YŕYß A°Ăż¨ˇˇ˘v[Ž(Đ™AŰ—[ ]B S…U(śŕŽNRr¦+cC÷@!Ě‘ńý«jšěUéd“´1ÔešWe+&‘Źd…śęşÄŮUµMA ‘—™CQ¶ ‚Ř_¸Ń7>\¬·˙;”ŘßNfŃ˝ŽľÚ‰łU´zw¤d~l.“¶Ú×X]¸UtBŽŞęłű„¨mf ľ}u6ß^˝n71J +I[UśÎ¨Ý—ű—ňdYy˛ÄjŞ`Ó&‡ő¶=¦ßU«µM`Áb0‘šĆ`–%JĐ~ëIĚÁŘĚäBz[€Š@¦p"XX´ | uÄ.źőDŽŽişá=ZĎŔžŢĚülzaA#*Š­NťiCP ŐÝ EĺĹĄÖSńÎU˛…­đů3¶Ů2L© Ś\iÍv2‰Vé8ÔE9­m’S1¦ěA@ZµČś´Ž_.¤u 3łG0”6ž%oĹ…ő51*Vť=˝@‘hĎÖˇakĂĽ÷ň)"ź Ě‘ąµÇ†áÚčw(p˛Üb2_MD~şěHDEQDEQDEQDEQDEQDEQDEQDEQD˙:(ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~écGŇâż1ü/[1Qm,f/–v ąU…KsUV¦řszażX«ZH§ąa¨©ŔĆtATÓTłÔ¶~ş¶[Uµýó ó ^ă cYŞB] ÔMT˘ŠŮÚŻŞŇL;'VXPä:ćUU›ę]¬ Žb–ŞćQPšTX€˙Z9ÎyŁŠÚ…ń`ÔZKë†čĆ s¤«BűŃĹ4z‡V9âoóóŞş «R­#6;źZđ/c° afn–ż–$Š-ŤwŇ©ą9 ¤@{QaÂ*¨jŢăX/˛NPj~˙G1T€ÚP•µa©ůÔěü}Ć\'’Á2¨dő¨Ş!Ť'ă k±éÔ´ă­Ęňd©ĄŹéô´jĽŘB5ňq´?(9sós3ó©9Ś˝Ł8ĹÉx‘ufŃËôBLI`ŞŠ¤§R3sŠăśšť‚Â’DŇş:F§'řsiQqÜ&„¨grvŠ>CfĘŠJ‚e@łS(©Ů;hyqÂŇxĐČÔŰH=\VŽh<ş©†K/ź’, ź™LyóZçőL§PŐćň€VYG§S3ô2S‘,ł6~lzBOćX”,±qÄ\OÍNŁŁ—_ŕĆ`¸0ŹXGXbč]E˛ÔŞF§ÇąŹ•ĹĺV €–O¦f ®PK(Pše(&g§'Sî<& UĹĺÖ>öŹń窒 +G4µaĹÔ*‹c­ŁJĹm<Ę’ĹVÉA%cÓ“&¨ ´ Łj| ÔĐä÷-˝¬˘ÎÚřˇÉQŚ*}F«Ę’vYíŕŞjĘŞ VŽ#ô‹±¶´*Xmž›ÖK˘…zŞK+‚ 0632Jă ̵UQ`®'f§1ŹŔ"5AE6ť301<ăőUUŰeµk¤Źť…ş˛«ú‚<Łan ‹ęË«eŔkxj ­ÂAŕˇĆ­}ś™ťźÖ ŻĘdyąmđˇpĐMjW2‘h(ݵqśĹ\ϸ‹QOMiĄµXďŘ ]YÓ, ęÇpÍb H)Ő•U[Eşcčn¬¨ ®YGé®ń‘é1č(^Ô‘€Î´ö´\q<ą¬Ň.«×»čŁ©˘ŢŞ0±´»ÇXVť5µËe`úĆŃ*,7,1ÔQ-´ŮÇk7ůsSe˝UK€ă­Ń~·YŽł¶ľĹÚř[#}SžÂÄěX'ŤőbŚC¶b(38é.4L÷ňŞ+Ç.ĹqÚăXUk« tĄż“?/Żj´Şh¬ëÁÉQŹc˛Ąş1XĽúƆđ/Ú_®lCyMPEŁŔŤá^ţÚÖ°ĘÚ*pIJĄŐ™YQ˝ĚZěĆpŹRš ¨ueť3 ŽCÝüuCăš`8j¸”Ú™„*M7W55xőŚ   XăĄz][ő*ŠuŽ›–Y8:ÚpôO ÓgԶ޶ŮZU÷Xż2Ł ‡š’Ę&Űęčí‡T 0ĸ´¨˛ZiÓr}ŕčY«úňLP° „ň<©,ň|8–V5WÖ‹aí\čâŻ[š×Yű4áMPcEŤU}ÎÜşÂ»ŻµuË­†Żö»ëvjmť}ˇ]Ç™)Źc-ţ,301Ň;>€bč#Ě:Ô—UrşFzQJ íÇ–ŞĆ }D%7QŮĚ$šWUR„Őôľ ĚśńiŐ0čg¨8k#ě,«/[WżŇÚG¬ŮqŐG5fŔ&ŰAŤ÷ŚöCŻ˘1XŚË*ë­Ö ’Ó­Ś{Zs,]źe=^îë@é3ĘXÍ1Şş5Ň?>3×Nłâh yFĂPú ó.đęęš…“_ž, Z­VëĄŢëüőţ•›eŔ±˝˙Z…R]Z  µ~üĚ`ÉcťgÝOih‰ŐV?-żĐ{Ťżî^µ5Xtˇçű PŞŮTô‡×OóçMËÖfăxľç*}FłV…2cŢŢdyu#dŐZěČ5Á±i­UK\ěꀉ;X]Ű,x©ŻΠ¬זUÁÔýČüŤˇĺŔho|EÍ2«Â„Ç˙é3Šmij –A%ü ¦X­µĄŐŁ`1óŤáîţ‰‘DAĽŞ¤lEuSPabpuŕĆ€61`‡ŢÁ(X=“3·.Ź`TµnÚ¶|]Ąm AĹ˙Ѱ¸âXAµ®G”aŁ€bŰš×Ë€\ů?o[ކ’Á2ĐH§».ń×GÖí –A!đ¬`bęËŞ±1äXą÷Ż|DĐËË7dá8vRp|tÝýVŽçşŰű&†Đ<,üęâňÍM­VŽď^>ĆźďkÇŠ`(Xdh łę’rčśę@1ě˛Ďv·MŤˇy ŠcĚ•ă;—Žf8®Ř¬ MM‰żâ˙mŤ«­ĹŽß8?ěm¬ÖÔµ¬©łx ß_ü??ąáAkČóUφ֔VěZ±)XfxrôBďuü‹ˇh€9+ŻÝ¶Ü"9Pnß8Ď_źÚ°'X´‹=×zDZ ŔC÷n_Ţ4µ¨ ę ş¦ eŕzm´90PŞíXÜ“ŁŘyˇ”jĐIÇS]—P•7[Ry˙ŞÍÁÍ# @VaűPţĆĘšeV-wűo@/ˇxłP_VeăbęSÚimXaµˇŕu®ç*ŞÂUaÍn¶é8˝G=ŤŐńĄÍű‚eĐć7/vŹ(lYe-”!ĚşA~íÜţĽgő6ëňŚŤŐĐÄ(mâ ĎÁb0ŽÂÁ µ €ŞAűw®ŘdÝůľvöźWď]˝˝ÖćäŔőGŘnRă[›ÖY‹ľvjŔsV±4˛ůíŻśyŹ?yëŁÖ20= /čˇ5;‚e śOßş ŽŘŔ‘€7…ě#¶„{Żco…?ˇ*X„Ő¦řÔ­KđLP †Ĺî_µĄÂćŔ|pőo:ö­˝ĎꡡŔÁ«'řë×¶=,ŽG;Î@ńjŽŘ•TďÇ€ EU'o^ÂżpPŽÖc°6,Ć ˝WQ[˛0QW^łcyŰr›q?Źbžź°qŮÚl›Ž_ť|‹??˛îţz[Á‹Ťč…OËĚĚÍÂ{“ 'ąąŞ±ˇĽúÁŐ۬‡Z˙r"ĂńŃu»‚>!čÄÍ Xł°•É2ŘٲŃZě˝ËőO¸ű¨ëšE=çzÚˇĆŃB…ÍËZ­Ĺ`ŞPŚB+(öŘú‚eŕiľv’6Mđęˇß°Đ¬}üĹń×ůó·v~1XŔQKűĘŮ[íôoŰm-SŐçíѶ4·ni˛l¬ â°lűĆuUµ[›×µş˙Qç9x_đ¬Ŕ¶ăáµ;‚ *9Öy®olLŃAŘY«ŤbdŃhu|çţ/Y Ë–>ĂT=i3C°đ´{džŕ2aKެÜ,†zP ' ‹°‰{`ŐëŕtW†#T„Ő8‚~rěUţüô†˝Ö]!ÖěĄŢĹ1^´ Wo]eăřć…Ă=Ţ Öşfáěađ1hPyLuOܸĐ>p"]/‚€í€ŘŰÖ#ôź¬nX¶ĆŞ{á[^éëśMÍÍŐ•Ve3|ŘĽÜî…;Q¦6_đ{­NÎÉ›G´ÓsśUµÍ«j,GÔ°rbV5‚OŐ5ÜK!ŐŠd™Ő—ĐŰ˝ž‰ŮI|¨.©D“°Sî áŔo×ËlsížrčđMY–sÇ;;˘(ĎŠęFk¸m*5sK Ëőpo~aě¦çfPŽLëËj‚^(Ö#\¸™ą¶´ÉxăoyŚvµ›ÂX¬(^„˝‰őÔqbvŠO9Ę’%ŮbLtľDq¬lŃą…ą±éIţj=rL§ÓęD(=ŹĆŁ’Â‚ÂŇD±5@Ć›PüCj=VUAŔ9: ŐsdŰyĄť´ Ű©0ó‚ŠöĆ ńřÝEiuUM*­âcq[$ÚqÖijW¶Ř7ŐĆź­6'¸OÇ4čŔ Pś$T ;˘`AGíÝbYʸ•y :|n)'ě[…XłUhLŇB¦e"kK;iY[Úm±˘é vÄ*ńŽř Ď6PW€÷nł ™†¸»‰5¬ÂĆn˘6/P/^Ű ŘA ‹:m‹Ł” ŕ@/QZĎŽF`dF55ŽľbŽFŰ$ Ćú@mĽ°Ń¤ŕé?Zžšź5Bc>r(f5(!ĐřBą{AăutsÁ‘ď@ă'‚ e:53OŁ‘vĐ;ëNËá%dž«ŻéÔl`Tc0WAŽ“©éyŻ ĄEĹĆ:3a¬ťŽËÁ®[Ť1F•NK…9[A#ŚrH« ˛ž]:šÖĂepDłá‘}¤á Îăö,é3…CŚ®ŕ¨˘ž`(XBźéđČÚřˇ‰QȆ‡* ŠôČÔ”y˘Ň˘yZŤQŻŹj4Šă¦_…­8!°!74¦&ĐÇ4<ą 4dT IŕZűxS„BëË«Ť˝%8MŽűX©ÎĺŐÉ8aGP xŚ‹ö g!Ž×6b04ů´(Îćý÷ŚđŇVˇ/›;ë¨3 (J¶ :Ç˝°  ŁvŚbi+ąŔšm¬¨“Ó401¡ «`î#*ą5ÚďMtÚńô Ę‘4]#}Ó· Ű;úh’yÖ úäČŃăÉĺ :¦Ż|X÷1ŁO0AجJÁŔ擜l©t0ăÁĂж¦rđű§ p÷ŹŞËqyUˇ+ ö7†Ă‚čł±Đ0ćÍUőÁ•Ë-¤ËP_0vŘtq¸‘ {ăŕ© iŁžŕńŃąn÷䱺¶9[€™!& ŕŽ’pm kŢ?\đsÖÔ-JőďTÂŃq‚¬!m‚¸&ű†öj˙ŤńŮLH;8Ń.F0A$VT70cąĘBĚ"^gĹ8úŘŽ?ŁŞlQáîQi—®o09BŤw Ý2ÜB¬ ěŰŤ=9DâR_µĆK=`ĘSkt±÷:Ë1Ë@g^ćŕAÖŵÁ®)żQ€{ą¶®Eú'‰%"‚¸nl\cř *ÜK‡ăş®¶±ÖşF\ŰaŤ cĚ%B‹KnhXĹὨ΄«”XźĐY§ńŰĂ=l­˛ŕ .&Ăđ0ˇvř$ôĐZűÉŃ™[WX™ťőřĎчPÜň­Íë¬0Í‘©q^Ź0ťŮÚé®Ë#Ç•5Ë‚†ďęŔŤ.ď<ČQ”úKRC Ü>Âzž»ŐÎÄ_×ÖŻ+ÎDËđľ % ŇąB÷´Ńí¤‹ůŘ8GîbS [|_ËkOÜĽG‡Đ–BíąÜ×!ŕž.µ¨ŁasĺB^S SUiß™e=Ş©ďCĂoG(g>îŃŠš&yЉĄzŞë’á aT·/o“Fąs¨ŰS™ŞŞK*w´l0„¶řŁÎsüőéŤ{ŤfŹÍL~ÔqVOPĆI@%¨č‘é'Ľqáű)í @6ÜŢŃŽ3üő‹›–qô14ű «l*úwçňçÝ«·Zىp9>Ľîr¬-­|pő6kU^?Í€B°Ë†zí¬?~ébj>ę<;&đńŽÚńĹ·4­mşÂ|ňćĄ9˙–ziÇň Ňo?yóbP™@ ěHőĄŢëlФŕ14ę9Ó}eÎď™T&ËvŻÚZâ9đ[ÎŢşBĄ[5ľU Ű ŽŽß¸`xńÂřΖŤA—ő Ž&RuűZÍh"8b]trTr¬_„†čŕ5úŚziÝéŘčW'ĎźiÝeĹ{aˇhĎ@LľľăIŁTĺű펼Áý­÷÷żôb{éě±=¸gď‰hâÜ÷´Q.ܡk' Ž0ŽŻŮÜSĽxü ţüčú #*9č|˘Ý«¶HϦ«Ěw‚ˇ÷ŃűZwO~ńq&¶÷xŰn#ôüÁöă¬ß0\PtAđńŰ—>ěăŘŢş­Y@“˙ăŁßňç“%ҦĂcWčsCyíS ËŹ;ĎŁŠŢí_żá‹bŻ÷ÖĹ#üő»âXÇYÇOđWo{@rü ýD§ŹŁęNP™@íśěşHEđ×`XO”1ŞB“žŘđ ů€ ýÝů\čŹö|ͨjpr:Í“–¦˙É {‚ĘüďżÄźż´yźˇmP fPľ¤A˙ĘĽcđÖűW>VÁC~ Źż;ô+>~nË~“ă\ęŐłďłŐ ÂěYł=ž|ĺĚűÝŁ®×§}—-Ŕ úďü ţźţkěŹo¸VMúĘÖÇŚ0\=iô˝µ•Źw.ÓČQßÁďCkďăŻĐŢď\>:@‘WŻ ú%D}˝|úě;¨ÔW·=nE|ÂuD1ţúďů–Q{Ć9ú]š/m~DVsMbüűăS뙹Ôď/ n:`ő‚ U8 ě™ŕŻŮ6˙ď{?ăĎ0VĘÍ‘^i†ţĂŁß1 Ŕüňä[|ÎF#ŕË[öÍÇ˙ýîOůó ;ž2^<™›}ĺĚ{7Gz}żI+_.ůř—oňţŢ Ő(…#÷łDpŔľ°ń!ă\îđµSG®ź"çMúćÎ/żÂöůőóp‰Đ;as˙o˙?˙oO|ß±t&40}†7ő­]v L«V(çŕĆę·çžíľb<Ä’|˘-c>úĆ{ö aC“Z׉-¬„Pľ°ęč34,c¸ŕ“˙üăß9Ţ\˙ďOý‘µń0ŁxČŞ5Ëľsżi†`ň¤ J„m9˘=ĐK—ů”ŔSa°ěAŻé@űq0ĄĎÖD˙ÇËźżűŔs(_<ń&úč×%Đ˝;ŔÜ}ĄÓC9ďpAÇ!bŢ˙ŕ“?łůaŮG%öĂ˝­yŃĆ'7ě ˘ľ^>ý.9™(Ĺ÷ą~ű/]Q†éĘꦇ[ď“6ôÍ ‡±mt㕺$Ttr°Ž\ŘAlSÓÚl€u4ŚZŹ˙eC ^îëlďď$vŘR×­ŃţËj˝ŕĹmÔË‹K±‰6ŁfúÖ%.ł/Ë\cůZĹŃhŮOgG4ěmY^‡Ď UTgÓ©ŮĂÝä/qŕ©P™6Č ±ÝP–Ý›kŞëšGžicÁrl"ćňtĘlđĹPđ.}¶tÇ`4„Hże:ĘQě ¬ ŰguÚöÎc±‚Şâ˛`€Ś·˝*•ĺUgńrµ;GFů…y lZ¬FÂU'ŠB˘´4ü…*.\ÄíL+?gÖ‹îy˛D©Ý„ŔŽd ĘK÷8ÄďLĹM0‘!#YÎřŽ9&#ňi]ř¶Řną[,ÂŽh°#ŽŮÚä$-řŠ™afďiÚ¨Ť7Á”!‹‚ˇ¤V˘«(,Ď—˛t3Ŕ ÇŽŕOęĚČV™Ě‚%=1É̆×Â=iĹę5žđ%–ŞĐx#‡D8vṲfҶŞta×®ŁĂe”Ťgeˇaó˛ŮLAPޢ`G¦RÓAÔ©ô˛d±ˇ,±#”Ť#ŘrG‡| …ŽŃpßSQaĽÄSĽ-vdtz"9rôb¬L–ѨÎÍĎŤ˘’.Çx‚›G™*‚eŇ:ýőQa/¦Ç¬J Ŕ)¨.5›·Ô°#`4“EVkK« 뎎úOŤ=J—™°ŹEÁŽ †1;GĺqĐ;ăZah,Ż3ôj8vDçŤJN*Ť)Xě ±6iöÂY°#FŢIMăäh©aG°¨o őú—¶»’ ĆWx{9ČUđÔ¨Zż*ç6{l@€2a!ĐŞę&Ă(ä ;‚ĺ,JţIgkpŹh‡§Ć䢖„±5<épě~Öż-vä@űqĎôűś80ű[Í3ß;räÚiĺlř‰퉶Ýäcúţ•ăsw9tóŞözáś›Ă='o^´:@$ …ŽG—-«Ca/RUĆIh ľ÷µld_čÝËÇ‚ĐdGĂGžŢ°×Ř^…cG.ô\ăčýíRvÍĐuůÄŽüîüÁŕ;Žv®žlŰcô1wěŞ×ΰşUŕřěćGڇáجáEű ś4x˝zö=â(±#Ä1ĆÇŽ(8H–MŞ2ĽľĽaGŕXľ|ęŰŠZ#łČm±#o]<,7ŹŚă)‘„FV.Ô}†$ŔÍ7ť(żpßSÄĆńŤó‡ĚZ4ˇž‡˝Ą MŽţEí~6Üăpě†|`6JÔ¦Ž ÇŽĚΧ^<ţ¦{4á·ěpËżH?Žy˙ĘÇ2 ¬D¦Ľ~ńŃë¶Ăĺ$ŁŃáŘ‘WϾĽ}{×3ĆF oŘřó?;öšŐpŔřʶǸĎô›e[ż›÷ /ź~÷–×lYâ÷˝ÝϧC‹‚ůńŃWÔ©Q ŕőýÝ_!ލä×¶…†ml\ĂiŠ  Ął! "aŔ>ň†ÁV菼$wLÜWěb‚řŞpěś.Ë6G×+cÇŽśënϸp~Úłzű^ápěČĚÜěßúĄőôX6Zް#‡®žřŔ«Ä g6ďŰęąÇ?˙čwÖó„d<ń'űľA§Žđ‚ţúŕ‹ÖŞ í ›µ(ŘTň3a%ÁŚBAq%ŻĎüM„¶`× ·jQ°#ŻśyĎM^b.Űôww?gl!ñ#ÔGĆAˇL%{¶°z$öv˙ýúsi‡cG.÷uĐ#`0uüŘĘ÷.tc¤'–‰ź{üb± ““7ěvg)yI&ÜęŽHuIĄ±˙]‚Řl[Ńžé€:2-ä#S(8´±LĎ2Ý„Âd¬ĆĘ-7Ęg죲,›GîyĂŽ¤Ő»ŻŁúÜžĹĘm`aĚ Ë;qrfÚŇçXA¬Ô‹ Ł´Šd˘´ň‰q´`Di;2ďGljů˙$+T‘Ü,ř3ĘaG‰ň‡qĽyJű‹Ĺ'‰rtxĚ`± ěžÇ]ěSB9ąCŹč*ŕ,T"q$1K†’0ě~ĎĂĺéލ ńÄ»â$M•Č×|)ɇf4?ż`6,ł§őpapUÓ^b• Çd")—H8vdVÝĎ2zµTB1Đ*Š©ÔL:3ćhCšż*.Ç~¨c®^±‚Ây"##*ś;v]“P›xa|Nť NăÖ€ěz713•öŽSń§ˇď ´Ň—U…cGÔÝ+ó<ć ±$ukyŇ—/$;EźÁ]BN ârź\¬‚) :>=‘łŚ’rđaJń Gžţc|8őNZOY,ʱĎaN2¬!†Í^RŘü\ľ,…ń™™O±čŞ‹0ü¬Ă±#py9€KZˇÄć]αXCYŤ4ZącG°¦úĆ്dAi*ďj¤‚‚ş˛Lí´şŹc”U’HN‰`€şÄ/B!Řpěൌ?ÍÍĎqŇ&Č­q•;v(9˘ńú®O»×„cGzÇY8 ó'ZsUÔäK ;2<™ą—D]ŹŹO ]W_^C˛­+pš;žMüjeÍ2ü›ą%Dä JMLY˘ÄČĺ ;Ň36ČX(nIQR‚ęZt^DčĄk]lú1’ :}…V_]Ó$­|8v¤{t€U ~"S}¬¨^&µJ8vęHmP=íaúłNĺ ń…1B°#„há>bfÁšżB·±´ĽaGúĆ{=FpK°s“úłˇĽĆŘ8ĺ ;‚ÁäµL‹‹%špcăZiC—v¤cđ‡-ŃN’cÜp±Ô°#*›HF` çthB¬—W5Đ ˛Ľ„z ;X)9×Ȕԋ‚9'.ˇ€ő±hąűZ6ÂĐ@o¸Ó§AłŤLO°/ bĽşŽ9×}eÄăHËY wůÓ5ߣؑŁgXŮŇr÷Ö¬çîŐ[ń/ÉŘX]Y•~oŐm –I#„ Ć=íý s`"ó ďußDlه×OłECżŘ¦_=¸f»´ÚącGP˙ák'Ů!‡w$sďÁ.ďőĎTîŘTţAű f31<9šáHRË™8ŤV«4âkëZOđQçąĚýe:źbƢĄŐqˇô=±#íý7X/(h¨¨•ůfZëVp“čsŽÁÖćş !#ç˝ÚťŁď*Ą¶†CťěşČ:$^Çęč—ÄŃͰeo_::çyţx2§öD®n“ódŰr#Ž9ˇň—tóoëJ«dh(mp|ëâŢ> ’u]&_ĐYüôFkďę9q3sµ4’ ±č %>­‚Ç7/b« w%ÍŽ_Üô¬*oŘŘ}V_äćĘ™ĽjÓ23;vDç˙żĘˇ¸ä=ž¬Ülxt!جý7/ćŻpó°fyĘ«[ŻRýźíľÂŢ D5¨Ąí™,%N‚Á&ômqŁ <ąaŹtVñ#P‡EÄrŢ.çđ^(ĄÂKŢr€q„ôľŞ‘…v…NŔv"Ęă„ĹČ_ń+’FčŢC‚#”m»ŽÁĐááöĺmÓzýüˇ^O{č‰Ň^ˇL^Řńü[8±żÔmĐô®¬^Ö­8ş»B4Ň„cG~wîÖW¤á‡Dâ ¶tVñ#p˝NxůKŠ đm®ôg<[,Ţu~?9;Őýk‚ďşEg_i­[€+|ü†ë®&ŕŇË»÷ŻŰe¨ýěĚń«gßçŻř!Üx>mĂWă^ŞĽaGŢŐŮDŇ^›«ę%’ě+[…“?;—úé±×ĽÖ¦ˇâfćgůZHŃ÷xÎŃÚ;—3K{CĂją€ů°ČPâ,v^+÷0[l .„SAˇÓ—N˝ÍW!T$KëĘ«iB¬żżűËŘŔů˙ŃŃWŘcű‰Í‚<Úúö®g$ëĽaGŕiđ]{Ř ­­[!Ź „Ř›Čň!؉ź~ô…a‚–P}ô †ˇ ÇŽüÝá_ńމ¬›!´ó‡{ż.÷/áŘ‘×ĎŔöż…–sŻÁŇŻĎŘXĺ;‚ťË˙ŕĹiOĐ*çeË€0Ć-oج2l) ź(,Äľ˛b„ë„í–;ÍĄ†ł sŔA‘ęŇ :ř˘î@«Ó Dů©Ô4Mv\Ĺézľ\ ɊꦤŽDÜîM; ôëҢ♔Žčş…-ţłšĽaG&f§ĽŚĽ*üśĚČTű˛Ü±#3s)öîĐŞ‚leĐô›Ąťć8p¦ç(mŚâÂt5×\XPHa‚ű«‚D ő@ŽŘ‘ÍÁm9 zCP4Ý/óěC—™,v$˛|én°#1÷CZ> ‚OčŃ‚8˘ŕţ#ěYđ Ťű„ˇFę‘ܱ#h€>¤QÄEâ ”ôĐ•QÜ,<Vd¤ ÁޏIG<„IÍÍńŔRę/é*GHŤ&ɬa|ůúž*¬ÉyŃTč)|ő˘ÝŠERë)‘HHőŽ‘Qg´gçgy cNAq˘Č€łA9˘w*R&ČS4^˙ĐŤ:CŁµěŁş®E¬Öܱ#2é¶@E„&a)4^ćÁŽ bđcĹĄtSL¦ń‰byQv?źťä…EHşHž‡K¦ ǎȤ#„_‰í¨*.Ç(a‡ hůCĚú;9;-ŰŚbęnqOeÜšĺ™U†0žĚ IŇJ„ dĺ’ŽȤ#xŽżúŃ$éÚŇjt ÁŽIGŕ@`X'GHČÓúŞBŮÂܱ#FŇ‘¦ĘzMB©G0ŕ3޲*I$ŃGüP7Ő-Ö\éŰá‡`G –#™@{ 1\zëĺVU[Z%=ˇÜ±#2é!EŔQµŁ…%>ŽY±#p§şEú¦Ę:TŘ3:Ŕ ËżZĚÂRĂŽt vó ­-«BďzEîL60ř*gµ~ ĂË}¬S?,—IGĐŚ*Xw‰·‹°3”©GňAďÚű3˛hÖ×­Ń>y-%dó+ŹG±7ĆŻ 4‰‘z$;b$Y®Ó$v‰›bđUž…cG® v)Iđ‚ĐĐtO9ýš°­Ńw.‚‘IG)i”©wŤÔ#yĂŽ\ę˝>›‰C(¤HŻľč—›j`ňÁŞ—ÇŁÔćK}×y‹b”_RŘXUh_[ׂý6ĂGĘ’ĄĆ˝K ;r¶»ťo«Á8ݬi‚Htuł•ß˝j‹‘t„"Mb¤É;‚ĄzZČ޶ćő0@xâ™űt}yMkÝ 7éăşŰ–·á‡r:ŚÔ#!Ř!Ö÷óű‚ŞŘ:©GîEě‘tdŻQÜyžűŘZßÍŹq`,ĆÓ$ĎŽwŻŢ†MÇ!}HJ͆|b…žíľÂ?¤Ô#ľ¤#*4{?lŮGg™Ł‘z$wě¦Xëfˇ‘Ź¬Ű…râƶˇFę‘ܱ#2é6PŻ˝9şŕčKÁ!®”t„FlĄľËFÜMŁšúŘúđĂ#â‡{Vo}?yó˘~Ký˛ąĘ—z$;"’Ž(˝ÔZż˘cčOG0őČç;‚‘Ôć^IěĹý+7Cz?î<Ç ó‰¶Ýń‚¸|µwÇň6rüÝ6J=˘“Ž\rĽś>_Ţú(lŮűW>â­ÜŽ– Rů„`GđCť'ŔmĹ«¶6UÔaxGý Ëg÷Ş­BŔ÷űŇć} Ű!Đ$”zD&A É0UgDdĺ«Ű—Ă‚B`uÇě ›BÍďhBÚ^ąĐň†‘IG)b IŚ`mîŘ‘—OżĂn”܉&)M$źő^)& ÁŽČ¤#xťŕG“¤źŢř”ĎK§2đŕÁ«Ç»†Ý-4§Ü ÁŽ@K°¦ Š&1ŢĘÍvŰ˝OĽÉç*ű×íÂBĂ bóŤ­‡Śî‡cG^;ű>kohB>˘Ôśß{ŕ9#éFŠÔzhŐJ=rˇçę1oďzŠN˘0e(‰'¬é.ě>RĘ$M'`xĺĚ{üCŚ3T®D“Pę‘cgiݑ֧pßSřáoÎĽË?4RŹ„`GńĂÓ™~eŰcĺÉH/űÉ›šZÁ­pě€/8řüŘYv§©GB°#2éÚł›Ńh’·O™Pę‘}…7 ^ ~o]8Ěđx~Ç’cväMőCwˇÁGÂth#őH~°#ł*§ĹŻą×XĹpo^?˙ëěű0ÝX8‡®şař˘Âří}^ŁI^e´Íă:őL:‚ŻxçcŰ ?{䛲aącG~qüug¬RűZwBńrl»(žřă‡^€A‘ęč[»ľs@hbM©GtŇ‘ł4Ř,˙ÁŻö«ţŽh¤Év䯾8빯Źh¤Č& ¦ ÁŽ@Ďő¸›–*…qŃ$žŢ“ö(;s,uÍËOŽ˝ĘgŚĐ–Ňą ÇŽü_ BHL:o‚©Gň3öÎĺŁ46Řţ‡Gż‹}Äß|đ"Sę™t*Ş+îϢáç˙é©?4’ŽRD˘IŕCJż"wě,Ô?čĄMDH‰&ˇÔ#2évyGőĂĂ/±j¤É;ňćĹĂ|iZcyíú:8BszŁĺüđˇd@=;˘“ŽĽćÁb¦SĽüÓ‡/Ó V±X ľ1ćôŤó‡ ö‚$Ŕ˘Aěî.m‹űÖ®gę…«‚éĽőÖĄ#. ]Ű­0s°qt8ŹçŘČŔ„ß«Ž.ßţ© {ĐGş3‹b†““ěö¤`äx`‹íË×c±CE+ÖşN(Fé_-5ěú5=—˘ Ś/ ÷ :2 î ZJ:âxYaVč±?šJÍŇĐU$Ëč¬U8ô#ě…!á°h ůáĺÉXVQŹÍµŠü`GÔA®wá E©°ąJMÓdącGôË<îrÇňݍ‚§úŚ)Ž%‰äüÂĽ>BqŰ\R¤ÎęgÄÝ4 Ć®dA„Ń}…&™źă¸¬‘z$wěČ|:“5Ł ?Fń8îNĚCŠh·Ź }®DŠČÜ$|‘M»çâcěŕÄK•ě„YJBk} ̇ĽžĆŃHt‡Ź3ř"›j/1Ă=’GŰ!بAy8Ĺ×!˙żDd?;rAD»[ޱTgŕ#Ă€ČI‚éşĹSˇ"t×Ő›,iő*‹‰|ő3Ř,:~ˇÍQň¶5 Ľě#ö™Ňjç;‘ॠ'¤zÁ°3đ•ŻČ/)ě ÁeŮ®/yéäµöD–v„ŹŤ@ëVbőAt%Šbcăę™ů”D>ŃńG×H/§1€ĐJIË;‚Ń–/‹ďŃc”÷îOŁüće­çzÚ]e’V§đtĺĘŃŽłěČ‘ěţSŹw.YDórm°‹U4ě‘ěă˝Áň©Ö%Ëëi)rčęI¶/|‘Íű"t !§:žÁxxí}p;H|ĺ°:_dsR#?č!ćFqżuîŘ Qżí†0ß·B˝zâĆ6¬Ş|]¦|îŘ‘Ź;3jR×Ę(1ţđúi^ktN‘ß{ˇÍ´@Ř8˙ő4JČńD*ş—áęŔ V°ŐĄ•ňä4;‚|G€ń+Ř}”?Ö™Yî’VţsŽyăüˇ9/+'~N5Ľvö}^{W«PÍáë§ř'_Řř6 )Âxµ´óÜÖýĐźÚŞŞŤcA];ÉŻ†CČnvÎŚN`ŕ¶â™MűŔQ]OÓwÝHi¤B“xŠ/˛ů@!?\ް M䪠Ć!®Đöo]Ě$şŔB–‘ěČÁöă@jŤDęŽC€riç;'G†Đö«jŕ\˝/Ęc Ą·–#vŠč­‹GXH ô°´űdůtúţČ\väŤ ‡Y7BoŃŻw˙s¦|ł†ťÔ»"ťŔł[öC™Ă’lĎD…ŤČ\vä—'ßâí Ĺ*~.b´O¨ň™ŤU~°#péź«|cçÓ‰ÂL[@˝Św†cG~zěUţĽwÍhcx­>¤Č†˝ŘŁ˝w93ĹßÓQ(Ř80Ą%A~~Ç“o^8Ôă9«­u+ČîCs˛ ÝŽ˙˙XĄLp‰Đ$°o^8Ěǡ_Ţú(4¤ ä˙ÁŻ8Ţő4ôĆń‹›b4IZëŇ}zi˙ˉ7ůüAfćwB±#纯˛ö†çü -Ćp€OzéCŕ–?Ł_Ę' ÁŽŔş)pŹGXSp°á,I•ţÝÝĎÉĂÉěČŻO˝=čŮ‹űZ6îÔVűď˙Ęń´2Üŕ×Î`‘€„ă 8J•ţÇľî ÁŽ@ÂŮ@Cw‘ż÷·‡~É |…ź“/ěÜ~‚Q/1ŕEń„¸žFťýŃŢŻ˝Łs“ĐľČć7R$­ÁÖĐäuđźąfB“ŚÍLţôhf-|uŰcrË;vä/üB˙W 9¦X' ń]OYö¦¨-Ńźď˙¶ŁěDµÎ)ňE,O˝żPĎ4šDůB?úđeľsšPbóÁv㏼Ě6ôë ‚=e"úSďV˘ěČĎŽ˝Ö7áęR…ŃĆ}÷',äđčd†ŹěaAč3L%ž)dŔT‡”´ě¶BŇBýP犀Kóş¸ëęőDňn9Ű}…Ć•Ď`!sy,Ě'Úü?ßúGţ‰B“4ŻOň7Ý…™VH‘/ÎĚĄ^:•™â˙¤± ĐƬŃĺ?Ý—AVĺŽĺzUhŞ˙üô÷z·<Śňö>ŻŃ$îmkózşČš“í‹É;ň“cŻ2ÇVnˇMÄ_üţGśWţ©Ť{ĺB ÁŽPÝ?NaőĘ’ň?ÓĹNɢb±$í[;żŽýăn2Č0íî˝…©˘ O¶í‘®cvDe˘şyŞÂîŕkŰźp´Ú©úđr‡ËYťČérŰšŰhďL. E70nRä;Â@H<şţ~l˘ŐË}ťT']fĘĺ—vDßÔě‡0ÎĹeôŽś‹÷9+«›ććč茰#t¸7¨uGič`ŕPŚÎ¨ ;‚–Ї ‰éÓ#K°#ó ŘT2Ś(@¦Y»7d9bGŇ łÓ\]‰ŽiÎ/ĚO§f˝âĘŐQÚ9ú^‹Q}díÎG4ä'G P’ÖŐú"wYQÓôm÷1 6G`GţË;?vĽŕ.cGţéČËú´YĹŤĄ‚Qy§†»©* /é«ÍŘâ9á/ŃćÁ1˛`G¶6­Ű"<™ü`G l);-žÔţö€Ř®zŤUŔS.ż¤°#ęU4•ÄÔ Ż®m.Őçůž«;2•š¦=H6ěŁ÷k;ÂgÚôi-™źv„Ň؇cGŚYŽŘ‘yü ăŕ}ĄI1°#ĹńäÜÂśVvÄŤŇęŕŻ{ń§DUVě‡§ąż‹)T@‘ăÇŽÄäM&ůÂŽ¤ů—Ď/ĺ;’vĚbv„Ćĺ“bGRó©LµwЉkěýęłÄŽ ZníbG@DĽspoaG4@äcG8ĹČ"bGíLdŢvÄŃ> Ű0玱#5% AyŹbGtŠ‘„ł¨Ř‘‰™)-Ňź:v„RŚ8w…HTřîř¸{ěH‘ ’ě ËsĚ\°#Ž—Ś„čžĂŽ üĐÔŻâ;ÄŽ`ôH¨>sěířëť`G t¨şŘ 1“‘…`G&U ý§Ľ`GPX äç;ŇŢué=‡Ńʬâ{ ;@ţiibGtŠ‘µŽ ;rD„l?m죏2ůóżěHÇŕ->— bG𕬰q´Bs–6v„SŚ|¶ŘĆĂ vźeĽÓŔŽŕWtHaGňŹnˇ?ŘGťg´÷'ÂŽ@ěY™|ŞŘ‘6ťbÄ `Gđđ«™&ź6vÄ|†ŘGg×>$Z\ěĺrX\ěČ»—Źy»Ú;ĹŽ‘;ÄŽpŠ‘Ď;˘˙tyQ°#úO™Ě:ź;‚ßę >v•㡸f莰#ârlŘ‘}řîň§ŤýˇÜ9v„ţ´¸Ř‘×Îčń|ŕ;ÄŽ<»ĺYíbGřOź9vDýI[í;ÇŽÜżrÓýÚĄ˙̱#*Ĺű§;ĹŽ€űó:UŔ=Šůťbdq±#!‘?˝xâ ąµůWʎ#Î]aG`ćfćfŘȇD‹‹±űÁŢŻ9K;"˙ôicG-VěČŻNľĄ—ö'ĂŽ@ůwŹő"ě¶ĄtPđ™cGÚűoč˝ç=‰ńN?v$™H’ŕÝv•KŻő3ÁŽÔ”UĆ –vDG“>vŤ¤čgŽqÎ#ÂŽä“ňťwĉ°#ĺ‚™ťKń@DyGţUbG0§zYDěy‘ÍcGî"ďS M㽩H–‘¬."vÄ»ČćSÇŽ@©†Ď6ďHţ±#ą>çجăzçvŘ‘ş˛*ŐĎ;˘Ż§毟UŢ‘»Ăލëir‘ěH”w$Ę;BĺˇĎw‡9qóĽëÓ~úؾȆčsŽI&Š(kz„ąëĽ#N„ą×°#÷DŢ‘lŘ‘<çŘď“ő9É;ňµmŹc˙ř™çů¦‡¤ŽşCěČľÖťtQćż&ě“CŢ­^ďź;+ʵđI±#P¶|úlóŽ$ rčî;‚_&;ňĎÇ_çó˝O5ď_Os/bG¶5ŻŁĘîEě aîQěČîů¶'‹‹ůű#/ŤMMdFyG2Ę`G`•ľ¤o׺óŽ`űöďů¦ł4°#K$ďíO~ęyGčŇ:g `G0ŚäöߋؑéÔŚ>sţŘ‘‚‚Âuú/Ę;’+vdaná“ć)ŚÇ—v$Ę;ňYŃÝcG$¶ăα#wzgŤ˙‡AěÖźvőĹ ”KěZ……a…‰X%DącGfyfąłOb~ěö]zś}Ř‘âx?ç 2Ř(;Pr÷Ř‘âD« ŤçX5aGôMZ>ŁÁ˘Ć( ćŞârŘ ™m5ŕąDŠ`l)(Č}$4 úHÇŮôŰŠd)Ú645ʲ„_#&Ń=˝Ň*Â8A^RŘpá(QqĽ}Ä ËzŇ5ĄUŇx‡`G Hü˛2VqmiúŽÎŇirZă*d sÇŽŕçDÇ ˘só‰!˘ˇ;hd˙Ä0ËR™ľÚ¶_÷Ńť‡eőR݆`GĆÄ 4b±WÁ˘î`‘«.©”}Ě;y—UÔ#Ç ©…2z‚™ńaAÔv+Oxabpd$`IaGŁâĎpO1ÎĂ))]QÓ„±bäz·˛fţ˝9ŇËJH‘ž±>_†DaQŕĆ—l#­öŐrŢóµ÷gĚÍ•őX_XĽÜGBŠčô$n!*t’r}¨{ÎrtGjĹěÖ…LÁ‚*ěšăÁ‘ç_áŘ‘k]śA C„9ÂtHŮ–';‚ âQB“ÖÖµŔö]ń{ŚC…PůÁލ6w_e— #ŹqĆđ2€ ŢΦ&ß>3?جz±ľT›ˇ/őu°Đ±&K;§Eľ'Šą†ą9ÜĂ ą,YÚ&™K ;r¶»}ĘS&ç•5MXˇWú:ŮĘď^µ G¸„ ‚”^îëąd°6w쬀\_¬Ü żë\ĎUĎb¦ëËkZëVt Ţęë'FhҶĺmŽŁ"łą©UîĚC°#B¬/Ńë­ĐÉ'».˛¦…>—§K÷"vQ_Q¬ăI}ü¸ó<{2„Á8pČúłµ~Xźęʤµß˝z~xHzRł·4µÂ”·÷ßŕl1„ÁW†ßAŇ©ßGgŮć¶ÖŻ”‡éącG0Ĺę¨N7 çU[ŕÂh¨qišsÇŽ@ű±qGH;x˝wůŘľĽ âŠ)&…–ÖZ˙‡ŠŞă© {°–Ź\?ÍO[˙ ˇkŇNsUýfˇŇC°# w.ĺ^oh\µ˛¦ącč«ÔLIż™>çŘڤö]ˇ‚ę€:Řţ1/Ě'ÚvÇ â™QŇh&¬—kžÍĹ6a˙ş]m¬ŐĆnĎ~Ť¬:|í$o1P9˝űH‚™JMżĄBn+đ',4hceső3BŠ(4‰†‡Ć{týđŽŢ˝ü~NďkŮmđîĺc¬Ž4šd=¬ŚśĐ/m~Dî°B°#z®]ô° PGŹ·íÇ×Îľďxm…i“ę.?ŘG‡ŐyÇ„Ąa€Řó2Aďd°ÖÉ;âč+żó ‚ÎĽÜ×yŇSĄ‰äłcÄ‚–`D&ęyxí}“łSŻf„6ýôF•P䟏g±(wnĚĄ^W„` ŤHFvä@űq¶ÂpTvęěGŻź˙€  *éřĺ;“¤BÔŢÚ{rĂ8'wžcőŐPQKq5˘pěÄ’µ7Ü~,[ 9ˇßÜůřŠĆí'P€‡®žÔέjĚ7& [b;žŰ˛|mJ4ž°U%4 8bőńqč÷ü 4ä+"źÄ·ď¦¨0ĄÍˇPÔÉ=Öq–|ˇ´ćř•­Ź‚ŁŢÇ×ď– -;˘± ™™ýÎ_G(aĆwb±ČTvÄQś×~ńdŰh”އžý‚gNqB°#;ŽG˘2…$ä$*ˇHiŐßţ‹ĘŔWQ±Ă®ăk¤C°#o^8Ěčd8´{×lśů•'{×3r/ězýłcŻqŻ1×pé!„§=ÇŹ"MR[VůŤűľ0;—zńÄăŢŃ"Äf[óz;!dlęÁtĂ1VOȡǤ= ÁŽ`é±g‚6üpď×áoSŢ+ż}okbĹŽ  2U ä jşë¸tF“ţ§Ý_–}Ěvú˙ťËGil`Âţí_ES˙éĂ—Ů­‚&„n˙§#/óî{×Juµ öł/ťz›žŕç˙ń±ďŕ‡G®ů÷|¦ŤýtYúącG`ˇţáČŻůëź=ňMěň~yň-¸ ôd}ĂJ4áGĽ[_mó<šú_Ţţ1{ˇ/Ü÷”7?źą”GAá|ˇÇܱ#čšżˇąH»ŤŹ‹ µŠAw&ĽKZµÄ!ˇw †"F5;âčcÎÔBŕ$©[±…–ö#;‚Qšö÷‘7çŽHÓ¨ŽNŤĎgŇŔ÷UŔbĆ1ěRÓř ×Lk٨Öů©Ô´sSfÓęÜłÄéXRŘJ)&ź)Ŕş°şÄo׳cGđ+™Ĺ„¦Ě[J DÓPV#E"w즣o|0ĂQ÷‹#čŕo 3‹ žňeŁ_V%‰bC„B°#ýż€,á %VqôJoôĂPrÇŽ`ej LN±¬Bt›ý‹ěŁă©¬ÜČ7’˘ źO˛^jŘlź8Ę‹Ői÷_U]Z 3Á” 0t“—Ž>VĂ0şĺŐâŚvŐ źŚCźü`Gť‡Łő$Ě \žŤux‚>^čbX¤§Ś§#ł¶ną´ň!ŘGmé{8:âŤj&KĆA®¸pěÔ‘’UO»a”(K}…l‚!ô=Ĺoe&*Č­KËv¤ol°WÜó©“„˝ź±qĘvÄŃÉj‹«¨0.Ť×Ćekäű‹K ;âč[?8lI¸Cy™dCF(—vöBÂÚPCďŘ€Ţ*‚Y«oý¸ĐsŤmô6| )9×ČDGącGXbŐëŰ!Qˇ›–)PÖ”;}šQ}y ¤QţĘ€„`GŤ`ď‹ŇÉyÄLIűr/bGć°ć ż‚š°wĎ;Wn‚ĺ‚Ę='҇`µj­»<ő˝6ę< BQá­L†L‰ĹÇŻźžń/űŢřŐk¶K÷8wě,ݱγěCĹÉÔ}ŕµwíÉ1wě8~ ^ †ž;™*ěA µŃĄ'iİZ!]<2Í*a‰Ę1päúińŰ"¬}6 řĺ.ť>„y…cGÚűoleK[¦éj­[!“99ź{ě„\wÜ…“AbźvYWQčĺd×EÖ!ń‚řšşĺ2ďÔŽĺm-ŐË`ËŢľttÎóüéppT Ĺźl{PndB°#ŽNXÂ/[ă·MunpE×~_ËF8EŕřÖĹ#Ľ}¨p|zĂp„żtâf&Ő iűŔMţ”!˙!بŮ7ŚšŤĎs5b¦ř‰¶Ý˛ŹyĂŽŔ—0|3©—`e C“;vÚňśŕßLba7/[KK›);ťđ®€ťÁĹ“TW]ýŘúÝŽ^_ěćarŰV©„Ož H´5úä?;‚MčŰ"a Ô8žŽ5Â,?ŘGă úĽ ËJ&?Űłf»Ś‡cG eN‘mÍëáźpQ­¸7/î—ńBÓ# í ť—R" °dŕrČ yĎmÝgUBL­l;‡»ůđ@!ŽşzćçeôsTô…M-Ó)«M/~ vCž®GCC°# OĽÉ^14<ěK§XĎlÚ·LřÉáظ^'Ľ„%ř3´î•ţŚ&„Ę” N(vľ®D@™ôŚöÓŮWZ,žŐ/”żĺ#µbá‡ËçÇ{ĺ;âčô!ěůŁŹPѧĹ.ě±őŕÉě\JwŇśł–Ę$ ß{๢xÚ;"AŃý+6Ă9ä>˘¨É:wěČŃŽł:±™{Ś-öµÁ›|µABuőĚŰ·DÎB0˘=ă„đ›©ä=®RĂŁ_Ąuí 6 ßđ«’uް#đ4>ߍËÖJsó JâsQB°#p$ţĺä›üumÝŠ›#=j¸Ź.;‚ĹňŇé·É˘)pFY4ĂŤˇsĂŠ+K–ôŚ Ľuá«V,{±ůŇőI»éää;â¨ÝÄ%ť‚EŐ’(,„9¸1ÜËuBéIsĽÔ°#°8Ýc0€˘#Sę™Ň!-M¶>¤Męů" {ÔŚąčęvé#ŻÔ|jvnŽć1QPŘâ?«ÉvŢť÷n•*Rś ©ĆdącG¦çf3a 'VXXŻ1O úE}ĄMÍpTžbë˘Q¬ăÂę"‹ąL±  ĘÄĽ_% }’;vdÁÖ/đç§@/čî•TĎ˝AW؉(ĐuţaG‹ň‡‘“´ŕ+ćű GzŇ&ČÄ+—6/¬q ;"BţŠăFÇc\§L=b…Ţĺ“pě›zÄVÚ/t cu-xń](Ĺ}–`nąă%ńżŔńÝ`㍥ŽÁpéĂqKU*ĹH<É•Hí`4ž9ęÔ#ó˛ŮLFŇg1°#ŽÖăAqĄďŘBó‚qDę‘ŕXIGśŰaG4dʱ,‡(8·ĂŽ wŁ3Ö%‰ń¬L–ѨΩke&e/é}–©G|\ôŘé>Şd$ÓcvŽúć9c—vÄŃ™-˛ÉjµĘ0ćłěŁBSňŇ%AéҢ’ňŔ J9bG¨’ń,ó’\¸w|p~a!PDŐÚX^kvvÄń§1ŞŞ*./ó7/wěŁsŰNÚGUyŇĆR ÇŽ©G$aÍgľK ;Ăqc¨×ŻĚ•–ë4*Ž °”D)Fčó­Ńţ錪ĚŔ%}Ő±űČv+Q”üSĽ0Î>ť±pÄRHGhęĘ|¤pě†ô86Bá•–ÂY±#Žľ÷‡őA­ő+ Í‚qÔőŤČ—$L!ŘyĂŽ@Ť\ę˝>ź*ĺę´5®.ô;iyĂŽ@¨˛Í#ÄŐń/5ěô­LË! ¦a‹?¸˛Ô°#ŽNĚôőöĺmäCÂppäĎ Šd™‘’gQ°#FęI5Ąm î€`ÍŞµcŰä`Í6řŤB8vËPžJB=†Ý‹ŘGß4$s59ç4Í\Oăř/˛á‚ôYIXŘŁ×O[·Uđř!»Műţv†®Ë;âč R×J’*\ç/ś3vÄQšůŞŔČú†dsS+yŁ‘‰™ŕěkÝIÇLţ‹l|e«K*ď÷‡¬Â±#ŕxŕĘÇ´¨ĽöŻŰE©:™>çŘĐ‘k§•łá'´˝«·Sá©Ô´ŚµK‚ËÄgĐ—z;.÷]·®Ž¶†Um~}ŽŃ©GŽ8AJg®§q´-ŕÜf_¶ o^8Ěp[žÚ°×pcB°#ŽvdtJ´ËL:âä;/ôwçZw…pážŮ´ĎpärÇŽ¨„+çdăř¬?•‹ŠqtÜ"Űŕ1Ż0¶TX­Ä13×úS0éŠq’…ăŞp­Y8/Ř•zäÔ;¶ß™IGśŰaG}ßÜÝËňüö'ČłE%X6†i¸¬Oo|ľë<«˛ĘŰ’ŽĐg™zDđM' â/Ü÷ˇáĘľqţY‹&J¶Oźá`ˇůµűíáµ÷Ú5;Ň9ÔP_nUFŇçvŘ‘ŮůÔ‹Çßt±~Ë^ä˝.ˇ`G@XA=â^WY#V†ŻűŇÉ·ĺűTLÁ¤#N(vÄŃ÷CÉ7[$ ç ;B©G¬†¦ážćA%žé7ˢměä˙äŘ«™#&Áďî~®ÂżŮÉ;⸩G&‚çŞEńÄ·v~‘@Ť¨ä×^IiŤ–Ăz¤Żżżřá…^űŕɶ=Ʀ#oŘ‘™ąÔ?yIč#Öq‚q"ńĘae,…ł`GęîkŮ(/żpn‡ÁćëďÄýM’0üĐ ĆĂü`Gt%'>(@I(ü°ç ýÍÁĺË'’ţdßЉ4ĂA‚„ťšał;‚J~&̢¤•˘0ô’OŁŽŃç[Ż~˙[rś™› †«U…‰Ź*FžoĎ‘#‹cPˇ, v§TNźT/ r ÇŽ Ůŕ%˝av‚ †pěőn&}h•$Š  ÇŽ¸HW‰z;3h°ÇAŕÚVž,É`ąŇ鱙ɠäH| őcä2ĆćßYzŘ —ĚÂÂDď ñ#ŽöH‚Ł ŽAaQ°#Đ3Ă“ŁÁőÍgUIcˇ0J®ű")ŤVAŔŚß†cG´'¦‹ÉŕÁý˘`G(˝Jđ\µ´¨¤60há؆+}ÁŐ—×^ÚRĂŽ8Zf'F…ŐSŠŐ oUVŘ7>Da›+ëyic{Ć‚aˇš 4$oŘGË ż˛ŔŃě–ęF ŚŔ­‘ľ)/?ÖcSEťaâñ#ŽvÖ߉ĺU †(Ţ;Ičě^(LePñ#ó*ăâ­ 2A=Í•ć‘\ް#ŽŽëcÁ łPOP…ăä;âčŻH,áÖEkÝ Ă†.5ěŁÍ˘|ą™Í^ß°ĘPŃK;‚uq±÷šáďĄŐŚ/—™c»FzeŢ"čĄőő« á_죺°Feݶ†UĽ´áŢśëiÇf››MTŻĐ+Śß†cG-3AeŽXG†}ąG±# ż˘ęxŘčĄÍM­ÜG,śłÝí~őĄĘµÖŻçzX‰R´PÉŽĺŘą‚‘‚tąąÓE„ ¦vKł9Ş‹‚Ç3]—e^"óÖŔ - v?î<ď­ÄŚMkň˛‰Á{9Őu)ĺwČ1mŤ«e6čďp6S”FŐp<±#޶,go]™ó’M¦=ް}ÁČP„÷ňqçYą uô aĄŚÝî9)’ Ĺ â{×lçs@xĽ§n^ Ş/p„6v1áŘG'NÂKâĹ»Woáí8ë8C MşU0|ňŔęčŕŐs‡\_jcj§pě8l?ÎúŤiEMSĐ®ĺ ;âhä.Ö…±éŔo_ŢÔ‡ącG˝A8Ůu1ČS٨0;=s´ăěH@}A¤Ą>„Ş„ë˘SYx¤ŹVöµî r ÇŽ€ăöăA˙N•żÄt<ň†q”{s zŐx/t˙ş]Ő~ít[ěÔŃ[óń í]łŁUä/~† p,Ć4±>ĆýÝËÇ‚Ż1ŔľË-Ś#Š"/,Ü˝r«LřÄWŇHŻÇ×ďf Žoś?4čsŹ]sĽo­ąŽÂ±# ;Îśď–ÓÄń‰¶ ď7;âh ĘYť`Ë^TxdÝ® 2 ÇŽ@{¸ň±čŁ[#tďžŐ™ů徎#×Ng&ŕřÔĆ=Áw8v^Đ›÷Ú°ďAő•7죷]2“¦֖߬ťK˝~ţťÔw.w’ĂÇ>ĐŢ/ź~׏ďQ%ÜS, v_:ő¶qÄ„ö@P%Úă {%ŤŹjËŞźÜđ o:fćR/ťú=çaŇ—Úě1ć ;âč˝˙űW>â>¦˝>ÂĂvŐ(ŽËńĘ™wűŤ>¦•9~týýFUáŘÝb<GČqŽqôiĽŢČńúřÍť_ Ú—ĽaG°%tß3Ë•Â}ěüůGż žÉ?łyź4XX‰0gF¸p L°(ŘG'Ó’;x=·ĺZŁŹ?=öşŕţŮSaŰš×?·użńŰEÁŽPŇeŃügĚŘc!áŘGc_Ôý‰~ěd3ÎäŠýř°µBťF…áŘGĺŁú–ČŔŽŔ˘Aar\889vdkóú “7ěŁß<ŻNö|Řř ĐAŔÄRĂŽL§fáşŮ,v¤É˙‚„yxrĚŔŽ$ă‰ĆŠ:ŽQŞcáŃľY/@ĂŘ4¬ľĚÜä ;B}śťôĐ#^ëcĺIK€,wěŁ7Vęş Č^%HÉłP”‘WjĐđÄbEń$·S_‚‘ň‚Gě‰fľącG(Úî5;C lă ,8écR0ÄaG‹rĹŽXÇ49¶Wĺ–KS=Öbě#±k±EÂŽpU” ’°,Dăᡨm1]•µa·ĹލV-,̧DU1k1…2ńŠQËÂĐWęx©„Ô &ôU;–Ş@žŽ.T9Něaűp죇Të•–śź(LĄbNUĺr¤Ć[ŐDj.5Żç(ć¸Uá8Î"aGăLj–_O4,P‘U*±#D3*=Ô<5Lu° ĐÚ°ŰbGOÝÓŕc —Ťë„n‹q"Łp-jđéśâx28ŞŕQő8*K 0‰~Ž‘AB¨ŞYUoäS Ęr¨ô9@cŐĄ†ˇ>ÂJé h¸0AÖ†Ý;âx jM˘µŘ˘`G¸*NS†Şŕ â>25† ‚T(ZA<Űŕ‡cGƦ'¦˝>˘@‰ęŁĄa‹‚!žăQE+˛ÇąěŁß›ž¤őH7UU–”eu bGíía(tƦ…xAż¶¬:čĂA$Ć Z˘ –ż‘ŤĂŃZb`bDk€9ÂÖ”TZůÄŽ8úÄkŁŞúX‡ä, B­I°‚č’đÂҰ*ĂŰbG˝fQŚ8B$P¬±˘&Čń¶ŘÇŵô“¬¨›×ŠŚ»Â±#D=c ňCŞâ «Hç;âhAíšś™š×Ăan®¬·*“|bG˝ďÂ˙IŻ˘UĺE%V0ÄÄŽ8Z/Aâ_¨h¨ń’˘$¤"ču,A죀k]p™  ŕi”Ş…Öič.ŚĽň¬ćń׊dŮňކ` ;âh‘€RĄTĚŕX™,k©n rěĽ۵F†.ß Öv[ěŁcßřŕ(s,._c[Ź÷.vÄŃ0 ¨_*Vš(qáŚ#LpŰűošVçĎ+FUAű%ve@-4”‡ž„“˝´h7GzŐ•Ć“ŠŁ¶łĺV-·(Ř"Č38Ňę€e©+ݶN÷˘`G°®‡'Çč*:Ŕb úĐ˝ű:ƵqÇ(U—V¶Öµu„°s¨{X_ÚŤżÂdŻ­[ŐŰbG\Ž˝×ˇđ!™HV$K[ëW`ĺKFŘGo^ÎkpŐ”š ĺfŁŞ`1čcü ď Ţ ÖăöĺmA ËkEP-TRWZ Ć;w€q´c©ďú8Îc1Ö,Ś{#ćşg´D«/”Ę«=¸Ź°zXÚ°VđĐ m s¬Ű´pě”R˙ř0i9€Šłją|bGíěťęş8˘Ť‚——UoZÖjőľ;â(ý'ŘK{ű[Źő bVő•4;7ř9^é˝vâz ]^oQm{ă˙‘5D=R(uÖÔ®02ŽÍ'vÄŇ&jbz‹áq•ßß´Í˙ö…u'쥏—±žŻ t‚dqYíćĹkVú€ďÖ,°#–¶T[{;¨tŮĘŞ%÷U»#vÄr.P;Ś1F Zö^ŕaČĽaGŕ.1Ę‚bĐŹ'Ŕ¬ľvf?ąrXTĐ/­6ÓKXZ˘µn}`cnďĂÍwűÇ8WŘKŁß čňô>l!?G¨30U[ÝáµaŃŞ@ŹoN°#–ž®˝­GŰűnĐ©)8b7ßÝ;bi›đTçĄk*ŰD¬¦¤biy˝q=qüčĘ)¸˘Xö1˝7-^ă7V­Y`G,5«í—zÚşUfč ô߯ř Kʶź…ő˘Ô±>/…őâÇ Xó‹±čPčfŰđÄśčü¤ňŃÖÔŻđ»{ ;bé¸*dřŘ” 3Ń˝áţő ^°WáUĹt.LeQ©˙VťiOŤCŕÄč Pä_7¦bް#–ö›ś™˛ÜY‘xI[Ňś`G,}ŤI µř& Äă‰SÓNřXE—cqżmlë`®ŽD+†q# ěüś`GÜ-5#ňwL¦WČŽ(°#sCż3v$˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘7aG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘>żaG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘>żaG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘>żaG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘>żaG"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘"Š(˘>żôI°#¶űO ˙—­Žh6 ®fëznĄ¬­qSřźx–¦¨šíö*+G]˙‹…U›±g¨rŚ(¨cşÝž_<ĎÖ÷?‹gë˙Ě̌۱X<Ü1|ŤÖf¨WV,ĎĘqFwL7••ăÔôNÄŃÎôĚ4:vŞ)4ÔęčAÎ`ŞR@Çđý´ęŘ &]ĘÎmMO۶ŞCk‰ŔÎë:jq+–L$9RçQ-¦–Ťj*p*Ŕqjýźˇ&8b¦gTÇđP'…ZA“ŽUÍQ=ťd–1˘•)đś™AŚ1™HŽqlr‚?§“É,cś™šä?óSyMMÍLSÇhJSAń€&§§¦ôăNę:Ů8Ž ŽY8ŽOMĐ&%ăÉl'¦'§ôjĹ„¦“©@ŽÔyü‹ÉDÇ҉T଎ăŚĂě9‚F&Fî®d^ŕ&Â< cô9Kä§ŇŮÕގWy©tŕĘ ŹŹň碼‚Ŕ:`ÇĎ(۬ŽNŽcŇgĚfĚ_ĆTÇÔîFT ÜD#UKęąĘOŚfbj‚VF‡Ő8«ŕ821Ć–ävÓĹ+­¦ó«ÝćĎEéüŔÎO)Ž™Y-Í/ÎÎqbrJŤ;¨ ĚńÖčP†c^AŕsGńí˛‚’Ŕ¦P[›>ç%ó˛­śŃAţ\śWČK˙Bjá!bşwÇĐř!ő (P`'âaňń!/‰¦‚Ç8<1 Žô¬±9Ş:SjąbuĄ !ÖÖęřô$¶dž®(ĺPgtŇY9ŞŮVfU=Ę鉼D(/h­b•˘c¨f©™OcŕZ;^«¨¸rÜéRËťÇĘĆ“Źj!¨€jÓ… cŞę`= Z GÔ›G›Ř‰ĹůEűß*Žă`ŮUś_â­1ěŽ1ťH®Uhźˇńa,0(đÂĚN—â86ţ\QX’J¬,ż‘Ěî¨-© lŞä6‹čâta \ĹoŹ ŤAfbŚ©ĽŇü˘tGôüöčţĹJ.PŐŠǦF'°\ÇUť‚âl"úĆíţ\YTČË˙ŃgT@µŔ¦nŤŇŕ*SĶáŔŘ :†ĎéĽňü’Ŕýv®\M'ÓUY8ößšr¬,Â’ µŞ8ŽŽLŽa– SůXÁnĐ#6QUQążG?ƨ÷VNyAi RŔ6ěîWź´˝¸Ľ6°óŕČş«‹+‚9ŽÜĆBť˛§ SXY8Nô ő» ­%ĺuŃdřbÁCŕT–VëčâĎ5Ĺ»űůĎ%Á»‡úŘ,ĒȦřÚűođgě ly?˘B¶Ť†:cî’(Ë/ÓŔjmýťÎ'ŰŞ-­ _Đł·\Ĺ{©®¤*°©®Á^cyAq6U{µĎĺhŮË*ë`Ů÷ ŤŹç@đ.BĹńv/Dśíp,)â1ŇŁš5‹ÖP'PŐ˘BĎŞ ţ \„––h>×—V6… ťB¬¨ZŘ!ö#öZ‰ćXÄÖK÷P?z˝\śW„…¨†ŔŐLJ1F´VSRh'€#ţŁĎh*۲oíéŕĎ‹Ęj&öšr8ćŐWÚ X„¨Y’_XYXČC»9Ô sH5URČőÚŔMú ą¸,X\»usÔŐˇĎ`Xíbw^\^ȱořVßČ-‡c*oqa‚eŹÎ“0ÁÖ( ҡĐŃhĐŇfv}iU RĐuÜ1ćg_Kl A#îLÂŤÁ^ě\2–P-P`b—ő2ÇTţŇŠú@ŽKP$UQ'°)t »Ú–8bwZ&·Ć†nÜęÁż$”P-ăą®Ëüą±bQ6Žť·»iŚ6‹˛p„FčqÇX]T¸µa/uŢRMMÎLˇó e5Ů8^Gµ±A˝$ŘUťŃÁ±ˇňüb° ÜÚŕxýÖMĹqzť×l!ô»ßB¨6”ŐrĽÚw}Řu¬jŠ+9‚Ît^âĎËŞŠ‚8BUÝt5ĚłĺYDôpgŽŮÔĐé΋üyâUu % Žé‚lórď5ćv1 —{®ńź˛sěµ´ťP”W¸2#ĚT]­LË K°Ĺľm¸Ó7•LV”Â4!%XkcŚ+«—věĵ üą©zi y µŘ1pŁoä6ÁÇ~ĚĆú‘>C.Ő•hmŚ[MMNMbth*Pż@9˘~*™ŞÔŐ9ަ”ĚĽŤ:`¸µÁ±­aŻNB>7fçx±»]´QaUMŁż¨­ŻM©njQ6üXÇ9>Ôn®i äF®öwRSU…eč| yÜŇÝ6ä«őe5‹˛ŻŁígůóÖĄëëŔH€ĚˇĎĐŹÍ5Ë«akC/@JCÎĂ^ t`E´ÜĽÂn[ş>ă­îë·»IŚC ­® ŕçńą ŤŽË«ő Ôú•^tl^IuQŮňĘĹÓ… ضÔůjŐZĐF›š¤:đŞ‹Ë! 9Ž _î»Ö;Ž©ę˘ 4•ÄBőÚ@·Ă±¸<›09tő^[·"ĐóG©†î^¶1°©Ë˝0!Ą«Š+`–dss>×eáx[qlĄĎ¨°®ne`S°Đ”R¨)*‡$Éf¬Ľr2ñ~e eÍ‚Öđ/d8ÚYR^čtś˝Ń ÍNźaZ&č<,4­A|rDťŽ~DZ*-(Z_ßŘůK=íp¬¨cM5K5ş):X 0z—–×:V`ípĚ/ް(€#úÜŢߥu_4Ë*Ĺ1@żGh+ĺy«jÓ…F`a˘54˘[ _ŕa‚šřP«:_¨Ń`)ťľžŃˇ»Vnń×±´ěmëżAťÇÍŮ8ŢĽÚ5Ô7>9ˇë, ô a“´t_ESZŞŐ. Łjj°ţ#oce=ţ ěŘţËÇůĐ3ř€n»-¦—=öc`S8öá’Pi4č—QĄŃ`üCJ{Ňě–fYś.”K–kČÝR†ś2ö§ 6!äóŕc:fłí!L´7¤\ˇ’Ľ˘löRŹr÷Ô)Ü=Ż`wojn‚¶÷bdE> t¬äÖČäxa*Öl6wĎ9;ҡ(ľ@1ŽYĹ3‚›™ĐljَÚŕţC/`™ĺ'ÓyęÔ1řČtH OÍLa˘đ_ §H48¦“YOŃ1XĚ0ˇS:ŞčÇÍŘ6zާcŰ6ěöüT:061=37ŤCĆY#>S“*°53Ď7™HB–vWéCLGs;OˇÉi{šÂŻŮÂŽS:|IÎl1S t:QÚx,ËV‡Ĺ÷-Űb@ATŔr€!u,ÄŽ!Ő>·ô;cGlńżąbGśJNÍřłŚ!94¨ÂÎtŤZS@OÍiăŕŽŃÚ<ă4eôMCfdI, ŇaĆe† ŔQÔ o;Ó6ćÎC„!ţfÄmÍ4™Húź]ZY¤z5éĺɇl• ţźńÎj"nŠBô˛RV"Qh̆Bč©ŕš:H–Žy9Ž \UM©Ř°‡#¦ ĘŔK‹Áŕç({¦Z,^Γ+Ľ ÁIž2ťˇh'§§ŔqĆ˱ ť'9ęΫˇü!&ZŮżrfŇq§ÁňźzăČäÁÓepÄ‚&ÎĚŞ&(Zż11Ąă—üg6KBťáşAô‡6Í pDŰ»!‹ŇůĆ1: Ž.aŠ‚Âí°ĚśaÚŞçŮ  ҵÔtž Áś’ćŔYí˝ŤÉ—KBÇV ýĎQFLł™z0ňřĚNĺĎj˙°ŠO ‡°ža¤˛·¬ Äĺ 訤,I%Ąr?b2Ń”±rŔŃď¬Â2ăcśöŔΫ“ńqŰ+ öTůd«7k¤mHDÚ|.($ě]gŚŽ°±+‹Ęü‚n6‘¶1iCSŮ<ś®Ű˝ăS™ŘŢlâ^u%UţĐzŽ˘ }ó›: Em÷ň­Čyřfrkcŕ/‹‡BPÔý?D\mQĄ”«h^«°ć«ŠËĺ¬b%ßě×3š˝ş¨ÜżrŕÂqŞ ™×ŕ;.ÁňĂ5ä(3¦qĚ1<>Ú5Ř«LU1FLl±ĎpWa•‘j BÉŁĹă»!"QEa‰qç˙¦wVˇ8—ŐJ±oQGŠqK ŐĹĺµrşŔ«óV÷—Ł?8vhŚ\‚F°ňý‚[ĄľőV±`:nđÖ¦I«/©2ÎLű†oÝě‘%†KËëĺr…tíÖÍA÷˛´ßŽ©đ»27;0ä Ní{Żq·˛ťÚ_îéšČüqh,‰«ý× ·dQiŤ!ZŐÉř`Ż!Ć—VÔxÇxĄďš„˘zeaiCĐŹ_;Ďź›Ş—:íXŇ7Üăx}˘˝Ô¨ ŹA; ]S\aÄ!"®öwc\V±Č/v°ŔŔÔU…§˝  7Ż2¨eQiő"ź$‡śo¸aplŞZęßÚęŕO´Á±nąQł*A‡–Ö ľh®:{Ąm=€»—mě<Çő[Žî<9Ż–î«ă^ńI^ď ‡¨C¨­.Cëžĺw`˝\ęé`ŮE„ĄŐT˝Äoá¸r‚?ŻWgŻÇ^Cg:[ůĎ{Wl "vĐ%>{ĹŢĎŁýđňq^Ń5•q„<áý.eŰh§®_Ľĺr\ZQ—Mńík=J`zÜŐĐx:ÖÖ×ŮćŞÚ˛‚˘»V6uâú–™`·¬2ă—>v·­}˙Şíţ —zÚĄ-ai+zCý*? óřµ ZŰŞć -ýaNěťKÝíS‚:ŢаJZ†řöbw›»ŻťžˇÂƆfż±z¬ăăG·,YV<ÚqŽ›zxőNŁ8¶ÜĽ*ń%ÄqÓâŐ’#vô‰ë-ÚÝËąćšeĆâ„í/K Ń”˙䮵§҉ą˛jI¶řĺ›ç8źlk{ăzżM‹őp^qĚô ·,^#… ÜŤc×Î RbMír‰2鹍)•®f`mý ż0Éqčęiú ž-sčę)|@Śg :ľzfŢąlc`Đ«‚!&•…e;}ÂΑöł†Ĺ"\Wď ů@OaˇzĆHn^ĽÚŻű°*ZcQٽ˅É+Ç{‡ť1b=ř•BG×é—Ŕ‘ź8âůć…›WxńT•ß·bs Çý—Ź+OA7·kĺfl‹BI:09v,ŰX-jâŰSťĄŃNL1˙~oî×'ŢáĎ»Wn…CaT€”8%b*–6™v.»Ë/ÁÎu]ć ”‹_ż@jĽr‚5M„ˇˇß/v·źĽ~A–€#ž‘ÔÚă‡WNôÇҬK×Ë1ÂŇ;pů¸1]Řł†ÉwćFëŮ­˛Ľv4®÷‹ť÷/ľé2]_·r}Px ôâŃ7řóÍ;rPUgn8Tx¨ůîŔ¦Ţm9Ä I° Č~úńküůëŰž ¬Uqş“9V>˛:ăŰ>ęv]ą ‹V*>Ří¨Ć~sű‚9^o9Ąu¨­­ĐGWßcT€ŕ‚ö—`hKŰ´X˛őHűă9>°j»kźĽŢ‚˙č38>¶ćŢŔŽýóˇĺĎŹ­˝×ßVňá¶3˘ŔÇ'ÖîňKé×.ś ĺj[XZřϨً‡(߬Ŕ˙ďhÜ`/¬ŔĂm§-Q ęřáćť•‚ăÄôäľÖcjkgŢT łÝM[Ąç uüÎ…CŚ'ÂîöҨůÚŮýÔT]iőÖí6*ŔŇĆľáŐˇhŔýú»żćsá§ÖďńZ ŻŹ)•ť!üű›¶ůőÂoOď˝qŰ1Ź·.Y› ň·ţ’?˙Ń}_ ¬óqűŮŁÄ]zfĂFŻźű°ĎőD­ň™°Ř˙őôűüçÜőB G¬U0ĄgˇôěF“#„ü{-‡éPuÇöĄëaČjĐű[ŹËç§üÄş]ň hßĺcş®Č‚)Ą|@ŕ…%!ʎÇĆőX‡˛+yë1Y‚Fľt×ĂRżŔAxçÂGŽęŇŠŞĹ0ŔüáÉ˙ţÁOřós›öŰ–ơJ5ô?ß˙ ŁÂřÔÄŰç2GŰĺřčš{ü‡Q˙ďű˙ÂźżĽé‘@ ěŢ_žx‹>Ă˙ĘćGý{úĂ<†F»Ő6?Ç˙úŢŹřóó›ő_^9ůŃU…/ásÇęâŠÇ×Ţë× ??ö3…WuŹĎ2:~ă܇ŇGĂś?ľö>Ř`FÍ—Ot+té«[7*ŔQzůä{Ý^Š˝…ep|íě>ă“ëvű9«Sú çëkŰž0*tőÁ 48Â2Ě!()L:b˛ŽéçîzHäř‹đ´ŔhZúŤćó[•ŕŕřݧŢońrl®i|făţEř_Ţţ‡ű‚ů×¶>:ÂŇúŐ‰·-]ÂľxnÓ#FHBH9:Ą×˙[]Óu(… é—IČ%],SÉ$č_0śg‹ŐW>ě39 ÓßżxŢĄËQýĽZŇG¸9SÓÓ\)ж‡ÖnŁŁc7ĚPš_´ińyZGÂĐř¨P˙»¸˘n•·ó•-7ۦíi®“H$0ůJţ’†—Ĺś*jĆ ÓX~IHgGÔŻ@`%lˇë·»ůý^zżş±r‘<śž™éRPőA1DÂ7ŽLŐI»Vn¸%CÂĐłCăĂÝC.;őO<Ż-®3ö ś ŃÉqŰ€ožz˝Ş\:ńáŇÁ—;ŻjIűĎ0ˇÎ0R ú#>¶mŽOLMÉđy:‘.Î+đŹŘóĹWo™ŽMŞ—*y,Ą-LĺËđ±m)Ô‹<µÓ ,5/ť¨015Á[–í)ß»Çô"·ŰŚEý‘č Xł"1„®üfľa÷ú+P6+ó¬c˙ŰűFřŇ B™Ř.2A–fËÔ`‰z|ÄOźyě ±ä!‘\ôÓ:±‡żq™ŔĂև™¦ÄPe: ™DŘF÷±#č’Ú9AO@ÂG4pdĆ?@K›üYă3O1f¬XäđG * J ©2źŘ‘ľá)ZöŢŢÓŰíFĺyĂŽ`ńy·A•ěŽh˛±/jÝ9DÖÍÁ^żj°u Đ.@콵ŔťćÝř‚őBĂŽpÄňm Ť¨5u8vKâÚ-Ď{^?8b1v„86VÔ3Gř-„ŢQ¦ĎXZđͤ‘ŔÔPVk“pě¤D[—+˘=MŃ»ą.Ç1^3ĆŚaş ÉŽÇÖžkĘ]ľ{{lHÇTíŇňĚŰ´ůˇ±ËG)oŻKÝ3v€Ş•đČçN÷¨Ń 8´† ÇŽ@HĚşFĽŰęŽpíćÚeĚńJoćEUIEę% 3;oŘÉóŢÓF&ůާ±Ěu›dmÝJ¶LÎݸlśSSuzuŇhN°#g:/-‡cYŁJ‡Ę0Ž]ü®űś`G äŻô]ř™mˇAC)„cG`ť¸Ţh ůá#s‚X>Őy)ăâ˛ă<ôŽŘýţܰĺŁŇüÂuľŕ"ěŃ|bG°ýť­íĄüdÚĽÇŽô śöF—™6/YĂĆṮ˼©=xdú^_(}N°#GŰĎx¦DŘŕ;]HĽ’Ź®žš’^­K+*ŻpŐ¶ęot™i÷Ę-†}2'Ř‘K=nbOŻŕ`şŘN8půŤ’`çÜížVĂäP‹Á± —°Ş a˛±#ď¶ 2ČŐń÷&wŹ@Ľr"đ¤ćžĺ›ŚW'ç;‚Ĺ|ÄŤő|ď[±É€}Ě vv¸yeą—ÍŞ}­ÇŚ!ĚąÇךˇôpěÄ‘|ł_Ňăkď3\ČpěĆם(u¦ŰD>Ĺ!ßA—ôäşÝĚńýKŔ"„4ms9ŽĘĺ' ŰŤ­>?p„&ÜSë÷¦c„!šěL¸—NĽ;é;bBőŤ Í ”‚$< ClÎ vĄ…@]˘˙ůň¦G Ó1;sń—Çß6FG˙#á#°Še*KěŽç7?Ę_;»ßk;˙SWZő¤ űÇź{3pÔ~řȱ#XÉCă>ÜŢGÖH pě8B”N¤ľ¶ő ‰2oŘ‘‰©Éźyu<Č›€÷ ×pšě8ţřđ+ÚÉś$IřTĆ»-‡ŰaËc¬^:ő^'¬zźćOńí»źaŽ˙|ř_ŤwZőMřNËGV}gÇ3쿼tâťë™Ś Á1ynÓĂFáś`G~uüíë┆Y7(؇˙žěČß|i0Či(Ż}ŢW9;ÂŔËkaÁďŢçŚĂ´pěHÇ@W¶­Ť%aśň…cGŕîaďŚű–„Ą]°'ÖíbŽ?;úz G?@!;Žł˙‘ †zílFkŰâÓ×·=ÁÝŻOĽí&Lň<µďď~9ţŐľźrôĂGîů—#Żx\"8}ßÜţ}†_öWű~fů BK» żôÎŕ>BhůÎŹ˙xĎ×Ů7üŃáßfáX˙íO…s‚GÂ8JěHL‰Íš§7ěˇ:0ű_>ůžü–oDصb‹áěÜ;ňĘ™˝”żPbG,íŘnse>¬Y7«Š§ţĹaźzr‰!1÷á1íiÚšŚ+CŽÜ˝qĺMÄ$vmŐ—TŻqaŕíj+¬˙“9].ő´÷hě…ÄŽŕźt*µŮ缇cGúGn«g-b6<+ÄI`{×ëîe:§ ňČ´µçš ;fşäôŻ˘¨”±/o:[m¦ŽWcńp4 öI ‰±t¤€ÍÚé™i÷0ApÔ)٧é±#îąĆE1ťgŃ …cGpDĺzMq+V$(ĂŁfŇ]3ŹłkŹY•XÎW$S× ŕ7ăpőF˘§ôm™ŠNÇ‚ŕ#áŘ™ńÁ€ńý@8‚„Ź0pÄß”˘aGîHźyě€S™ˇK[Ńt´‡Ą!ÔC±LMě%–µ\ë1/WşŤE6ŽQy„Ľ -DË íHź]Č™s ž@´é&Ł®—ö]A‚Á$HT¬1Ƥ{é‰Ę&˘¦"łeµüdÍ*D?Á·W.^ŕ8ęy1Î3F•VD#Q —=“‹‰WÍUśŚ8ŽLŚĎ8€J˙tĹ)š‡"Ż˝ŕj¶Óů4Ťó‰âčŰvf2Ň'VW@ŕÄáń*·P‘>2.ÚMY`aäđĎ;2Ą˛‰dcs´ą”‘ŞNRz, 9«Ć~Ä# Ó1¸7ŕčBOb^ŽI#ގÄĹ(9włŐ)·-5·ŔŮą§—Ǩ«ńîX]»Ě€CĺŽŃßfP;ÝG˛ľľ‰6šĘzíŠhŁóhÓH6;'Ř‘“ť-âb5ÁŃ@‡„cG®ßşyýV Ĺú…>ojh–úeN°#­:#tŽń-‹×HŽáŘ|+ŁqĐeÂ|˛×ůĐ!v„hް#P|śmůt(4Db8väŕ•|Şb4I¸yÉKĂ=Źud6~~2%óHa)q¦Ü±##·ő·®Ă’Ę“!ĄÁÇB‰IlŮ˙d,±Kť9Ş’}—ŽrąŃÔ˘˛j#xîŘčń2m# Hş–"BŞ ŮyÚ@ď¬j;íXęîKµ‹ą„ł±6v¤E|K–8’‡šwëtđĘÉľázÖ”p…m!?:dN°#oź˙ű ŻéUUTf Cć;ňćą™ …Éaë6wëX|ůâ8&Gľ]°uÉZC$†`GĐţ»-‡ŘŃĄ$“`ˇťmŢ€n8väăöłm«^őÂí?>?ąnŤčµłűx\ÇĆĘEŰő%hçpűŮ”4ďoÚF‡Úň¬aÉ.ĺjéü§ÖWÎěÍĆq]ý ckGآ9ÁŽśÄ·ts×5Jm Üąźň™c‰˛±j¤?‹ó ^Řâ !‡cG x÷^:Ę–öÖď6´vvfł BMAĹC4ɦć ;˘ľm?Ëł ă_ě|cűd^±9ÁŽiÓß*R5ŠGLË [+ŃŻÉýčđoeąś.´ůĹŤZÚxůÔ{üöş*Ď!R(úÎ…CÄU;đŹČO±őçďěx†LôŹľÎPFSkj—“}âĄďZî~0ŞaI—×äŽNyűüAŮyyëG‡äŽMř–—#»u¶ń´‚+ôă#żĺźcËKŹF‡x¬ťpěČ‹â[JlŔSQ]\ń/ž ;‚oĄŰUš_$±ţtß—É űçCża}çőă4:d«ŽÁ·ř/c^2ýű;ź%Žł˙ç˛|LĽá¶¤˘îZµµ÷ßú?Ľ-ň|`’y ő±@ľ˘5>Ăçě~Ažd†cGđíży5 G˛nŁF:ľrúÖw~ޞçkTň{ć”ŰfShçé ÷[ÚFýĹń·;úÖŽ§˝†\îŘ«Ĺ\LdgAÁÓyţęŮ}tG[L_ďk‘Ą­+§ żěĹr…cG®ö]?Üv†A)eEO3fâ‹Üäý­Ç{G¨Ę‹YÓúrzkš '8°Í8 €Ž/¨űě…]˙JL…±Ć¦&˛sŮ]”tËF‡˘T}2Ăuř2&<8.ŠEąŕČ <ăĚ-;⼥ż¦ł#†N`Vé53Ř!Wű:3©8’)˛…i}Y5ťctőőŹ 2ś%ᇪ?âń8Ľ{:膭łŞP*ޏ~ĹÝáX”Χ4Ňđëoő2"„LŽvÁcĄ#Jx—®—A­ĹÜŰLTäMÉ %áŘHAg;¨*ńLüE5áż:<;˘ó—ŚPObÎą˝ó•FŰ$)¬ îC;‹˘“ úČOćŃéşZÁ‹«Č râ”·žă¢±LEo$zZ4ŕAjÝ•‘;bg˛9Í8sC 6Ďź8´-ă­(#CI(vÄjáóFźměH:˘ţÂňŐ%"Ż»ľąFÝóÄ}OŤͤRŹx—©ťŃ6ČDL)őĽ­&¦…¸qŤ‘z$;‚LÎLńĐÍ2r#ˇ2şIGT=ŇyL„L™t„¶ń„¸ż=O{·ev}ŕÇu§ ·„FM©Gܡú‡níššńC#éHA*ťÔ·ÉdX«®ęŰż8©§o2Ëŕ? 021ĆcÄ<€ăŘDB©G žµAćT§ŠŁt~J Rů”†Ä…Ë@Rx’Ž`Ô (A# hN:Bs-Ë@h °Ŕů©aş0˘Qq›Ś?őHîŘ™t]E7ĐvŇ0Ď0p1–ŰŁCŇ·DOť¤É¸ą&wě’ô%V5Ý_ăN—şąF&Ń€’ô|ČËZ.ÚyĂŽô ÷óU;E©0‚‚çyĆ\“ůÁŽ`őĚ޵%UăSărž)őşĘî U•ąiH´<ŹĹęKŞŤ¤#°& Ňů}Ă“îîŔĺś,4ěL:‚µWUTŢ7|{xÂY9ŘGFLtAaG8éĄĹ8&K±GLŻM[ˇŘ#éČb}®Ńy»‡ĹĄéľĹŢVŞáirĽ0nĹ+Uę™t룓÷×@¶Ô•VQŇËGô\®ßĘSŕ_ÉüáŘ™+ k§—RŹ@>Ë„Ë*°e‰‘z$;b$Áä`Śíý]Ě‘n!u“Ž8Ł\UÓÍËyĐňĘ,!•tÂJ—bż,­¨GŢŹ”zĽZnRŚGm¶EĄ5¨ŮÖßÉJRŹČ¤#(‘c\^µX^J‚1’ŽŕĄ©+}×yÔtsŤN:ŇË긹fv®×#˘Ô#­=íŁnTkľ·ĽżĆźzd~°#ĐĹ2!üj(ßÖŢ6Ň(őVŻ~/A<¨¦ęĄý#·ĐŔ©GdŇpÁ㸤Fí(wxłĆsÇŽśĽ~»Š)Ĺ:Ä#cŽ…epŹ!"ZERĺ őMđ“ωT+†÷ž;vÄH:˛eńH*§D·»®~ĄÔą!ŘGĹ šX %§o\bab¤É;‚-|\ĽöÚ¬r®¦Ďv]ć,úćšL$ ;rňz ›ŐęBî%7WŽŮSFę‘;B4oŘ™t*xóâŐ˛ÚÓx'/;‚]skĎťÍÝM[!ZeNŁíŤë±ˇ0K¬Ł! ·,YŁÓ8  ę‘ܱ#X„$äm˝754K,Š]+6CîÇŮx.0‡>n?ăčqťA KHŢVÉÁ»űd#őHîŘ÷¶ęjúľĺ›nőKí°§işŠGĚŽV6Úá¶3dCÚÚą»q„ÇĽżl{Dz ©xňP&ŐŠ™zdˇaGŢ8w€%pÁÚ;xő$ëPc›ŻÖIGN2ŔôáŐwONOCŞ0žÓ+5`îŘ‘Žţ.©ČžX· K–©GrÇŽIGľ°~ŹĘă-ĐQ6ď€űčę)ŢVŘsě6ŕý©GB°#ň¶3ŹŻ˝ŰG¦!1RŹ„`Gڤ#Đ…é¬^6ä(őĽ­-?˛ú¨Č#&B©G^;»oŘŐ/«Ş—B±ľé‹DŘ„¬Úy%ă€éDňý‹G&Ý;wčÔ#2é$á«¶CEŠËJě/Ýő°t#ěQîŘ#éČ=Ë7-©¨Ĺ#ÓůVŐŠ^S·|ŰŇőFŇ‘Żn}[O–©GrÇŽ` Ń ŔÖËţ+›Źóáĺ ë™ HŽ!Ř#éČCÍ;Šň ±&B©Gäm5EyĎn|vź@€Qꑟ“/ľYW·ró’ŐŻťŮÇî!ĄLţÍÉ÷ضyrÝ.x¬ŻťŮĎ&:äůzqWN8väĹcopbHü ŠňśĹľ?őHv›] ůç6=,Kü©Gć ;ňŹ_ć##X•«k–ýćôű|Ť‘z$wěH:˛!–W.~ůÔ»¬h e ڤ#xĎsWú®ÉJ=‚g§] ešÁĎÂ0J=]ůŁĂżĺbIŔřéä»|I:Ą9q˝EU™”<{Ą÷šLCňŐ­O@´RŇK×Ă}dőNȶ÷ĐĄŻ{ącGţńŁß¸ŃDµż°€uüm6&ý©GrǎȤ#›ŻŮą|ă/ŹżEŔz[ŁÇžŃŃ}¦ěČ›çśírô ¬Đom ö kę‘ě‘t„2O >ă9 ŽĺÖÇŽŕąđ\µcý˘•ĐY|fH©G ž ¬Xŕą\ěi—zÜŔ(„`Gڤ#XáPdĐYŽ‹š |ڤ#úŔ7aĽJ%şżżóYHu™tfĂs›yőĚ^Vm”zĽţë{?榾Ľéa”˙äă׸Fę‘pěL:+Kî•Ó{O99\Úâ?Ţó5N:Bm`QÁűń‘W#Ý\ăÜVC]Í+ţŢ}ĎÁ…¸sgQę‘˙ţÁOٓůö4mĹ.ć#ÖĆĘEßr“ťĺŽ!°Ĺć`Źm[ş˛®O…ůŐ/ŕf>şćĆ—N˝Ë€‰gďzŢ€F›!C –­ôw±#/ť|g’®ˇŃÇ#Ř˝—>†7MíCVc `§ŘzśŁđ¬RYĺ\9 Űž ĎË['ąÉtîŇu÷ňťT<ń ¶Ż`NąŹćÚF°8Öq^Et[0 Ó`Ă,d| ö žěyX¶.šRŹŔíe „>ÓXŮÚŰŃ«¤„*źh !C°#äZ]úëőőMxôJ¸Pxvp0±ŐRT’W´¤˘®óv7úć j’I8›3ö m ÂŽ,*­I%°Űůş.Đżř†sŕńĄuęťw±P[PĘúâ› j¬0• †0ÂůxbQiőôĚ4|Îźĺ˝ Çoóă'™áŘ|ĺ:ĹňRéâtüYJCBŃd#őHvÄI:˘Ç“PW%dÂŽÄ»HÇňdŇő~2Ą®npK~2­“ŽŚ3‚Fâţšś Ôś”QŕX,­Â»ÓîzS$"ŃÎ<'â*äŤícg ‚[ˇŘ~F”Xîť!Îy©žtJ4âąM^—Ř^LNBP väŽôŮĆŽ8€#‡‹Ó‚D*ĹuN‘iqý e12‘`OÎx@'6倚Ń×Ó¸Ŕ°ÓD.'Ëđ— ÁŽL+ĐÉ4Oą‚ňÍădBíXľ”‡±] ‘R “n§t–´3!:–†`GĆŐM4¶ĺľřNűY‚!4(8ćöÁÖ%i´€ÁĘ” ŇůřSÂ#čRf"Q×n%Rh\s´©ó©D ˘Yľ"“źÔ?śĘôˇ0Ą˛Ś@Nqűřł0ťŹ’ ńR8ťţŚNŽq<ě0^(DgA—46š˘t>ş4"Ţj*N‚…ĘD2•_ŔĆLfĆčfAűĽŔňôí6;LYFŚL$·!Ŕ9cGÄ=*’§pŻŢL$0ţĐó‘‰Ě[ tj€yŕľĆä9bG0]üdŐí3NV^ŔPT% µ=ÄłŠeCęYbPGŢÄ4?ŘL`ż>\ ™‚ůAežŐ˘zŽŇć;‚ 組˛SŔ/ĺ¨ěj]˝3P2zÜL$NauQ–˝śçşŇj'Ň™HlwNäv^(&ěđ¸ůˇü ąŃv¤ëv{ŠÜ,#2j E®í켉†łŚČL$XxŽ×nÝdźňź·öş/“ŮĘΆ撳JYFd&ĚçňŞp$c—…ýŕódbí%2oJv?‘+MaŐéL$Î!ůňĘlg#Ť]eŽŘˇ2Ł{vdTe ÉŚ‘˛ŚČL$hÝ€#áJr»ŔÍ2rµď:?µŞ˘rŚńĽvS–•‰D¬4Lä•;Fµ'›k—až1">9ÂĆJĂpXĽp–™‰¤¶¤JŢ‚ą5:(ó=PNiŚgő1«XoZŞŢ«,#úD̉dFT‡“GcE=˛‘‰ÄĚv"Ž·*g‘™H ÷0'şŻňF€,"©%kݬ^s«Ĺ ‰YúA—aŶ‰ç¸Ůű"fŽŘä (Aý˝tŤ&L J ŘIŔҤ<±ö>čA~ń=‹S´ÓË*Úa‹8ĺ\PŘČ Ţ8–7@7AůňSKĆ“ŹŻ˝·ĺ&µ ŚTŘÓDçË'8e*Ă*ącGÎt^şě LO„|úđňq”ősÇŽň‚BčąP&zÖkj—C)Ľtň]ţ e12‘ČŰm¬PěĸäHBţ·§?`ł "QŢp‚iëďü¸Í ßÂäxFSŹL$ŕ{Ó¶ÄM4śeä—âí[”@ŤţćT&:NYF ë?ŕ˝`ŰĎoy ëmpü˘rp&[{ax ď_<ÂvÖ0Ů*"DgŁŽŚwFآܱ#hA‚{^Řúüz7‰¶« KźZżçŔĺěj1ä•3{Y ß%n·±ć;ÁN®ś­nجĂăĂçź|ü*/{HZą¶C°#˝ű[3ŘÄßßů¬ĺd"qźŕűÄş]ŻóM4Z–RDó>z™¸{ĺldůâűkwŐ—Va{ĘPîwďů#íĚç·v¨ř"ž;Vhçˇ(C°#Đŕ/{Źł)Ë6¬|îxďsrVC°#3¬/`´“0ůá_qŁţü`G Đ,W]R–Ôçt°IäÚÎ;‚~sŠ[°˙ŕžçŕż@Ý3BÚä…-Źc׳ľŕ,#??öëşÝć/÷˝Híŕ˙(ËĘD"TŔ·w< …ňšX$ß»÷Ëŕx¸í4Ҩ! żt×CŻžÝ§=SUuI+áoü’Ź>°,áXýĹ?uşîfą®Žx y”#vd|jňě˙ŰxOmŘł˘j ‡Ŕ‰ţôoĘÖrÄŽŔäř‡/ńź_ŃYF`ŃÉuňźü–l-;ňă#ݰFŰĽxÍÚ˙Ţő·<*OçB°#°gرâ,#2 ¬8‰s ÁŽ@ľI EYFd&QxŽďµ‚ÁLC††ú˝»•řúŮŃ×ů¤ †“´dB°#?2íY^2-3‘ ýßßůE,Â3®†B ¤Č •ŽÖý¸oĹ&¬Ă˙ňÖßsS”eÄČDňýÝ/@żüJ,*<2p„ěe°řR•Ĺ$łµĂ±#˙כǟżĽů‘ćšF‘‰Dýŕyč;°*ˇ,·č˙xě{řđÖ…G\(*dď·¶?…%ÁŇxă˘U”eäĎßř!7őÔ†űa:ţßďüsĢj®]#ęLJ_ˇ’X,Fí3ĺT r^±Ü%DÄÎŐľëož?Č( 8Ç®ť§:śĹꍳv Q&’śą$B°# Ý{€3…<şćž˛‚č—Ź;ÎRű0Ű09维嬋°Ji‘mO…7 ˙Z[żTkСM5K§¦§Ţi9Ä—ďlÓĆ$9€4"¬ĄüT„†IG¶błC"QŚ‘ś#%·ÇP ,j;­Ť¨řŕĐ,#cúÄŔÁ@ÍIK;;‚őŕŘ3±Xqş€Ć‹ÝíÎCcŘ0f´ąčL„6¦ ±*8Ů śÍń© :&"ěHSő’x,N Şi" RyÂ]·{‡'FinĐI˛:ú»¦l'FEa„€˛ĎťůSЉ"2˛€¦Ć&ÇÄĹŽĐ×í±ˇaJÜ"rş…`Glۆ·Âh„Ň‚"ťüfJé8 2;2<>ęxč12Łĺ4˘¦PŹÇŐ<¸?ˇ×ćń«ńItbéČ ú$[g"QłŠ§Ć(òüb¬"'xŁÁ#q$_XG!„Ś»q”PŁ[‰±t!ܧLžť‰ÄŇá !QvD~ÉF!1v‹B8~p/9wv%xÔ€’Q ó ®ö^g@7ÔŘăÚšůÁŽtŞ„"ÎąžŞ”Pá‰ëH]±sCŤÄŽ M¨ÝV‘‘›ÎÍ!«ešîąĹŽÜ”ű‘{ (±őYł„‰đ 5žÂtasm&Ţ™;väÂÍ+¬÷!%(¨ćş‘ő&1ěqa ÝGXH”;v_q&XzŰőI˝(´uáz®‚1.¬Ń7ÔŘăÚš;B4oŘ‘÷/áĎ  ,$ ÁŽ`;+u©AĚnĐłtĽă<ëP*”Ř‘-KÖPăď¶…€HŽŘlŇCWO9×:ÚČ2‚Â!L`ŰÓąäĺŢ°Ş°y‡Äެ¨ZL3°(wěČ»MşÎŃĘęĹ$Ld–´YYXĆo«[ú›]˘Bšť°¤ŹĄqEA a.u·sü˛Â YPŘ•PD@ščžOˇ­âIúš[d$0DbG €HîŘ‘&©/­’":wěČţÖcěD¬Ö0.¤gŤ%Ĺ–YT:Ú‡ÝGײ…ügvdߥŁl'€é‹ŔB˘ěúę†óX¸çěŤL}ČĂGVď|íě>¶ŮđsBîľ}á ‹;²ÂFÇŽ<şćčJVC°ýhkźułŚŘÚBCˇ|“ě`$±#ş0×°#DącGŚ kĺ ±#şđé·Îčr;Ă0,r6V±Ąe’;väŤshĽ—úĽ©ˇ™lÚ7Î}Č^ó¦@$;˝Éł†‰Ü§ Ďs!dďłü…H(‚źo^¬đ—/źzŹő Lčş’ę×ĎeŘ‘gďz°˝ďÚ§éĹN€cçŮęćB˘ěľRoü»;Ť`"ŞPôoďxZ& ÁŽHßP# w.»K®íůÁŽ@ŮCŁüŹ»ž·4 k€ëP!QîŘqaŤbűýÝ_ĄB™]é»żŠ§ĎŢÁD,˝$¸Ę…?rbÉĘ4űâ]5”ŐLLMĘYE!lţ#™DJÖďůţ•ŘĐźěůÚK'ßŐţ…*ć"ĺőŇÉwŘé@ ÚÉ…‰Ř ޵v„ ůϱ#đAôW¶Ű‚‚Ř ’#vD}%ĐŠ˙IĂD¸úń÷|Iľţ‚‘_a…“Ł$±#Ƶ5!Ř Á ľŞĂö…D!ŘťP$Dţ_ţ=KÝ^>ůž,|QĂDhČ|CŤÄŽ×Ö„`G°ćĄµ˙ż=ň]Ëw‹ ˇĹ¸qŘHd&ý„ u?6,Z ćŻ÷ýśeG^ž” °˝˙†´ö˙ěŃ?°´˝$ í?{ôąBvĸ°Ęˇ€ţŢÁŮşđ©¶ţNéÖ”Tţá=J`Âďă Rđ"±ŃţîŕŻYyí^±ewÓV|řńa”¨¦v­ÜÚXYĎ0K+G8zvä[Űź’îmŽŘ‘ë Óöžĺ†,±Â!Ř´îĚ^ĆŽ Ů30ZşZÝĽ *Ó•%4 ĘkKŞdf»ěl6yËĚó[łôáŢŢÖŁÁ„Äřčę)uEŽ.b˲ ę[Ą]h%BBÄ´~ˇ8´6cG`Ĺ%I˛ hDÔř€pW9§lBňŻ©NyA1ÝF$±#tm ťZP ťrXÚ-běČšÚĺňĄâě¶žcÄb5Eĺt¬tąçÚđä(± ¤Ĺço^ćé‚×_¨ŹaB3vdiyýčäů 4tđ%±#–ö×čćtš>Óľáľ–ÓGë…éü·z;R§Oţ'§'»DĽ†«ľefş•J¤ČÖUoŇŞDćÎěD;ÓJćÓŚms40ěsCͬ°#–+˘3)xpv$wúśbG,ďşś vÄň]Gúo™÷ŃĚ;’ÖÉHřĎYbG([‘5§Řo2’YaGŚ }­ vdFÄŔŽ@şQ¶•9ÄŽL«d!™d$łÁŽ qH^™bäß ;by“‘Ě;by"ó€‰ëd$ŽŔ0™ŚdÁbG`J 0˙ج@já`GJóбaĺĘ!SoBD>vÄřа#V(@dAaG®Š#Śą!’‘Ě;"SŚĚ;RUTFˇÍO€ÁSč Ž;âĚ;Bţ˙9ě„ä˘RĹń“aGdŠËĹŽ@Č„+v;ťâ;[…íλÝÖě°#±Xś8~ě'#!š%v„ż’ŘK‡·Ď@řg;"SŚĚv¤©z‰”Ă9bGdŠkˇbG°ËhkKě ˛@±#:ĹČ oˇjwç2@$ÂŽý»ÄŽ Íe€Č¬°#”bÄňbGĐř˛Ş†c™]?Ř‘‘b„±#–‹r;Űt€JbG@ʬąGľ??Ř‘7ĎŕőÉŘ‘Ăm§™Ł;ňřZ4°#—zÚůWź9ěH‹řĘú±#PUl™|ŞŘ‘f7Ĺȇ^@‰Ěv•Q(SŚ0LD&#™=vD¦ů´±#–zĂű´cěLFâÇŽ<ŻĂ~vâˆŐëďŠyóüA÷ZĚ;2ŻŘlŘ.~ü;aG €HîŘĚ$_lôicG,•Śä‹˙(RŚ0vä5‘ŚÄŹÁ„§);ňÄş]$Řç ;BÉHřĎYbG° µŃâ”,^»ui&ýŐü`GÔWÉ!±# ň×™ěn‰fAł(ŮůU;‚?ţrďϸ);A‚9ÄŽX ňSćř©bG°YJôÍĽ˙¶Ř É4;K왂s‘ÉHfŹ‘)F,;b$#1°#P‚O®Űe}Rě&bů’‘Ě;˛¤˘v׊-†˛»#vîŰv«­:‡Ř+“Ś$;˛D§±ĽŘK'#ůó7ČÎ;ň'ú›ůÄŽ|_O—H‡*ą1Ř3oŘ85đă”mďĹŽź ;˛cŮř–;˛˘Jm=JP={ěHUqĺ[ýŘ<iWĚ;RçÖIěHQş ¦¤B}˙Ř‘x<ѤÎ'ŔŽ {EéB˘őbG,oÚr;’N¦ÉąŘ˝T2–Ŕě±#ĺ…%I}Ě'ĂŽdâ;BaÇlŘz(v$?™§ŁÉ3żv$‘¤Î|ě~(!łÄŽpŕ^bGb2kěHĚĹ$|2ěmÉo>żaGśÂĎvD…ç ;’˘áĚ!vD§Hš–…źv„~Xvä3…IĆăe%ź]ě )ńć;‚ 'ÔÂ'ŔŽ”ç—+'ÂŽXźě¦‹Ő'ŔŽ4VÔßꏰ#óŹÁJŁEŘ‘ůÄŽ¬ÖŮđź9bGş‡úä ź vOĄ>8°#v„(ÂŽđç@ě]dĂćiŞYzXĽůú™ĂŽČëi>sŘ,Ş›CŽ`˙ĚaGäő4ÖBÍ;ňď;ňƹقúĚaGÚú®_Í\ó»aG^9ł—Ď["ěČ|bGZ{®éxçż%väWÇßćÜ ;ňÝť_´´ťl`Gŕga…/pěaG;—P>ÜO;˛H_OcÍ)vd|jR>…O;ňv=ź—LF±#üŐbGŢ»x„o~üT±#ؤˇ>‹Ř(»?¸G Ě;ňŮÂŽ<˝áţŹŕhüŰaGęJ+aů[ź;˛Ľj±´´ç;’L¦VhWý`GJň‹ SůvÄú¤Ř‘”›Sŕ“`G ÄŹ°#źQú`Gb1Yí“ßYS€©@ČgăΚdZ>†\î¬I)Jl6Ř‘‰©IŢ˙łľł&Mł$±#:}HŚ.H#úÄwÖ`Dů©ĽŮ`Gđŕ$GÂŽ`€™'bbG’ęâ±<Ë‹I'RŁ&‚53t‘ QŽŘĚ0]~FDŠÇ”x±#|=ŤÄŽ`fdĂy»łZ“ ĂD%Ît-ěČÂĽł†’‘Ěćά[ 0˘˘˛–ÄîX°Ř¬půâ>aGĆ=ČŹŤą6ĐĹ“±#W döŘ?LÄ şČćŽwÖŔĄˇŹ\-Űť5Ý}®8běČő[7%’c–ŘüÄ Qá%}‘M·(Ľóť5ś W‚Á´pDßĘáÎL ÄÂyí&ě¤YËÍĚKĆ(Ë2řΚ¸”Ěçť5ĐłxŽ&2f`GZ{Ú•ëĺbG řZ{:±#MŐKäÚžě&b]dsúĆE6 ±#X˝čü<ßY#a"–‹‘ŮP¨Ű“ÍŔĽ#eůĹ2¦;wÖŕ)Čłžěą~ěLJúM4·Ř¨Š^Hě.Ěp ÁŽ`_pđĆĘ‚૎ąP¬í;B´p°#sxg äVÚ<ßY áw8vwÖ@ľíZąeţď¬9xůÄmWärgÍýM۰ĺ˙ÝßYóqŰYgÍŠúŁđŃÜbGęÜëi$vÂëśëĎ-vOâU–;˛¦v9Ęý×Ó@ ű/˛á?ç˙Î>ÚŞ;ľX«Ćő4„1.˛1°#Ź®Ţ /ŔŔŽ|aýnxłąłćĄ“ďňąPtg Ńü`GÎw]AôYÝYĂ×ÓHěJěť5úzš,/vDJvýF\OĂŘ‘ź‹‹lfygÍó[`˙”ëi ěJrąłfOÓ¶fˇDć;rµďú›úz‰ąŕ^dc‰B˘Ü±#XŢ">«;k664ďŇú”`Ů˙đ௩+‡;kŕ}|çîgfOúâÇN°ß^0wÖ|cۓһź[ěČ÷wż@h‰ů.ä:ąÜYóřÚ{IÍ…`GđôŮ×ÎńÎ?LÄúDwÖŔđ#(Qvzzś˙śÍť5Ű–®#ť(±#Ű–®…ń`ŔDč¤čż˝÷cYxÇ;kŕŇţçżÍB°#°Iţjß‹ü'aG $;R˘Ż§±ĽŘ‘Z}‘ÍŹŹĽÂŢ=cG 9µF ĆŽŢY¦äiůÜbGľąă);ňťĎŔb9víĽ0!CîÓ¸ł.^G—!Ű>v ɉٴx \ž#ş*Żż)HçˇD#f<Ř‘‘‰1ćN¤0Ţá‰Q^9č<˘Şń:)JŘ(}(NĆb&Áă€äźśŕ}<ž(ҨčQ~îyp„¬gH†1N©&|LI^‘Ü)9bG,oŠ c4°#¨ŹŮҲ#~%í€Ü±#@>5°ôᦥuž@9¤ŔQ¦Á˛ˇ@ŁÄ(”ćKM3?Řě){Žĺ„Ę<«XrňHÔš/ěZŕ>0v¤gx`ĘťCTĆÝC}SnÄ€ƤéÓRg ŔĆĺ<וVcçJěHZ!?2c\PŘK‡!yëáY`ůŘ#ä¶ °#x@Ľö`šŔ\bGę˝őC°#ŘA|ÖéAŁ–ÉH°`µË˛ł! 3mu<”Š'ÚÄ,ˇł ĹĎí7V.â[/’ĄúąHě§…`G°¨äs/ť¨ťgDxL‘,aěşĘOěŞDD';‚źç˘Đ*P(2 ę/­¨Ăęw€b¶.Qłzą·ašŘAfKw›Ň8šü",FÔ)J;r®ë2o´ú’ęEe™Łíܱ#78ȡ° µËńádg‹˛Ü%!µ[v‹ÄAViňcG°×xëçÁ†jśť:`ÜÖ×yÉ—Řذôţ QvÄY”­,Ř‘{ĽÁÚ;B4oŘ‘#ígؤëi°Şe$o粻č|„(;rE˝ßťAnÖńň#mgx›4Ő,Ĺ8pů'[ĄK QůŤIKC¤ÖÎ;˘†ń9ʶŽ/ÖWô‹d$–>%ÄĆ‘%ŹčZşŻ:JÇVQçM‹WC°wŢr„IŤ.Áy‘ ­ącGŽwśçuCY5Ţ8—ą˘~óâ5&˛R-Ŕ#Kž)FˇqĘ]ĆÉXü‘5*|{čę)ÖˇP^rm/(줽Dí^ąÂD^dŁčˇŐw·Ü¤e$ ĄµŘČ˙f!ŇsÇŽ@´d° e÷ęí÷/á· UVT-ősĹŽ@qčĺ»Vn±t~Lm€Ť‹Vv„˝Â­KÖBBÝËd$O­ß#}şěŰc°ĐHČËú[—®k6; íŕĺŚRřňf´8Ň~¶Íµ'ˇ‹ńđČX'ÂZ& €Śäˇ6JXzßß´ [‹ś•Lń/Ţő„GL1Ţ/ę~¶–{Ř2(aG kp®;ňŔ*ň#ÂŽĺŽA R„ľ°ő1ŘŠ;˘ęŻą÷ăö3ç\{ʱ X„lšn[şN®´Ü±#° hَpĐđřđůźý†+`óŹ(;‚í#Ĺ×ďď|ÖŇńKĆía{âąăóFCË´µ˙A$#y¸ůnÔ”%„ÁŻŢOá»÷|éRw;, ç"‘"DΫg÷uąć4ÚßŁŁ•D!Ř‘‰éÉţ-gSŠŮ˝—Kíűî§ĺ¬†`G —Ř 'ě ă>śy FýůÁŽ@Ľ˙J`ľ±ý 0ĹQźm!h‡ç° wěH§ŠŃr öÜó|(‰Aý/n|Šŕ”»Ś©đ8جÂ"TŘ‘żÖ§‚Ę4ĂB‚SIř˛Č2ő˝{ż ů/K;‚EmBŁnĐÉHŢąpH;Ş ľ'­„ż=đK>ç|¸y'Ú˙ ÷z[/ †ô`Gţ§űż.§"Gěč˙{˙'v¤µ·ă•Óäź>đMY?GěČřÔÄ_ďű9˙ůťbÎ +:·ůcŤřa ÁŽüâř›|^GŘ´˙—{3@„ç·<*OçB°#ňzŘĄß١¶Ţ‹ŢúŇ’ ÁŽ@ĺIřG÷}ŽLF}ôť»ź9pů8J ě$!kL°“–LvÄH1‚G–—LKěęCmAňÖŁ|řëý?Wf•îÇC«wŔ*řoďýĎŻ°ˇ¤ĐľÔ€˙éÁoAżüD”v:‹Ű‡łöŤmµ‚±2)FÁz=i`Gţ÷Çľ“ňW®­bë#–ľřŹÍoü Ë Ö ź°ŮžŢp?>üů?ä¦PĆę˙ůĆß2GÂŽŔŕü…Ű~,Łö™rÄŽ`›˙ť˘Qô" bßżô1Aň’),‰3ť—>j;EuŠó ^ĐXĄ7Î~Ř5ÔKż….–(íě4ř« čěDtŕŽaUCťělˇö ÓůŹŻ˝ď|—¶śuV)€%vł Ëm_ë±!u"§ZŽ×9:9ľťw±#;őÖĐŘ;rß ĺr^éŐ¬n«(Ż«ëŞrĂ; ě<˛áÉQę,ŔsW°*©Ĺ™Ó'vţ{žY…`G®ÝęîĄ=‹»osaŕťDcP[đ2`]ĎŘîB»¬ ą«4c“t€)±#0z sŢN¤—inřµÉ¶ľ3Ö ý¶Ş¨Ď·Ł˙ĆŚ ¨)./Hĺű# c“ăPŁn\.FŃ 8ďúBUL/ĺfVZvěĄE“AýÁ±a^'† ‚Áä8®PĚĘSo§«ărШ),°x<>4>Ę1EzIżr´ž~’„™Tz–&5FÁVL…{ÂŁ(đřÔ¤íž9vÄÖŐd248ÁMi`ŤB«Ř3”Ź«Ľ#łĹŽL‹4hÇߏĹăN¶w8.vDw#ěȧKźměąhě¸N"Y;éCě™™Nb‰“>„›r.»™™áţ%°NUę›~]• ˝}đ#§˛bG,-hxW%‘VÎĆ›q!&ş6íŚâé;uޡĚ(’DĚ ÁŽ€Ý”{%jLŤ(%GĆ †2î@LlÝůŞMLM0Çd\B09Će71oŠ”ü”ť¸gQĄ“é 'Ť’ñ “c2ż Ľ»ńÉ ~Ž`‡hČ8/*ÔAÉ‘Ŕwb⸠1Ą`Ň4~ÖÄqx"‰[q´/9ćiPĽĹĆÖ(9Bč#” ‚cťŚ3\)ˇ@'žXZîŘô*3F­ čyőbş4>Ćľ=6ÄcÄpRń¤Ěř‚:ia"äŽG¨^;Ă1ťJ$†š¤$żP=Ů© sA70X6©c ÁęѲó±”Ýp›wV2–(Î/Ä“âá źxX˛ţü`G°ĄŃŻđL%2 ţÖńăSsXPz{|·^JAh+¨Ď¬ˇ ©S\Ţy«‡9bf`gcéĘ[~đ¬QAbć–W6Č=‚±äÚd†cşJÝń”#ţ¬Ňďąşđ Ő Ü”@„˛â[Yµń\TĚŐŐěpe±~xm@:QÜ·µ§vź­t” !J<µš‘ÉQÖ´—c ÁŽ@ř_$P‹&¬Ď˘tţ5‘<›«Č/iéÂZl(gVmĹÎ?Täő›ý™Ä6®rŚ‘'í[óÁ~‘đ ČR0’< h,<ç^!maŚXŤr†^«A!™w&4nóőĆđ»ęâŠĹ^q—#vt¦ó’Ľ} NűĺŢŽLŠ”Ňjl[X/§ÝŔŚĄˇ!˙7Ô7I­ť;v˘›Ł–ŢV,©t»w54KŽ!ŘKăřĐëÚőYăŮPsÇŽ ĺc×.pű$ĄyE­™|K6–„|·/;r©§Cî/Lţµ.N‡vdčĹŠ°#.Ív䪸ĐfóúEMž]śLďô>ĐěJů‹íÎćšşĺ(éé©°6 .v·ł„GLćE‘+|‹ČŁcÍväěŤV VŠb]ýJMÉqŰŇu0ö·cŹrQiUq^QK·»‹m…|‡Üů–°DűGo3šŤďnÚ*˝ŹÜ±#ŘěĺĹ×kj—CĽ0t ĽîoÚçWŢbS’W¤’Eu^dÄ DńĆE«`¨`µ»ď`Řă•EĄň¶ÎđL´ °# ˝­G]@¤Öúş•GÚϲ봪ş±ą¶QAL.&#ÁŇâ1OH0ÜĂ«ď–VîŘv“X:¨Ź-)uč#«wJ+wěHŻ‚M’vaL>¶ć^pÄŽ`›6źzcŇPhp·ŽL3…`G:o÷|$P€[—®T—Ť?ľö>iV…`G`óĽ~v?[>0ˇżŽ°ÚöĄëP(ßżßľt}÷p?ăKŔëÉu»ń/$«rŇujIśáĆ—UÔooÜ{ě­ó3…ŕX\Áh[Ç*ŕńAlm´Ě­0ť÷ÔúűĺtEآܱ# —NĽ;,lÔUK>vžŁZŃĎkęVÜě}S@L°UÁ:“ôѲž»ëayž;v¤ E. lU”´şh,’Żl~Ö/×ÁŽŔLýű·x6U/©+­2n•‚đ„ň5 ˇ@/şÁëů-Šă;bRQPşeÉš}—ޞ%Śv †ÇŁoŽ‹BX_l{€ž\·KB4B°#–ťÜpŐś–Ěß>˙s„YN(=¦ěŢGn˛(Śú ’Š5Lnyů…5_ŘĐOŽĽĘďü@Ü·|Óçđ±· ÖącG,}?…k‡ŘřjeëqćH N@ôPó”H˙â[*1@–„.T¦ś G™žŠo¨ůá_±7±şv9„<­7őĂ.čD_mćZSÍ;á,0„ŤgÇłyÉÔ;>"çŃÖnËŽe±ţ™#í/¬÷,ˇÜ±#ŻśŢ{ŮÝďĐw/ßŔĂ–ytŤGŞä±4Z‘ŮtB¬íxčÄŁ^W·â±µ©‚Ë ±0‡4m?Úqžť#Ř3ßófî ÁŽŔç’e”/aúßŢń´T4!ŘKoĆąâWPR/ź|—3¸CĚÂĂęęśdGéÁU;`HH°ő¸ď+ŇY ÁŽ€ţ† .ÇmK×CµńÔ6š1Ázn¸áč,ÝŹďď~_=ł—Y^2ŤuőÎ…CÝîÍŚK\PČ_íű9[>VpQŤÇBݸ(ŁÚ±#X„ ǧ6ěÁ✸«4(DŁ‚~F#˛5.¤±˘ţ·"ÜÓë÷llh†NĚÚÖÓöŔés rŤ˙Éý_Çżż8ö&ۨPd;7ě˝t”‡A ¦±#–›Ö˘‡UĹĺ„Đ3SM€™ ˇ Áőâ±7bn仩¦±ľ´ęĂÖă–‹_0”ivÄŇÖT÷ĐäË Š75¬ĆzžTUÜ sdbLÁ¶ś fliy]iA1˝B%@9<ŤČÔ‰.â‰-K×]čş§‰B«©ţŁplÖůŹGUXD•Ąóeľ:+;‚r®żĆł]¤2µ»ł ĂŮ€čSMt –‰ Mń‘)ŇҬÂ4*Lĺ÷ ßr@'1őćÄĄÄvq5j?bZTŚ‰Ň‡ÄâĐ»¶Đbş0ý7‡ýeL~–»ÔŃÉ ŐŤĽDJ9ďÔm˘Kç+;_Ď• ęę<8÷µv†bŹB°#`4:1îĚ ľzfÚž!cŚv šÂŻF&ÇfÜĂCJ’ą¨!¦ž,ę(íĂ!’ęćŚ8GLYĄ“L{q©i{šá>:n«ěF‰¶śnčô S"…A"–÷rXˇŘ#pźđîŃ<55-°#4Wř{µŤqmŤAJ!ÂŽÜ‘>ŰŘËsmŤ9‹T˛ĽŮo Â⎹Ś8ÇlĎvŃÜT¶I3.¬±î„q®­ jŚo±±jrJo€zÉx’8θ‚C˙ňÎx !ŘKGgí,L»7]éj&{Ąä`*Źž”Ľ¶Ć×ů‰Śnlbś…‚Ńbľ{‹ŤĘ¶$ҫȪ Ť‘çpDť)ßT8Iľ€×Čříë<ý]čŢb)Í\[ă­WŞËQ|mŤ.čÂKO×đř¨ź#‘qaŤ5ŘăÚ`‘ĐCÇJřIĆ…5Ö\`G,ďµ5Ćt¤Ü[l,­8%FJRQş@FÜ­yĎе5+[ îź±Ńć;bé« ˛=G<Â1@Ýę ÚŮŞ¤Ş°śö# Ŕgjč%‹J¦VZhŘăÚËöHs8)q4f-0ě%®­ń?¤ĘÂ2c?†`G,ďµ51ŰŇ3 q“’uMQᄌj$AŚ4VÖ“0!Äw FĆž•ÇmÖť°#ŢkkČ!”%ó±Ľ×ÖÄ·ŘX:$Á»’đ€Hgü^A 0]W·Ň°÷rÇŽ×ÖH/xěd™@†đŮ´AFÄ=wěĄa4ÁÂD_k…ý(˱#=ĂWÄUY’ €6yQącG,5罀%)/™”ÖXwÂŽ@Âë8o“˝eÉZCDآyĂŽ@—}tĺd6§Ă¸°Ć ĹŽXZjő XADÖÇ—O:”ÉŹÉ;2¦1&'—čKkv2đÔÍOćíríň†Ś k¬ąŔŽXęńu=Psh6ľÜ;’lť’p¨Kε5>-ZáC‡,4ěqmŤ$¸ö5ď zâÚ…kn~u 6yďMË;béLÝŚ‘2řÖXs±Ľ×ÖH˛u~lĘDeÜPcqaŤŠ±Ľ7Ôd\Xc…bGÔ·â†î6]XCźĺµ5ń-6Eo ŕ‚A_X·‹.DăjüÄ·ŘX:#B6ÓqGăzĂ8ڰ#Ds‚iíąv0X|ٰBż´éaúCŢPcßbĂ”;vÄrŻ­ńnjç/ăÂ+;byŻ­1šŇ·ŘşzŇĎŁ{¨ůnĂt ÇŽ ‘˝—>–Z›& ŤÜ»ü.F÷Â0:đs„Ŕ|D °91¤UŐK9xŹFŢ:ŔŻŃÇ›ykCsć|/Ç’ÇĽo´[vÄĄ9ÁŽX¸30â‡Ű*…ĹN+$!DĄIŔ<~jĂă¨}N°#6ﵞđp´‰ă308†cG&¦'_?űˇ×ćVŻ®].#µH~ܡ­óĐđÝj=Ă/ť|‡Sz0Á=ůęÖ'9<Sö䵿Yµiq3˝Ü/)w쥡`IX•‘ůĆš ěĄ/3ŽD`g B­;aG ŽyÍHű *ďŰúJ)Iáظ]?:üŻăľ„GóíĎ–pě«ëR}bÝ}ś2&Ç?úM Çß»űYĂS ÇŽ€ţńŁ—»˝Żĺ}鮇ŮÇďęűéÇŻŹű"ĄyEß˝ç‹|ö-öî…8ôăÖďá?˙ţŕËśŹDŇ—7=l¬áŘK«EÎ[&i{ă:i™üýÁ_C9»ÝĆă ţŕĺýňř[jŚŢzµ%ßÚń4Źń­ó·ťösÜѸáQźe’;vÄŇöçiťĹŔŽ`˛áÁúĹŔŽŔ¬‚ř2ĽpěĄŘ*±ś;«_ Q–ömi{°#С{š¶°ms°÷hÇy?vĆ/‰N\oŃĸµµ+XŹMMSŮ gŚ:Éx2‡3˝7e`GĘ Kš}Q8vł ŻdÚÍQa‰Y]UÝČlj}Ă·Ř’Ř«RŰ^íëT±Bv¤ľ¬š!ç;owgnKpyÂ+l(«‘‡´t¦m`GĐé•c—i ͉Ĺ╥ĆÁW8v4ědő6±#©<đ(;‚.)ű߇IÄâ2 v˘a^Ň/Ô%®ŹŁŢŢźśđFíťÓÉ<Ž™R\ŘŰŚ“_ĉV9üŘ‘D<‘đEůñ#čµeŕ?ć ÜĎč|$9ÍŢőŕ©ćç+ëEŘ?}ć±#Tn‹‹‘,ßÂr۱ŤX]cT›VX” V€šň’t5‹ůq!Ö,°#–Ţi˛c„AńsÔ7ed8&‚!Ó3ÓňZţíjÝ ;bééRj1Fşőʨ†^É”D1­óŚa˘Űă““rŚ*{R*eËjbG@-˘ŽcrűŇuFk0Ž´źéHMTŘľt˝ß…™ěĄá#‡ŰNC˛0©**ŰѸÁĎqN°#–>FÇĚłłţöŢĂ»®ăČě<ä@@‚ Áć%’)Y˛4¶śÇë™ń|“öśŮÝsvĎ~ű7ěŮoĎŮđí÷턝ńDŮ[’,YÁ ¦(‘"Ĺś‚H䌷żîş·^Ýľ÷6 ňmËŇĂ}ýş:TWUwýn•ń†b-ŠĐeŘňÎqmݲH>tcG”G®źé±} ÁÂctcG”Y ·.pšŚ9`,aQu”§ű†Ş:ěG‹"” $!ŹߢŽ% ń-HľľŹÇ‹×-+hy?o¨Źż v„ĘTaG”qíËŠ0zZ¶Ů†8eżé°D`@kŔß}M vDź6Ł YP1÷Á%ÂÝŘeÎŞ‡®žş” ΗÁčv.ŮT#8ű/aŠ#WaËY/µ]‡|ö ň ľ…^´Aqߥ#ňŘZ»–n˛˛« `G”ÉyđęIţ3_{ě65DYně2gŐ·Ď:tőÜĄ‘ÖătbG¨Î'"…ĆřäĘÂćýTaG”1AOFĺCÇS«vZŞ˙Ť3űĺ»0˝ (¬ëЦö›ď\řXžŃv.ŮmQÜů(o e{Wď˛ÂPµőŢ{çüAys裍ۭK-lŘ}—Ź0EôşceÔfJ°#Ę(—}—>áÄ1 řĐŇÍa٦;˘LüN7Ł E“HęĆŽ(sŰŔśă ĹŤóW<e“»±#ĘÜě˝|ň=y>·vOřRn\ěŐ‘‡/¬ňsë± rPüĺ‰we,Tx~Ý#aŠăbG”QgrŁ•–€+¬Č0oŔtI¶¬zÁÓ«wYaÂĽ”>Ź,ßf…ˇRFť)–~eýŁá{ćq±#ĘśőĐSDv-ŮÓ]ÖÁ·ż9wŕ„¸É­gV?dQ„ýŐéß¶veŻľˇg_±Ă#6ěŰçHЍŢÚjа#4F¬#cGňÓů`Tˬ"ýrúĹÇŽT–”ďY¶5|™3.vD™u<~ëcGňŇéÍ V×ur„ŚÝ ÍşçÄ‘äčőłú¸ç{• CĂ{öJűͦö[ ˝ČËÉ]3o™uĆD#gZ.ű–¶®[^T c÷`üð3iĆ â"eŽ;˘Ě¬6u4únGڱĽ¨¤~Öë:bäV睱̌˙><Ţéé 7`˝ ąyRKŚŹŚŤÜîî ˇJ ‡â‚Bhë’¶w¨f {CĐl"«˙cúmçî>“#†(bgFřŹĆĹŽ(}ź0˘ŚuH™7Ě#ýně2÷ś}Ăý~ç "Äx0-·Łőž|ŽŇî×°—sĹ>S4Ł!ůVScÚM~ao”‘± ĐNöutżZ¤‹ßŤQ>"ń=‘këE”TZ€Üń %’¨őěH¸|jěČÔ¶Ĺ]0 q.!Ť%Ş’m-B}Ĺ4ĺ®–ń»ć “ălŤyzĽÖtµ8śŤ¬ĆyžbČI´JN\˝ RäÖŐ2„đŃ®—--)ŇTXJĹ*$ă4¨Ç1]š˘©’®™÷`@‘ČAŃbŠÂÉÎ“Ë áŤ¬ÎÓ9Ć(o„ăZ“ wkŁĹU ZüˇŁ—ě„Hż>•;šśw€rŹłLřݰą~3uJŤp! g–| Šý>ĹĽ< " ÁÚ`K¸)’R{]Ť ę &*Äé I±Ľ¨4Î Ľü¦âŢ:8Ez ä"ß ‚S!ˇrçŚ7Ć‘ÁÂt" hqk`ű<×¶mďí¤­í–FwtĄ KâŐńÄLĺżł CČ1]±´•91áźÔx'&˛ qbr¨cľ;łSˇ[ĺĽ ˇ»#ş¬wÜDńŤ\ažű:q®µÝW¦tLH縮LůNŰqÓ®LŇ–±L&'•Ę‹ż'TF§śŢý’żx—ŢqëH+·i„ť©”ĂĄČY5M)ßŃ ĽČöź˝´n×ęDýÂrjóg§3× l5ľ?zLKůś±#IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IůK‚IJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IůÝ- v$)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$ĺw·$Ř‘¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”ßÝ’`G’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR~wËçŚÉř˙Já±u˛=tUIĄ\Ő2şťqęL¨)ÓXJW‡śß”«˙cşâ8­ŤeĆĽ¦Ć«†Ćđ}N*'ľójlL·–“ŠmĘt>Űýśq(fĐŽ‹b&CýĎŃ-ąš3łš““Š›. G˙ÇEwç E•›“Űy…JşZ.šĘ‰#8ę/J:ľµQÝÔ(fËQgdl”?çĆĎ:ŹÖ𭣵†š9NŠş˙şZ&7'Ç1hgdtÄP'Ž"µăuóĂ ŽanŃ+wú rqý×ířŃTnü ŹŽ^ĺĆŐˇÖ0FTHÇŹ‘¦”>ç¦b[ĂꌌiŠéś´ŁÎhfÔď<ĆŽëŘĐČ0x ˝ĘËŤ­É63–§Ç=]¨3:ć “T*®5ĚĎj:7ą‰Ćü)ĄR΋ëŞáLBA:?®Žim}C—âzEuĹŘÖG†°L.'Ĺ1ô Őň5ĹŘÎŁZĂ|ćëy^Ç!LüOWnŻ‚âfĆňÓyŽýְܨ€j±G†™ ±@q­ ňç¸Ö Ď{ë ů1ëHHźÁ`é5BSfŤ róu†Çísâ8gPŹŃ«†­áŕUÔT†»‹ňrŇEů…Ž:Ľ;|h(ŠůnŠĂC¨PO±oh€?äĺçF-¦}px˙ŚkÍě2owä¤r ó˘9żo¨_y*Lĉ&´Ö;ÔŹÎ;ę  j˘ZI~‘Łv´^íĚĎÉ+ĚsŐÉ.P:ťłmQ§w¨O“Ë+«C»Ś>cwĺDVë×=&ÄÖp´ÖoöZQç@ćÄ©ČUě5Ô,/,q×á?Ë K#«ańtˇ)Gk]=ř€ÍčP|h­w°J ŠâęŔ˘Ď$q­uö÷đgWký=Cý…NЦµî‘ˇŇübTsÔáĎłŠĘ"ë@ęŚx»äâv¦«g°";ző•ĆH 4…Pˇ"¦Wź’˘_ĹĺŽéşŰ×…é¬V—;(‚ź1ذnŠh ťÇ‡âđ Ş9(˘†Ě‰´`t›Rq·AWä¤Ö: Qt>NŚŁN×`/}† ŕ}ť X^PâŞÓŰÉźQ-ÎččíčDu×aë«(^ü¶ ŠłKfĹu ­uŠŽ:ĐרŁÇXX'p¨Ž XO±BŐQ‡ZĚźUTGQĄ@Dєìjë˝ +®:žb[Ď=ţ ˘‘­ˇWR|U—F·†^±včÓZ7*W—VşëŠ•‘ŐPgČg‰’xŠwzîňgČś¸1Ţó)˘‚C4ˇ5Č|Tp×—" (â(ĐŠ˘rGťa_‡ĹYŹčŇ˝>Ý˙Šâ2‡…‰Ö (Pˇ¶¬*®lă»}Ýh°cŚ&°âGk gĆč˘H­AwT—ʼnŻ!Ý«¬ŔśS6;˛šQ žŔ„M×ÚíîvţŚ:‘†č)Byv{Fkö8ݡ[ëíBßĐŽCż@>ßíë„fŻ,‰î•–®öŢÁ>›[^_§Ť?W•ĚŠk bĽŁ· *ŰU§·sČ?194r€bń¬Hś´?}ąŞń Š>ŲxŠÍ‚b]ĚT€\·ŻŃňsóżąó´-„ŞŁ*tôj™YURá8)´÷Ţ&B…şY5Ž:8Đ":î>ťoďŃJmv鬸Óµa:/ž"ČA)ŔÎ ŹSC°ĂŰ{łâkެÚč^AeűłZoÜęlĺĎłK*ăn0ĐÚÍÎV4R_§­ç.ź& ‘ă(ŢĽ—ĄaFä8°âą8ýB­AŐB×WDϵFDŃNyĽ-Ą€! Ű5Ą•qÇ„;zŚŢ©DăZőr§§jJ«ÜQ íLb¬ťI ĄVŁÇ[§«ßc‰‚Ľ<ô-˛ȵvw`µe•qu¨µÖnMŐ¶š˘1.¨śWçúÝţ 5{FĂ»;𭣵sĆ’"Ćxcěď®-›§ř¨˙ŮßÚµ»ÍD±ˇ˛ÎAS ^ăś.p $6luiěFSľ$t‹/h„Ű]ZŤBĆÉg:AÓgČ·8“ †ß;LÇö^6VS.­ES8q§*e”;Mp0Ś<®˘w^ó8Ž"¬YşúvlĆţᑱ1ré‹»čĂ#f•î˘7rĘśÜő%­óĘ´_\CźănČ1L°MN*ĺ¸EŃŢoşĐó¸“/Égcś7D;Ʋ޸1Jw•ŰAF®´tn¬L ˘Ű HM‘çÎŃ}Hy>ćč1NÄ/Ĺhßž©“••)}7‘g űyp8@ý‡¸·(Bl Ť e˛BB_sD _í:˘Ö2¦N¨csÔ ˛DÔ•Ĺ<Ú<<$ÁIč|xPcúl)dWQ~„v$·˙©h‡µî P,LD«Ć˝ŽÇtő÷“¬ĎxťOçZłJŢ,ą%ˇÚ-Űßö ° M™ĺĆyŰ㨾ňî—łŠž‡)*ş őąäÂ7ˇ Ă}ăna€‘Ă”×—`śáËŘŰí… Ű ŘĹuĚŚĄµ1Tjí}Ż7ĐcMW¤íx·żkx${µös ‘{Âj¤1Î** ; ł4ńWBşÎ`ÖÝ‹9Ż,*ł8 t·ż{d4`»T—‡Ą\wđŽ#ÎTĄó?}®*©”ć4ž˝˘Ť<ŰkźD×ŐY…ĄÖ¬â[şuĺ'¨ČëcěGy}9żbN"ć­Ť#‡´LEq™u7Nľg®ů rK´‚KÍíĎjË]©gŐ^G6ř¤ [<ěÓĹöŢN1ĆŚžüŇŠüEó†…$Ç\UEQléjđđ™ŠřËĐ+í7ůs]yuäY‚®A‰ż ň ć•G«nuŢa$ &!Ě«cKW»qi{Ë .­+«źs:ú:ůú˛(]0/ćţâć˝V>'TĎ ßÇa‹aµîđ ö,řĐš.Č®ŰÝí†â×CS‘wL×ďŢfŠłŁę€â­ÎV^kC±°ľ˘6D±ŻąłM L4éś8{ű Ć:ňȶÁ1›˙\9gq¸Žň/qč3ÚYX5/˛Ú™–ËĘ_ˇ…Uuáy¬2Ć8 Ćí3oV­%ľŔ3ň> FÎÜYŐ‘§čSÍůó˘Ůő‘ŻŢmf1®Ś« ®Ľ&,0Ż´Ýčń·mmYUřâjńĆ˝¨!~ž_P1'Ěů` ş#PFĎ.­^î9ĘĄ¶ë|Ň®-›=·<‚bSÇÍá bÖÖFlF>ˇ)s]yswńÎ5nmnyuä5:*\¸sŤ˙Ü4e¸ÄŕŐŽ[Ł j3 |irăŢíVq×9_R˝ |}Ü=Ř{ľő*˙ąeÁę0Ee¤DsçúŚF–ĎYYíÜí&ľ˘]Q»(|a žżŇqÓ>K,™]oY&`řkw[F…ŔÄ&š\#| î’ŢD¨łĆš…Ö^­Ëm׉"ÍDÜŇęůa{3ĆśŹ «!—`éˇ-0Xóa™śnľĚ>°x˝Š*§š/±-ráŰ=MńÎuČU^ë’üÂe5 E¨Ľ“·.ĘéÂ&Bµ0ETëô).¨św»÷Áĺ#ôúvÝĽĆđ=¬Yq6É@’,©žoU»ÚŃ,EÔńňÚ…‘"ú·—>ńĹxćˇe["{¶GôşxCýňp,-"™  ¸¦n™%ľ —0órkŁÂšyËŇ6Ţ7côz¶¨j$€Eu¤ ŤlśżŇ˛…@ëLËCŃkŞş´rŐÜ%E´Í(O|Ť5 WŕŰ ­WŤĘk 2pýĽĺE„§c„\Z]·Ô˘Mm(Ž(żąŐs—Fš|oťűČű”Q[VGڴ؇®ťâ?ź\ů`¸ÎµŽćs­Mü'úłbÎb‹",ޓ͗Z…Ç’dmݲ°<ÁÖřřŞGŐ¶…kĂ/Ţą~©-+TA,]ĺ[}ýôüyűµaËvă'×ĎČ2Ô1Ö1ÜÔ¦č}ĆNlŚÚŚ(ż:ő[ţüĚš‡Â ÎŽÝ»&BDC†ź‡/ĚŔ“+°Ž0Ţ<űa‡¸ÉÁÉ Ůşbję¸őŢ…Cň:tó‚UĐďa˘Żś|ÖŐúňÚ=a#–˙göK4$şôÔĘťEh˙ý—ŹĘËÉťK6Z ßBŕśv{Wď Ă q¤ýĺ‰wůĎżŘýÍpĎQ`$°e˛µa 5˛ÚýíŹř3GXZ¶őŢ{íÔ>>ă ¬łh÷’Íá›´źű !Q0cŕůíQ– Ę˙óţůóWÖ?yr„AűłăoÓçúYµ‘úĺŘŤsRaÎZşŮR1#CŻžz?V©Y7Ű7ďÝ~ĺÔű'äł6Q¤ŠůéŃ7ോÖíXds@ńĺ“ďYź[»Ç˘Ůűʉwj“1›š(LŞ •éó‹Ö‡V06ŔÖuâóë Ł+>Ľr űë|cóŢ09¨3ěGţŤ )Ë E%D1ă·ö•őŹZa/˝sţcyĹôČňm‘Çí˙ôö?đçom~*|*„:{íô>O‡’KkžYłŰ˘ł´ž¤řŘňíÖÖĆ·ż9wŕ„&ĺ…Ą/lx<¬Cq˙áˇ×řĎ˙řä÷Ă=Ç“Zýy|Ĺkkâë§÷]l»‘ň˝ĆµĄU{Wí´¬XJŻžú-ť_čÍpl´]ˇŤ†1bÉa‘Ňlź–°Śm77î¶Ű$+KĘ÷,ŰöśĽuCeČŐ”V=ş|[xŚĘrífąŃÔĘą¦#•WNľOÝÂ˙"m{h´Ł×ĎęăžďqYXU¶´•¶sÎvř5eˇw€8’źl&[B·ˇ®4űˇhş¦Áv‘2f&źú…ů Ďfµ©ŁyĐż:ĆK Š*ë¬Ë˝îŢ[ťwĆ2cěT‚őyx¤‹/ŞT_1'ü¶$ҝ޻CYŔG޸@ÍĂ·č >t8pí·ĚŤQś†$H.űăU 8<6âCm˘ÝUô>ý©_ĎÉ)Î+˛¦ktl¬o¸ßwWéöĚk~¶k•ßr¤’Łô«ˇéÜg4ű&Đ@"gÄó ëQćßqäł/§â}ßCŁŚ_XiB.~~˝ß4–Š{{?ŕÔŽ Ż@N(ůE8Aë%`«L=v$®ÁHĆ´aGůÂ?̉ •áĆŽČ@˛DE;"ßě—%Śk;‚-=ÇP»i¤Ë‘š VŁ’Ż%…-qÜŘ‘!! b*ňrŇě)ĚGx„)s‰ÉskŕC˛ŰT0iaŹ;‚ ďČ(›¦Á|ň-yʤÓÁ—Ź!ÁÇ|Z˛@â[Âw\ěfžß”CŁ+ÜŘzQ•9‡»†e©‰gµx0ťŘ‘îŢ‹m׳Ó콵uKYŁ]ëh–/ÚrW4Te±'›/J`"—Ćšb`BpΨig ŠoÝĽFK‡ş±#PÇÇo][_hdEíBËŚ™ě&ęřÍóDQ  ¸˛v1»0;z;Ą´á‚ý¸aţ ëá”`G "HÚ’!ŠŇkr¦ĺR[”0Ö‡.ĺ§;rřúiáÍĘÎŮšşeěu€˛;|ítřÄ›pKĂj&`†‹w®ËŃQA;kĹečˇk§$>kŻE˙2ŽĐa°)ĐÚ¶p-«Řř7î¶„Vŕ yzđęIźb îşyËůúŞ ś#(îX´Ž)băűď8fdsĐłáĚ)ÁŽ@>”BvŚu+}‘“ăæă«4}5(gÁJ ňá¸Ř‘·.Ž=ŻĐ¶aMęĆŽ@(Ž*kŮ˝d“ő|J°#`B¬cřW„ŇđQÓ±­­—iŤĄ×ĆĹŽ\iżA·çV¶ÚÚő·˝wńpö`%¦vŰÂ5¬×Pap@Ą0Żđ‘Ć­lČ%$– ¤D+0mŘqřDžŮůuŽ­«ů9fvŰŇRÉĹ1ź6ÔŻh¬µYŃŤąŮŮŠu ÷†Dx»±#°Bß8ł?ĚŐ˝«v˛ŮÔ~óŔŐ“aŠőłjv/ÝĚţćüÁ;QůöEë~ăbGŔrkó¤A)?$(ľvzźŚ_ÂŐ±L–µpźbG`÷ľqćC‰ŽĄÉČËÍ{´qwa`żqvż˛*™óăS«v˛yüńµSžťĽÖ燵;rínË;bą©ĘâYĎŻ{Äjꋍyëě‡M:B`ąŹ)ěěűŮŃ·Mđ•€âĂŇ|u㌠‡ ýá•cŢw˘"4ăŢUöÖvcG Y^>ńŢKĄ´ řëźä]pűţ+GCÚXÁŢžZH$yĹcX[{:±#„őB6áď­ĚşL›NěČ[g?Š<€.ě=úŚsÄ‹‡_ëo_PÁŇĽ°á –ů—ŰnĽzę}ú,í/¨Ľßßú%ë·ně_˙zčŐÁĐta˘~ëł|ť~şĺŇ›g>”ńőMOZżucG`rüóÇŻDR„<´ÎhăbGţéŕËňZ’ËóëĺŚ;=?ţäŤđ]nAnţźîzoq0y÷üÇᦠź‰7vűĎŹ˙&{őEF÷G<ϡďpĚ SÜҰę±ĺ;č3ůáá× ÇŽooů’Yd\ěôť4ţą`»=ľ"KńĽÜ ÓчqĐ˙°@Ď­{„u( c…ЇŮ%•ßËcăBë5YŤ>mšżjÓOćC"˝|âÝžÁ~ţ–Hj“cĺNë3ťŘĆ=/‹ďnŃo—‡/a¦;ŇÜŐvÍ(Ž”WĹC`T—…Ź'něNg—Ű®Źúî”Ú»IÎ׉˝ť|“ĂĄ”9Ľ‡µ­;Š­úEÁ 7B4q* żU8Ó°#ć=ç^ëő~ú7Ś^>ŹĂ0Ö7ZYʏ÷_ĚŞôFaY&4ý"2`ó´aG2*ĂmEÇLĺś´ĺăź*ěHÝ‹_EŐKŕ#˛L1vÄÝZx…¦ ;‰öŕĘV‹ně•’%ś,ĂŤŃ™#Đí¨Ć‰$ÜŘů-ašxaE†G):S$ŚĆÎSŕĆŽ€˘±ş˘zźQ…ů^Îq“OéLőĚŔĐ`Ć:2úĄ".8oněČŔČĐH”KXDNˇ±–@«o0_BűA·0Y´G°.– $¨ ÝŘLWď`"•â|âĆŽôŠ dV×8F(v…LŮ=Úq:GŔp˘EćçQ ©H|IĆC‡4·;Ň?4Ŕ­é0čŔĽM vÓeŤ‘éĘľ°]FŁ`UĘ8Ŕ,§Ł;‚žŐ Ú±FáĆŽ@÷Ë(é"›•ŕPťýÝqë%e»§ ;žÁyi,,1Íßu&Kđ*[ LhŽněö…|ŻWbG”ľ^™M’SÚ‹VÁ^ă—rĐÔP˘E™Đ)Ö¬ş±#÷ú»ĺ¦–MaĎÎńÇxóŢmÚÚaIQU<ËÚ3 ;r§»¬%Ť.Ř#Ö:N v‡ ľŕ°f sEצ„WÚoŤ1˘%XücĺŻqcGüo­Đ` #hŔ~´0ÁńŢP3 ;ŇÔqK&ŃČ–Śö=Ôä­„XeyíBË€qcGε6 1»ułŞ­%pcGŔ‘¨eĐzAyJ°#×ď¶°çĎ*` Š=0:6v¦ĺŇH K4Tε{ňŘČ^Ě9#Z¬ÝŃX».…Ű{;Éo.°¬VÍY,­ŻéÄŽĐ·–7‹ ´ ]›BŢFşK©¬©[F[ 2ä¦/-KA:˝ˇŢ›·3·/ka%żÂč7vßň­ĄU —VĎ 8ɦ;&ĽŇË J×Î󫇯ťŽÄ+ă´¶.;&Ź.;tőTčŕuLH›Öˉ["Ťc¨c‰™ 2yěv˝tBK­Z;­'ŠÇnž‹ň˙é2§|6 aŚîŁ+ÇeTYmăü•daBYG^ŮgŚđŕâ ôç‘ëgďeSZš‚$!_T0yq"g r€ô2XBȇ@ÝÂt_~rýL”őĄ Č‘ŔŲ.ávDÇĽużtě-_‰RŢPŻ«}]XÇŕ×Ůy}aă–;ĘŤůéŃ7{ł-î^˛É ±öĆŽ\h˝ŠŤi$€áÁŘtwúŢĹĂ<«Ţ® ŠO™‹Üż–E{+B5XLÜŘ‘—Í·‘#Z;Żq§±…`ü˙äČ[CŁC‘VÎsëˇ6qL€ WČŁÇw·=+N'väÇźüş-JَlÓmlŹiĂŽčoŹ˝Ůx^:ď;[ľDWL`›h;Áv^Řđ}ţÁ_dŻ_‚ËôäĘ,ťĺĆŽ@q„ ć^A;{Ťq“ËßôłÁáÚÉ>·nŹu~wcGŢ8ł˙TKňU™pz*ň‰;‚ŁŮŻĎ| ˘ ćóOv~Ť>%ä©PjŰÍ VřGĽ<đrÜí›!t;ňŁO^—Imäe(ěĄ]ćĐŮßó×ü$’ęţŮ®oĐfˇBĂ۱Ľ°ô/vC>qcG@ń˙Ý÷ăŠzWEŰĺă żŇüĘ9_ßčA…Ŕ„=}JŮŘü-™Ž·:ď@"Ą˛ńIĄľąy/égZ®Čo9EĆś˛j°´ěç´aG`lŔBă¤0;‚Ż™»Ô’˝“ÇŽŕ0 ]Fv˙[ş«qcGĽŰ3áIĺY­,*'!†1âÇŻµKěţľ2ucG°ÜÚsh„ţNČ8Ó°#86 ¶?φۭ̽ń%™0v$e^§îYY­ý Ţ|„“Lv„č„:F Ź+iű”`G9tBżĺĘWU‚‰/ź!v‹a5ţyaGdĐ‘”ÉĎ4„tYśęŔŽ )ův)v˛ŃÄ:f»±#ž!îұzä«zÄŤfBaŃ[—'$•Ža–|Śm†ÚO™ÎŤX)ÁÜŘ‘A/ń ůwsŇ9é!?k@Ć@:˘”\hÚHޱ0O‹'2Ý0LĄ…QţĐh6Ç žÁě~Ő7”M—PWrňz«8żł‡ź‚Đ>„5~K?3áˇ4Ĺޡ>žU“ý'Wć¸aMĹŤ>ŕ©6ÁT †ѲĺKs`GL¦ş>ńm±5śň‚üj€bDPQ˝"pć )“ Ź#!™Ĺu0F´/âH68:L¨‚ Eď(,•ŰġL.ÜŤB ÓÉ‘çüň`RđÉcG°aď Ç^±Ž=“+ĂHRÎć~?»Ľ2 ŰHf „¨ ŢK:°# (ŻA1"'fŔ›ăĆ~á něH[ďÝŃQŹO°@č˙]oőR‚^Ś]R¬(. B‚jJ+.ŔiÂŽÜëďâř˙čŔěâYzްRŽ—ŤµĄ«ť‘IĄ&öŚqfdó@Zv¤ŁŻ‹ď. t·Ż{Řß”ďÓ„ąĂlŻŁÝ¤ódöúŞ’YXS, ˛Ĺa÷ú §!FćÍ ¤)q`G@Çf¦oÁ2ó.ÎXY, O&L¨ÚŇĘ®Á^¶ç@k~01ĘŚÂŽ@Ě^3ÇT$:ŹQ·xŁVšř“ÇŽ ŮËĺąĺ5X ĂÁ <ĐŢŰÉŽ™tn.†&W ,!ă('vkáţ34",Y—«łdö|PÄşhź«˙ŽÓQsgSÄB['ü…c’7&´ĐiR×Ó Á~Ťµ !´oÝk˝ëű8ńóš˛Ęë-¬ŃŔŤÖĹ–;™Ŕ—J˝‹g×mŘeKŃ;$*×Ę“AÂń-䛼ŻÁIY=yě(Ę;/ZYy_6!ÓŔ DsŠ.5TÍ5Śím%yěd‹Ś–¬)ćĺ›HŢkMÝ2(ťÖ>Ă K®¦ö›l{ŕ‰ŁxňŘ‘k: M ·żĽvá嶬Cń„îĐ?ľz’“Ž ëgŐž9n@waPDO;r°é'ä‚Á »yŽ)BčAw@čé t_¸caڱ¸PćĘó̦0ťżvŢ2ČsŢĽ„äŽúčĘ1¦‚L ±OÍŻšł{Bďď|RzGŻhîj“XŘoEz1öŇúyŤÇo]7/X…±ěż|”G„ĺCͬ¤Ęčylm0ąô˙á‡Í]w8őŽ»–nÂżO·\⇕Ĺe‹gĎ—Ó…vÖáP“ÇŽŕ+6LިGý=•1vćÚşeýCău#“Ať˘ü0-7˛uázÄŤvx3ŕ#:ăŚ7Fčz+ž¶;‚]Ć»6ĎşyË —FkŤ'Ź4.š'ŹąĐz•uÚßҰćřÍsl g[ľ]™LY€ ˇj?l:>âäŤ:ÝĚBnÓŤ8şŇ~çX¸mᚣ7ဂŐDp¨·Î`ŠKf×ă‡jÜČĆů+ Ç@H«Řąd#čuaL>±âml V¬hs~đęIIqWđ|z°#0!Âcŕ+tő°Ć[¬’ćLĂŽĽńź§°‘kîżr”϶Ř–ëÔKśö˝q8˛m7,ÁH8á%`glĄ;rňÖÎb(nţ¨é8Źrăqó˘ö/ŹżËŠä`4úPÝŮ‹ÖKóýÝűŇŃ·yńUiA‘µ‹!aöđCŠG‚'}[vď Çż}f?żsŚo¨_ńîů|…v †dÇŘ^ŢŃhůŃĺŰŚ`ď4ĐO¬éýcG~třő˙]-Űk°č<«Đőř§c&Č@ 7uÜňˇ$z´ßŢň%Řđ‡Żźf †ÄŢ•ľwáÇŻ‚ܰ´;B~\ţßžom’ÇŠďlĹ’w.|lę WČv¬ă;ç?ćëP¤2˙ŃĎůüŤš%!Ňŕ7ÓqÚ°#P,Cpř'ŕ źLÁ„ßŰţśĽO›6ěÖšŹ-‹«ço¬_ńŞÉ8C¤ˇh 1`6üĂ_đOZş†şDmľ°áńúŠ9`uVd8jA˝1«łđäűüž$íŔŽ€"Ö‘˙¢–ÇjěY(HZ-E3^ű{Wí˛ň*/,±¶‰;r§§r’mđäĆi%ů~UŢ6»±#»˙§lkA‘-¨ &ä {Řh0]ţíČü“ç×=z±íš¶ÍôăOw˝ŠŻźŢDZÜjJ«ž^˝ Šł¶ÍŻśó­Í}äŔŽ€âŹ>y]|ű4lchL5ÖôĎw˙~íÔ>ÖhP+0! |ł*s,„±üŐľ㨖0éç”Výęô>nü™Ő»e„E7vF «č0´6T Ov1Ś[üů×üdpd° ;oŔäĽqv?ă?ľ¶ń ,śIqć}főC°{›Ľ[ÁTA^Ţ? Y‚ŔjT ˛Ëń$ˇçżO5Ö6€É!*rôMŻ}Ą6Ě_A÷áĺc =°”é´aGpš0·ÚĹŰ~ÍĽĆóćć„|.x˛+ČpňŘző…¦˘0ť×X»črűŤ~}Ż˘ź•”XrŘ<żLŕ~ó5ňŘ)úrĎźUzÍ Ňď^ůđçüĘąÍ˙1DµÂW¦ěN…z­}¸K]yuŹöwôSíÜTŽ•^|FaG´ kç &í Kĺô‰—0·8ŹP˙Đ Í`ŽÉ¨Ŕoé੤ H;‡ř ĆÜśčť,*ĹDa±WMvÄ :BW»ŁŤ2˙ĎMĺXn÷ÉcG¤›>'ś~|Ó4*˝Íďj™JěČř‹\ĚiĂŽŚŽŤr'@…řFÂGB Ab±#-•ŁsPyŃ)$i řp`GĐa˙ÎK˙‹$‘La®Ę¬(ně„©ćiĐI¶â°H´\Î7(Šl$dň ŤdQčžĺ¶ŹĂŽčL4EăkL{/vĆdř ]č‰ŇČŹ!¦H“áÁ1ßžÎŐ‘”Đľ—řˇdvÄ (˛0rPA 2E4ŽúEAO Ç|bpc˛%yEYg>¨`ş‚vÄÜú€‰t(RŢ®Pfü§;Ň/@!xNáOÄ«ŠÚ‰‚AÉ'ŔĂVÖv¬No6N€~‚>`rxŚ^č*üŠ×‘ž(só«üÝ[ZP$U;‚ ”ď Đ}+ęsű`3iyL;‚ee¨ FGž`LSDAQ>ÁfÁÉ"<ß1ÉŽŃ1~¦H—k.HeL}ËşŠĂŽ`őůÜ_! :ÉM{–ż_ŞK*zš†¬2ÉV5EnvÚ°#-]D#c^ÁGŔzVýŐÍŞf˙ź2ˇA°łŔ˙=ľ[¬+Ă>»±#ŇOŚ%#Š2lĐţáI‘LÉŽŢN^°yY&ŕ ­Łôßă‰ämvë%g‰bÉ0LlĆüb8?ŕ tÄŕ°*5ÚŚÂŽ`řĆŁź1-Ѭz·*ćŘAʧý+{evŘŻ[çťÉŽŃz‹ÔÁ¸řćz“\ÔҸő…€u`G [ä mäí3îjŻ>¤ĄCL;‚ żĺÇ´€ě][×HőYŔÎŃő«Ď·6őyÂr3ŃzZÜŽá4.Ŕ“ÇŽś š˛*ČIp5˝UCemݲŃ̨|˛jîb4L`ł™ą$˝‰Ó†Č"™1lLžéO®źő! °Dô'×ĎŚ „ÁśňŮ`Bą›¶-\ !#giË‚UĐ/—ł “ ¶gcÍ w®zâ(Łď%ÉWw@Ľ¬ŚyâÎK\n»Î»ckĂŘiçZ›XÜ$§M;ŇÜuGúŐČk{R×÷ _Ř&Ëj°§¸z›PľMţsňŘ‘·.°) Ű`Iő|(¸C"ĹŔ¦ů«rssé ÍŘzÝBŮU :ńÄ$­u™>Iě6Ž„Úl^° |ޤë{s?ÁŰŢ“Ś˙Äk\9Î:ziÍ,ÄGâ ]ŐA“­G뉝\Ń8 ?±±[ÄÖ#§Ĺo/ć– ëÎO2ćŞOŔZtňđ˛-ŘÖ0á™–KŢÖÎč¸âëë—A!囍K:2WIř Tá1:±™“ÇŽĽy6™|Cý °+¤ )‘Ś9ř<¶|;žđ­7oŻyUôă«'yŁÍ›U+˝ÂěČŽ˘Áă Ör«ĎÂŽŃ9ŘDŢJ˝¶PÁ&˝ď]8Ä2a×’Mň„8yěČľKź°…zĹáĎ}ľk'c<@Š6Žżsđç©ótr•žˇKr7ą±#oź;Ř?ěéÄĺt˛őłI ”zlůŚzżxňřňćXÄËmžE ăjç’ ć‰CA—ö4ę7Ý_?˝Ź_€Ş‚čxÍ[>PX/lx\>)-(úöťjäĄcoŃ»4cÁzńđk|ˇ'Í’Ew}[>˛WLě4ÂIźŤŃĄŻ™ř^ľŐ„‚ů÷Ţ}oşsÉF<şY ?ľ˙ŔWÚtî›ělîĐÄnž1ˇ2mب*ľuÁQ…8áżpýŚúŇšÝ2źÎô`GG†ţćźňź0! C!ęIeŚâĎw}]‚BĚR,ÁçŘcP"ňÉŞ9K j  Áâ…ŤŹËc‘;b@!ž-HçŃşüˡ_±D}čĐ9ôŞ~b–űÚÇ™żű0 :ůî¶gĄ>r`G>şr D‰I`öü‡_Ŕ‡ţřÖ_¨Ď±•;bBľ·ýË5ĄU¨Ď¶ęsóS„ĽŃĐÉďmţ†@'¦Ź,ߊmőźß{1 :Yľ OĐţŹ?ů5·˙—{ľ#=ľěČk†âé8<'ĐÉzëlŃ}I>–ýooý€Łć:(ţđ0NtÝ˙ů‰ďĂ$řąŹ0ĂŁ˙á‘ď˘Đěl~7 ·ăĆŽüŻoţbk_h˝ú’ß~*•úŹO| úő3űü©˙é±?Ŕ1ĎÄB¨CŃh É-f&«ŘßÚŁňüşG«K*~`°PTmďŞa“ëL—>!hXśsşůŇÁk'=JnŢ·MŇĄ7Ď|x»§ť~ «Oľ\1mŘ‘.5—áz*ŞęĐB˙đ l{ ˛}Ńz){'Ź"3¸ ⥢¶ľb¸ôś6€˝!ëć-—îväfçľ2@:ÚŔ"ď$Ú‚€uÍřX,ĐMtáÉ!CđCyeęŔŽPôkšś˛ëڦÖ×#^[:™Q©¸NśQŘí ęçčŕ,_c†•…ú°0˝')ýZ;µ@@úĄ~GÚĽ•Í>ELΰ0ř˝[Ał’ÖUóô`G¬ tdÓmš0*ĘÄw¤'ŹÉŃ 9qH‘H C>’`G˛ez±#AôČô`G°đcccÜ 4YŘ ĺäŔŽČ„5śˇfDDř°ŇÖ8°#^ÂC3Ôč‡ţ¦˛ŇÖ8°#VÂ2,đp(řť÷Sąg8C ~8*"R :°#~ÂĺżYUč?4¸T3âb…Ł ótÇ$v„rHę'Í’ taĄ­q`Gđ• Ż›˘`ĘÄüŕY…ô„ •Š"?CMŹ@QçŚi|L6rCYľé“Ře°ĎüŮŤ‘ 2(C &AvĂJ[ăŔŽČ„5~†©] M@ůţ=a-ěHi~1řsŔ÷Žc-čŇv »‡)mM·Ć‚řŤűjĐCŽÔR”—/ťčěLX“ö3Ôô‰‡yąąRyO;Ň7ÔĎ-G#âë~ŠN!ář9ą6ĹĂ ćPÄ‘ kĐ8©‰±"ěŮ",v)…0ćʰ‡÷¶Îů|đF t‹-‚OdłÓ†aŻjĆxmŃ l«ć®;<˘ęŇ ´ óŞŇysŘíŻ;Ä]ť8–;°#VÂśĐ@ŃÂŽŔžb¦â 5҂ĪaVń+~Úd¨ŃĽg˛ŘxsbĄ­q`Gd“ˇf¶˙°[<¬ć„5¦/¶žÄŽX÷fv„LvešŔ®'NŘó0»Ž“ÇŽ`şdăţ†x]‰HĎ1B´‹/¸•¶Ć_i@ĂÁI›Q†ÚŇ*/‚Ź´€<¨¤d«T¬Ś3 ;bÖxIyt†šR Á}] Ló<„â»ÜvŐ%N§§G:°—VĎ—śćŔŽČ„5=:qIěžČc;"Öp†šćÎ;Ś´ŇÖL;"Ö€%¨…¦ö›ět§‡Ŕ€f "Žn¸äŘ‹g×K§űä±#G„wĽ±v!ťç? >„x—‘{ČsŚ ”ĽÍâj{Ú°#üU†2ÔŤv=M‘ÁÖî!°#ĐXWrÚŠ9‹ń™°†®eE› ôÚ†ú•^ÂC˛Ţ\—(ă­aăÁ8°#ć«Ű|/Ijd+mÍä±#2a l$rÂAě7“‹"Ł®ť·ě@Ó‰Ńl ŠąÔ‚tľ‚ %˛jňŘ‘}—˛~نʹôţý>á:B÷‘KŚfŚśÜ0*$˛ĘĘű0Iě•°†ś©@fϲ­:aMż÷Ôë†ů:şţ1ń&=Ą­‘.´ŤóW &”¸ăĆů+±U/Š­J.4H [ěŚQ&¬P%ď6˛xXOŘođ~†´0€ČŃ>T©÷)ěÄ•öŢĂŚ¶äw.Ů(Öp†đ <¬)«’#PÄŻ_ϦHß±h‘¨L;b}µµa Q¤‡Ě'°..ůʢ2‚@™20ÔJ[ăŔŽČŻ@á©U»ü‡ŮYĄ‡\Ř˙+ÝÓe5 ”%áőÓűXcZik&Ź‘_q†~1ľá±“ŐŢë9Áę÷ěٵŇűčÂŽǡ÷%g¨‘/”ă!äŐI€ňś ŮÎJ–öÓ«wÉ„5ŕŔ5uîC‰´aG¸)ĘPéôžŘ}VÚšéÁŽčŻ|ü%DߣfŁťYl¬´53 ;"Ö(ó24Vĺ¬~}Ó“˛5vDşĐ ŕH ɇVÚväKGXkłcćťóóŘôśjÄ$»—l˘Ă㏠3řčÍsT ¬}Č2äđĽ¶l¶L[3mŘh(AŁć2’3ožý±#ëëWH3lňŘĘJS-Lnsň°#ÖuŤ;’˝:KĄpć˘{’+m7{ îŤá¨Íe^Nó\­ «ęŠó‹Fő•éUĆŽ,¨\™:°#tGMsĂ8ť=[ü×2Sâjť§bć`Gú‡µ/ŚZHçäŇ$c8쮢´5^ÂÓˇÂt>ů|%vÝCÍ>Ý”WLÄýśŃ±QĎeňJ—úô`Gdđ 97%vMK7úç‚Éf±I°#QeZ±#͸ţt`GĚWvD§†Rq`G$D#‹‰”pS3;’ź›Ń`/ęL;2L-v$ QFĽrŔ˘(ěHM ÄŽä™`$üç±#QAěJ&‚A;:צ_čb=—I¬'±BŚ0L$ (á?'‰ˇčüÂŽ€K;E ;ŠJbG”ąŮĐ;B€’)ÇŽ¤sr¤Ó}ňŘ‘NP„±#˝A@‰…10=F‰ÁYyâ°#>LÄkśl?ɧÎx_±#C#Ă"ĄËD°#üĘô`G ř+ĆŽ(ŤDnýTŘópŽl6;b}EŘL!aaG(‹Ť ZʸÖdĐlĆŽÜî‘©ĂŽ`÷aŚŇŹËn‹F2“±#ü•ÄŽ"ÓŽÁC°Ç¸Ř,‡,ÄŽŕ9}%±#Ĺy…xxýžá7QĆeÂíĚděď˛ `G  ¤ź±#ĹEWŰoą±#ô˙t`GNŠŻ;˘Ź— 2Aě 1Â0‘H@ •ÉcGdĆŽč 5~î0vdYÍ:]KěÚ FŢţ̱#Ř0ZšŘŽ`"ĐrwĚLědÝܲŮrăvDyw^±°#: Ů8;˘ĚŐçáë§Gý@€ŚÁ6a îbG`pnkČŢGO;‚ébß3cGtŢ_vDÂD"±#üĘÔbGř+‰«@›éÜ\ş8–ŘhĆăľźLM5vD~Ą|ě—ˇĆ/vdˇ'±#ĐąKkŢ ÂŽ(ăWŢëë’Đ0vD™7°ÇĹŽT—V.¨ĂE;˘L:nßÂŽPÄŽ <¶bÇ{ńÁ±# í[aZÂŘi L-v3“6y %vdkĂš[ť­·|9ĂŘ‘Kw®3hj±#¨/§M;˛iÁ*ŇP;bD¦;Bm}ŔŽh€^M;kÄđŰ8Ř´pNč ÂŽ`łź’€’u{$vdyí" -±#h­Ś‘ľŔĎ;»Ť¤’ŘĄ"Ź Š3;B1,ě™ v„a"‘€*ěH&‚Żž` 3Ś” +QbG‡¤ŤĎ v!‡µ8vÄ$jÉNxv¶ź„>värŰM“¶ć 10‘U;˘ô+řĎý“(ÂŘ™ˇ&ŚyaĂă”äQbGö"ěüб#/źxöw ;˘ż2Z[bG`–ż*4……i¬m€ŮŁ‚Ř‘şrťŹć3ÂŽŔl WůĺC´ç/{Ş$‹Áµď߸ ;‚ĆďÄŽ( ů˙dÚ°#˙E|ĹŘ‘ź˙Ťg®Ě ěČ_îůŽ|H3†Ýwŕęqy´!ěL P"±#°ĎiăHě¬ă?Ř‘0LŢ»xwS;ňµMOŇ™KbGB‘ aG&"±# (ˇâŔŽ„a"ĘdÎ’˝,ěL# j"±#ó+kw.Ţ(CŚ0L$ (á?'‰i¨śëĂDt!ěČŕČżŽŘ‘ů•sżc˘IěĘ|BD&…ůަŘâĆŽŕ(ôÝ­ĎZŘ‘_x-;ň§»ľ¦Ś$”ŘČęŁ7εt·YŘÖ€3;ÂY8%vdńěůňRk°#‹f×KK{‚Ř‘9ţeťÄŽPÂksőŔŽ(cZŘ‘˛ÂR™2řţÂŽä¤r°Y˙ ŔŽô ŚŽŤĆaGhQ,ěHˇďoĄ2=Řé1gěvNgĆ>#ěČXś`G&_ěHŕ!•;Âý,°#2‘ÍgЎd4jJ±#Ł2Ó±#x…QÁÔ63;Ţ–Íź vĤ§Ń[ď~ÄŽpzšű;‚é"{ëw ;IŠ v$\&ě˘cÉż;>‘S—`G”ßű bG(ÄH‚ąż°#Ěó>ĹŽ 2N!v„/F§;˘ĚU&ž±±ÄŽ´ęD6ŢâÎظ#˙ľś5;]ŽKěX ćQĽ?±#—ŰnʧŔŽL2î:ĂöcGtJTNd3aěHdzšĎ;NOŁ˘ŮHě§§‘.4NdCezrÖ@‡ÓÓ´÷v†ŮP™9ŘHl@ÉT„–Ţ ;‚±Ö8“$v晳ć3ÂŽ|¦9kĘ K×ÎHěřmŽŮĹ;‚Í-ÎYó™bG°p2= 9S!7$;YŘJOŁ‚Ř4kć- ç¬QźYÜ‘ů•sˇÁĐŔŘX2˝…ŃéiĚUµÄŽŔČy¸qkdΚ™†Ů˝t3Tą…ypŃúÖžŽpΚĎ;ňřňiq$ź vdťźžFbGVÍ]"“wLv«€Ăţ1-Ř‘–îöĂŐO‰QËY‰‘9kÔİ#`Ë%łçg™Ę‡‰ŔB'˛á?gvň2Fůď3ěćDŢDM;˛±~~ÜC*ź;âÎY‰Ů˝dÓĐčöz±#PЬ›&ŽQËY‰ů笉ĎD6{^éi;ň˛HdĆŽŕWÎväËëöHÜާŎü欹১™8v'AŇÂź/vdyíB<üWĎ—/ě4 /E'Š)÷ŮP™†¸#ÄőÁż Ť [Ř‘˙ďĂ—ĚĹő§ŔŽ`­O7_:}űň ÇŽ`—‘É!±#ŕy){glΚš’ ę§ÄŽŕĽ Íu®őĘ´aGľ9kşz™ÁŘ,c,ÂŘ‘’‚"4kç¬É+”îĎ1gÍ(ąŃ“¸#÷IůâcG1%…Ië»°#Q0‰ŰŔ9v$3Ć!˛1¨Ľ´>śŹŚŽJ°E:7[ßA—ŘI¬Ś7żµ°#/輟,&A‘¸ŠeŠčžĽ#pbG2ľ—4c/@u$@Q~a8ÄŇr0 (Á!z +ͬf¨ó¶« ďaăŘ ÇŚ:;BÁH ĚX"P”ڍo¨źů¤$ż]ę“éi vŁfo:F$ě˛`"y…iF#>śăŔŽŕW<«y=»tţ3oŚĐŁT ÄÁŽ€˘ÍĚ*,E;rÔ¤e1óBQA{L„§‹Tţ3ţt;ůŤĹŽ`íxe1ŢŠb­Â{ű™b~nZ%“ÇŽô †Cţő{" ¶(b8<ĆHě F’ĺ4vÄ1âő™fŐF˘íËÜđěŮ",va‹`ŁőhäG?39ĚVLxźh!Śá`$T¦;˘ĚYÝ›>Ř[Ĺł ó °ĐÚąëŹ6:¦Ą˝·“ĆŽ€µŞĹĄ;˘Ś‹Ž?vőŮsLíCŕtŠtÜş××ŐíĎ #ÁŻđ[ęiYA1­‹ôßĂ‚”.pvĂáË2Ho˘yăUK`o‹#lŕJźSmi•äí…A ,;`$F$oö'ŹiëąËR.;‚úŕíKm7X6Ö”VT•ĺšÄś4TŐIńĺŔŽ´tµűâ(±FëxµăŻ*cŚçZ›”ň„#ř ["HżÁqNRśQŘ /1tIŠę94?Ŕ,ĺąŰWÜŘé PNěř3bÄÇŽČËw̡ä4vDÂDŔçä„Ă1zYÎÉä±#á#*Śs>Á„C–ŇŚq‰á`$T&Ź9~ó›=Ř(t@†x!/N8ÄHsçľM†±D` *Ó†Áđikg `ŽÖńŘÍóľ>ŇŘp…ôěv¶ŠÜMëë—ăÉe±ŮévIbGL0’%;uCNôC×N3jŰD®‚;–¸ęc8= X‚ŐÖgŠÉOço1ëxV'˛ąG#‚ŘÄü`Oue± Ř‘5uË$ňcňŘ‘ŹŻžbťŘP9’V±#¨ŻŚWLůâh۵0ɰ:śfÝ´r™$v¬%FäLmŇő=ń…ěX´ڤ·¶!&Ü`ĽP;BÁH$vdĺśE`lL }ŘÚ°¶%{•Tvíc˙bÚzY3ČŃy~áÎUz“ć±Y”;ňú™ý#ţůbCý 0 d‹0a[ˇbV#°#8ĐíiÜ‚%cë]d Ń Q_a%á#8JHńőÄŠ¤í4=ŘXeź\Ë"«ľbBŚżyL +ˇo3 ;‚cŁß<ĽLcA`´ďżś]µŻozR¶ćŔŽ€ßX6r‘Č`$TŘ‹śŘ(;ë˘ď•“ďó ~[,÷’çŐŹmÔüüÎ…|ä|aăă8ČCµ±EZś_ôÜş=LÚŤůéŃ7ůę: réuŚäéU»PA Ě0v˛W îGěŘ[2É÷¶ë>ľv꬯t  dç"ÄČĘąKČúGŚd×’Ť ‚ţË˝+wÂB¶°#°ăyŮ1vÄ„á &بBiÉ|Q±#Ú9jôŤú¶?cőŠăxžuhÁy‰ş‡ťŹ çۤ=˶Â*čě“îal+yRv`G°ëYţ×ÍŞ!Ą€mĹ·@(ů«~bţŇ7µXbX>8VĽ,T¶ 4ÔŻ“üąń^KěČZÖZŰřk ň ţňáo+°Š5¨ús›&±°#ţĆÔľ;í0 ÜIŐ决Ţ[ç0väű|˘űčÍsT§çŚÜxó̇·{Úé· (YbÚ°#°„Fi*–V/XZł¦ţ;>fěČć pňŘčqÁB·O÷ţ;9vÖť´´Řđ’wŔLĄJý·.ŢąnF¤Ăî€1sşĺűć±;př˘ OĆŽ,™=_z'Řz‰‘ćťôÂQß˝=’ĄźTĎ’îą…Á´`ŕ)C‘"ž°ňĹ$č»ÖÁ~ď„.°#tÉÉÍćääčyđ[¦—äń«A‘×°jú°#c|!ĎŘݦŹAł’ôä±#™ !ÁŽLľL%vD#ŚIg~Ú°#`Ô1ź Ź˘şčŘı#c𝀱OrseŘt`XJBAJ®…˝ŠĂŽ(™`ĎŐ “4dÍ€ąäxÄ„:$˘hŕ‰ěˇ;˘ €—Ź@'hŠ(â_č9DfFFéŔĚ%$O=ăĐ+C(ăĘË÷źč’2 Ŕ"‡Âëbţ,Ę/Ŕ<÷‹ ,$@Mx’ěĐPmýřaiAćSBL4č$7˛•9 ¤ĄÖŤÁN*Î/‚’ ZZ¨ďŔŽ`JŮ} ž)É/Í3é”`ţe$tµ8ŻóŔ˛¦a,]ý=1S„âLČ»ŁŘ€B@Q(•TYA1V–c (}ń]*÷Ż;‚Y˛††ĺČ‚( EÎęä±#„{"çć›ô^7SÄtćĺ÷đ$bRTÖ7< Uéěâ ) ŘLň˝ľ,p§˘¸ ““‚Rsa*mvĄµ§'áWĄ…%}]#>@ Of• Ś ńŃÉŞâY Ĺ—ŃĘř/ĺ6™6ěúŔyL°|Ő%•0jő¬úŇunůl v4*Hˇ;=÷F}‚)×ÝŤÁW,s090±˝CŢ`) XBR¬*™ńŘÚÝÁK®čěĹoév( As‘­•ÓE>+ĎôLŁ> 2ge$39Ő˝6A•gvۇf•omŔö·:[ÇDH éžZTX3o8ä˘`ˇí‹ÖIý2yě¸E†üYWßx­Ł™Ą ő€ąŚűčĘ1b‡í ńá°Q„'ËĹŰęjŇŘe3lců°"ŘĽă@,ˇˇ ţmĂüжRŽm0QF0K¬ŁK ŠÁ'RvG¦ó1FТ1ŇC4^]Z &á`‡XĐF#Îř1 @qÓ‚•¨ ! Ű® 1ѢUëë—_h˝Ęx/Š2I(Ýö«ć.†IsüÖyO}gt@‘ĹŐóÁĽŁAqsĂęžŢÓ‚â®%Ń`brŞĺ’ÜăŇ &ŤQf‰ŮŇ€-ůpôć9§ę€" kşz?l:îʬť· cüřęIžg<±BťĹaGPŢżxŘ?hhÚŞ9‹^;É!ń°}6Í8ůŘ,zm!—¶/\–`źYłĘŃÇ“e@ńĎwöŘ_ŕ…üÁĎźY˝»¶lö‹‡_ăQCóĘŤćŔŽ üýG?çSáÚyŤO¬ŘńęÉ÷ŮNh¨ŞűΖ/ˇÂ?üĄçŻMĄ0µe•X !ŁÇS©ĚOÂ9‘Ó­Ľ¨ô«ë»ŮŮęŹZ_ŘwëłŘhÜ`Ş-źł’"®C»ůuµ…Uu0V!yň]Ďmcé&h´7ˇŃĚ!ϱ˛ňânÚ°#PúF8č©ŔXpđÁ±ôVçňGäĺäîi ž*„^»őé‚#sĂěy­Ýíč$ŐĘK§ńCIŃ|Óť÷P9uĺŐP‚ZÄy5`Q3 ;2–]Ę-K®g¨źÝUôfřŔđ·ő42#Uś_4:6F§Wúe‰~=Ő+~ÎMCĐő f!9ą…B>«éÂŽŕ9źĐ9ŮŤ‹ÄŰxfŐr‚n÷ÉbG‚P„0v$"ԅى8˘ě,ź!v$‚Ř焱˘ŚXĹJXŁśŘŚ2b4”‚ˇÄaGĚ·Łü.ŻU8 7v‚˝ő\˛ ‰DyQF2*Š$G"áâĆŽ(##ÜTJ4 p4o2ĘU HâűđŽě7rÇjtH® [‰ĂŽ(-ţÇ2Y܉lŠ#‘P”Ń+ŻšoJćç› e„şděÖH:Ë q`G¬(#VSkAŘe´ŁîÉLK$Š2Ę…Şş˘YEŻŘ@·ŞQf5zŇ9Đ#źó猱Ľ-ô˘;˘ŚÇ—-ÎL°5‰¤¨Tî¸ÉcG”‰.·­ś1ěJşóEÚű:#ǨD$.ěĘFÉRô[Ë@óU—.řÜŘýí`–s”hJ™«@’*2ĘŐy+aŤšFěšľeĆúi±5G¦­ń«‘÷:5§ĽFn47vÄú6GĄF…ÄĂ<Đ:bşdV¬Ář\gpŘbÍťwFĹs)<ŃŽD('vDyQF,Š~ř%h!аŞéąŃw9RxÂ"ŻRśQŘţ–ŤŮ˙tNzaUŔő8yě ¦­I§‹Ö(#CDě–LŽ TòćÍQf2‡}ĹǤ!ű‘Ht”‘{-,ŕ­u4q;rlFaG`Kŕ`Ć:4ĐůŚľ.§•˛˘Ś$—˙´Ö('vĎ·6ńĎuSŹ[Q\fíqvD™ś;rkCéskĐ ÖĽM;˘‚QF,Š®äőp>Ó|9UG‰H$\&Źč–sž¤9@áCe”‘pÇÖÖ- ‚§ ;‚rüÖyŽÔ7:š=m–Ó:ZQFt5q(]<»žV]nżÁ€«Ć»±~=9Şa4ŁlůËó-ÚYÄ{9°#*e$DQ߼H‹nňŘe&“ÜĎŮóŮąů#:,"©XĹJX٦;202t(› DĄ˝Yőö¤H$·L”‘Ś]Í+‰DRśŇ¸ŤS›ťÉ ąZĆ|ţîÖgĺµŐ´aGG†˙éă—ąĂVçqŘâ“MMv6ˇ5˛cä˘6e”«Ži´ă÷”ąµ{ńđŻř9¶¶Ł•°F9±#*eD™[ĺAAńŹM6"˙ŃĎY7Qfo ˘śŘĄĺä+­ľ†•äT(aŤrbGT0Ęi-_ľ4ű';_ ‹ëżÝ˙SńS>G«ĹćWΡ´,V”«©§WďZ#â€*'vĺŻ?řI—ßL!Ř ýމ‘&˘Ś„)f ÄÖš×Z^;ő[”dBŐđů/vCúŹÜŘ‘ ­W_ą“¬1~gë3 fŻťŢ‡3ŻÁ@ G‡&ňÝ­ĎĐpŕĂ> Ś:<2ě{R+ç,"Ô)áŐ8śCľQCľK2őĚOžsĚ*އjÚ¦5•Jó‹)¤—iĂŽŕ4a zŁ‚ĄMGxęţ’Ůó­WŃ&ŹÁ¬B—1Ś&×Pä X˨p`GPζ\ňg›î—Rľ÷łJÝY…ó8ßňçćäŇ­#ť;«zVĐőăŔŽ ŔÍŚŇ÷9©śŚn*ĺGÚ(”ˇďÔ ĂŽĐT ]rücĘ&˙Ž÷Ž·!fü‰~}ńZ;¬\ąłČíňA4V>5]ŘĚŕ!şçýßrwN;˘‚ik‚l”®Ş‰=řť-SŚQńđ‘T˛3mŘeśA‘ß«`^%*nězD+č;‚.ÉSz )ť'Đ17vDCŹří{•y{űˇG"HZAGÔxŘeî…3Q śÜT. V+ô,M<ů&ĐHö¶ űfŐŤ1ř»U(čw~$"ă{„@č‘ඨµqcGT0ô,á #j<ěTTż %»şĽ•dčY(e}ÖˇGDŘY 5ěĂSÉ2ô,™PĐ5vD#+ý·š,ŞĄEaÓä±#VčI—‚ŽĐç^‘ÝFH€ŮĹł,9ŕĆŽXˇG$ĺŠârKÝş±#ĘÜ6˛Ě3–ˇ #Ĺ‘ahD+čšFěŇńá»0«6{eĽ #ôäŇí®¶1› őźVĐ5vDCŹ(±{) =KDQÔäŘű…u‘ůt¸W*tDŤ‡±BŹČ¦`‰ň~äĐ#VϰĹćWÔZm¦aG(ô4¸`ş,ű~J°#řŠgŐš1 :BźEč‘€’Ä1l±ąę•ĹŤÁĆ1§U+Srbi¤ ç:˘fvD&äŘ’ń‚ŽĐ_Mí·$JK8črbGT0ôRŮŮ……°´f%0ÝŘČŢs·›": :˘¦;–ŕőVÁHůĐ F•‚‹ ƸzîRËťzD¨ă- «-Ť6yě2÷8×lŠžo~ëµLńă«'˘N á #j*°#PÇ›N8BvÚŔË|9IxL$–’…‚ŽĐg0ˇŹJÉ  #LQ†Q˘ö˘Şy¬†dčk1\Ľu÷‘ëgtđĽPŻ`H°ă´Dx•@ÝĹU:č}ĆV•Fdˇ #ôY„ `G QĂr`ňŘe"[Ü ÚíT*LĐú “Ăóćl9+č;˘˛ˇGě¦ĐŽJ9±#ĘpчJ&*čš ě †‘v] +sžúͅᓯö^ލń°#ʤЎXČľ1+ôśZěëľjˇG‚ýň‚ŽĐź\>*Ź’˘tDM#vÄ =˘Ä(­ #jćaG”=biŰpĐĺÄŽ(٤Lřq»„ލń°#2ôUiÜĆíŕŐWÚ#0y%ů…µŁMÇáŃá—OĽůŢ—tDŤ‡QP(ŹT‚™Ç1/<˙ně2 „E´âb+Âc;‚tŻżŰÚŁĹc#Cť"QśUTV˘8ťŘě ®îŢŕ¬čP(2šČ Ö‚±†#jŘPÄtya~|ěř°Şd–Ô2–í˝ťÖ~¤l5ňI÷`ďÝ Hżż[]Z¶™ÜŘeXâN÷]a3éČXî© Šť_on^uiEâLĂŽ(ăËińrńd5;lh + ¦;˘LŁŰÝíR€âś˛ŮĄÁ- žńč×\šWQ6<ÜŘe6l‹ S5•S?«ÖŠ=(óÔPA…úHÍ<ěň2×´É'ż *ćÓ´ŤÝělµîˇ°g1aH®;˘Ś´Éľ%ozV¨#ÇÔ†ŮŐŤQ†%®Ţ˝%Ť4ô§®Ľ&Ě®S‚Q†%š:nZTÖYoK€m„ŹYČ%śźĂ6Ě”`G”ą »cÂĂňYT5OR„żÔvĂBÜr`Y¦;˘ |äÚÝ–˙ż˝s˙më¶â8eÉ’_ň3Ч¶łŘIšĹÉ’ő1téş®?ěaö—î—ý˛ĂĐbY°G—dXł<í,qűĺ‡l˲-k’ş}y¨t€tC‰Ŕr ~I^ňśĂsľ—§ĹůH ňsĄ)ż&Oý<5¶ ĎŽťö-¶ĎÂęRJą›l5G^Ą¦Ź$źŇ:§äů“gÂ-Ů™;˘Ś-Á\Ąü‰©l5¶ wÄ"2Ą>EČę:yô;›>Âfś;9nÉcáŽ(>Ňëâ©Yß2A-Ţ-?N L$Ič6RÇÁQĆůňEů‘Ý×N+đ‚Ε™,­ű/}OŔĄÉąáŁúýŃ«g‰źşŐć'Ďů¦#Qżu4–3ăGlAJ<\~ę_ĐB#L¬Żßyę穱łäŰgSwË ±mPś+ͤ»•µęŹ©{ĺôů˘g™čôâ±1˝Ú‡ŽŇŔČĄSł)ߥ:&îď?5bĹ˙O›ż&çˇQ@·źß÷ÉôĚŔŰßJĹrÔWŕŽ€xké^Š„mó×ä˛é1vćŽ(‰>2ĐÓ˙ÎÔĹđ@t,Ü ďú‰gě)seţ}Dä<ÓľyTkł$B†Öką#ʨőĹŁŘKďN_ňYH­[K÷[˛+iÎ'ŽŘ‚P˘5ß §‘wgćýËööő’x”_(Gt_wđ‚ŢwD™űźźüĂé;Ę8˘ľ–ÜfőćâmŞůÎ#äŇŐ·.„łÚ™;˘$ú’đűg݆úĄ3wDo'µ$Ţźąś š˛gŹÜmc?ś˝ć#˘˙řčď.OŤ-,Â0r˙Zî21{—>ĂN†čfżëźŃĐ,ź=ţ<ő Éüä\ČBűĺŽ(s#=/Ń»UO†O±%EicűGçŢőô§ă ·őÖö¸#äďť™Oľťą#ĘHBPtMqxĽ>{-uw”úżćŽ(cüîŢÍĘŃ`ćOÍĄŚLŚĄO~îßőÂśŁ‘SG€›‹wZÉ,IA…żýAx~éĚQ†>ň§…;ľs2oRů59ÜXĽýŕč— ţôâu=ő‡Mq ?8{őJ°ŃŢ$wDIô‘bˇ˙g—><¸Ţ$w„# †DęC&›żĆwN>_ů›/>óĚůGłď¤¶¶ŁŹ8ż#V(¦BčďĚQćHŲńď˙ŕđĹ"LťĘ?}ř7źfÚ4Jí—ş ;sG”9×˙ö_7R?ąx=ôtćŽ(cä`o¤>ń‰#¶ öT0óżĽü±oóÔĎSÓ獇ŢăÎÜeč#´Ö:‡ČbĎŔŻľó‰Řć©—§¦UlţÍřë;żwGB[RŮjly-wD?OŤ-Ř˝?ź˙(…ȬnÖ·Ť3#V‡˝ Ń•;K÷±©|îVč'ľço4V2’đE’ęĹR"Η¦Y‡ľ0A LÜ­$6Ŕ{Óóá9ôMrG”9`.Ř/”’ŕ [ěĘé ˝ěX¸#J+…̆Ďaĺś+M…źÎÜevÇłő—‡‰Ě~´?\xüRç©©zCÔ ŕÓĂăˇË´3wDiĹ·˝ş˝é_^’ËfYóˇ-ńu㎨ $—1…1¦:ŹŕÚ=¨űÜ‘lFG0ýđqS5ëű{ţŃ>c¦‚ţ‡Áô7ĆQ}$F?îňč#ţńV •Şô q$(˙5wDyĚĹÎłŮzIń AĆ˙ÔćřĽ–‰ŇL҉Ĺ_71JÓđUšŞuÉO¬o‡ /A÷«+ÂV±M5m :ëءGXÉÍáVŁbW¦UD/óŽx]ŠkJÓGô]Fé¬Q^çŐˇN—Ł;Öeމ>E&LÇ“ŞÖT‡®Kś|:D;±Tóµ;OĎš‡–ÖClĺú1íRGś F×HŞuiMúJżóÔÔ˝ęę„Ř0—,é¦$fŹEÜoř6hÚČłĹf× fCR‚-îÚjĄMöś8«4˘;ÖhLrş)qVA´¤"&=—͉VŽŰ‰5ěź(˘eŮy!Ö=FQ®+şź,"ęsżˇgµ;Ű ŃMó›Ő]˝Ä1DtmĂZ˛¦WâĘatzŚŤŢ2ťĎgsâ5É!ćŇi•<Ä–Ú¶ś*ĂťĐXˇd‹Ą:šÓYśä1šLRűűćzf5źM3´Zôľ…K9…Ą¦oĘiiw왓§“1µ˝öaüĎz^Ó”ŻF6“-HÔ+ŐşioOʱѭ“óĺĹ1¦Ň?ĹL=¸K[†`›Ź ę[‘ö b.Ç<»Dš˘OŮŚ1Łj»^s”©B®˘%9DÖł˝±‰őŔ¬Ć™U^ĄFĚvÓ”¨/jĄrhötDR2A÷[$B)łž]ň¤e1¸ ɖަ…µ–„/QjŚ:/•Y`…l7u¸‹2,“ö-ĺ]ąŘĘŃD´ÄwÜ›h*Y]öxĚŰ1)ŔD*€¸łW·+0<á$[Î[-Zö â®CĐůË„D…ęî«I"rÚlYń<C˝E±ó nxŽďR@™dާ…” L¶ř>Žá8"Ż›Ă‰ľ1Wč;JLteDŢdă@§K+ô†[\‚[ĄYGE‘üĘ‚‘WiÖ|ˇ?‚Čzv>Ç|_ČŰSFëń-ĎI7UčE´źŚÓ”ăl!&"š¦Ä•"'v»‰XÔ©hmŻž7' ´Űâç Ł)‘.­zaΔ î˛«őť>6lľg8˛$ÖkŐš‘9ôŞŘÓ'n4W:2má%şŹŮk!űĘ–ÍMl)÷±ţ‘7±Z×ÍPlVލ†–fUěĺłůÁž~Q ä&Ô¬7öúş{iJT ěYš˘ZŢ$ăŁ5‘¦śÇşJ•ă¶ĐlźŃľÁ˘ ˇ)ă% ë(˝g+Ίů8@¬ělŘ%ÍBęŮł›µ-ţňTʱw@T ěYÇDň®ăJ•6§­©NŽ…\Ue”#»c«^ă)‹- ›ŮŤ ˇÎpOQÜÚĘxµ’źÍ=ÎÝŕĄôý…ń€ďĺ!î°+Ůbl qŁ!Fhͦś(ô"{Ĺ额•­u&cî7š˝ŹšLěkí&*ú: "É©ŚŁ)Q|¸¦·wőűK#˘ťŔSšbŻ1WlšiŠfŚ‘Üo„ިCŃe ŢUy!)Ä!:j5cu(c¤NEŹq‡ŃMŤL Uől­ĚTПѾ!šÍăň&+t=;5:R=ląí]6WšŠ!>]+#Éi ‰Š0ż KŰ Ţsľr1_Ů^,ô#ĆiJ<ć¸Ű›†đ_ń/F7uĎ–R ÂĹqYż`!ľ¨Ś˝„$5v8†śő ź1rÄchęŐÖ:OĂäž® ŞÜ‰‰¦B¶˝E|ě!ľG\Z±‚ž-Gb¦ăÝňăÍZkŁqŞmTŰ~_r™;1%ž€ÓiM4¤9ÚňčŐ3z…}‚r™OeÇh#šÎ󮩆řő&*¦uĹĎâwirnH2«64˘ţ` iÓT Ń„YÝ8Aä!T—uŚ u†ŔO…ššŕe’ş>{-¬ŁĚÉńiĄL÷č6楨CAdş–ÖËő}^â”^"+yѤ¦µ‹0¶ŃlŠ^d§* !Q˘ŃžUĘ•šöšrf7ߡ Ň^ß•k–M&cŻÚM_`l‹3ä2*hŠ9îů5·í«ú4±‰ŘĶG˘Ć¨ ć“B{šČ`}‰†ÇĎe{Ë—!†ÄVĆ*+ĐřŽzb~ĄEô†öä@ÉXpÍą-Ě*vŽóČńEçŢîţ<8<čÖ.ÓŢËÔ^n3ô*)°níl¦Ë¸Çe/:SQOü*±H2“ď~ÇŁ!:é 5ĆÜŚŃČ:„«l(ŞiľVí ;h4MÁĚč`h$ŘĐXť±]Gb!rźĄ‹îŮ(­»(‰ör}Ľ.ömëŘ|ěš weH4pßôoŹíŔ(P-âArB»ÁoX#‘ň»şĘ^endstream endobj 219 0 obj 2479 endobj 190 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [181.8429 674.5331 183.8354 690.4733] /Subtype /Link /A << /S /GoTo /D (Hfootnote.1) >> >> endobj 197 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [216.1237 660.4755 218.1162 676.5256] /Subtype /Link /A << /S /GoTo /D (Hfootnote.2) >> >> endobj 204 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [106.7225 110.7118 179.6838 123.6633] /Subtype/Link/A<> >> endobj 208 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [106.7225 99.464 189.9404 112.7043] /Subtype/Link/A<> >> endobj 182 0 obj << /D [178 0 R /XYZ 100.3464 764.2205 null] >> endobj 183 0 obj << /D [178 0 R /XYZ 100.3464 727.37 null] >> endobj 180 0 obj << /Font << /F20 186 0 R /F21 189 0 R /F29 193 0 R /F35 196 0 R /F18 200 0 R /F30 203 0 R /F36 207 0 R /F41 211 0 R /F24 214 0 R >> /XObject << /Im1 179 0 R >> /ProcSet [ /PDF /Text ] >> endobj 224 0 obj << /Length 2741 /Filter /FlateDecode >> stream xÚí[ŰrŰČ}÷Wđ‘|ŔěÜ<ú¦”R¶ś’TRI Ҳ–˝ ĺËßďôÜA Ťu,{K[)U Ŕ és¦§§A°5lÁ ˘Ň‹RKÂ9U‹ÍÝ3ş¸5çţňŚy›"ąŐ‹őłźÎXµ`”Ô´f‹őÍBŠ’PEáná•‹uűďĺËwë×ë«Ő×}özo+kIj^+;Z} ÎŤ$Bjŕ±'LÉsŘűţŘőÇ`˙t&Uţ´tQpsďRŐÖ”­Šš«ĺyż|yö«ÂlŰűÍq»ďW×JÓĄ„űś^ČÝ…—ÝŞ`ËĂŠ-ßŰK÷ýÁ´J,Űí(ÝĐő›îŕš®­Iw¬ŹđŻëzwćĹůĹ+·W¸ˇ ĺ˛é[×~qĺ ˇÖ„® IkąT®—lÔKă ˇEiH¤Ruĺ™Ţ2ĘąqĐÜâ˝yěfŘ «BĺţĆmÓîúe:Ĺ+Ó©ôŃ4Řžą<î˝ĺŢÝáŻ÷áJ¸Ĺ¬uU/Íó*J'7˛®żáÜ©ľŞšČR-´âDŐő„ĽĽQ‘[9iŹÜřĹÍŔŤjRŇ8f”ô (ă5)e].´¨H)"yü±É»xă¶k8ůćŐĂ:ydĆľ;eˇż8e™FYî<„23Q†&ĘL¨aÂv¶2Ů:˛9‚w BÉYg=ŠŻżţÜwĄŘů'8Ú`ô&Gëir´D-Ç”9)©!–1B9ĺZJ™”ËľŘě†Ö°şżŢú(X¸avqeZý¨Úű»®îřŐ;·Ť×lűŮŃk&V?&ˇK8™ĆGî„3q‚FVT]¦©Š¬đś•M{ !씕@I¤C._ľú]t”~zçJ<ţĐ}AéČ­:FŽ™¦ÇŚtĚ€&:*“ŚQłčžŽkCGcU| #6^ľy~Ă„şĂGĂ]ś~†1.KŞ~X´ŠýÁ)ɬ0Jrç”Ó” ‰4Q˘ şd‘Čqłí5>ľď†Ď#NÖ/Ý6µű»D•ĄqUú {·Ű`jI5‡Ť·łbr{1ůh ]°§Â(‡ ú0-©ç˙rę?٬ɮeš­Ů…ŁŮSV“Ds1˘2+LOÁ śVM ĹLŠÂA“¤(%ĄIRe”LM{2°çÎLČCPn'łIQ ކîý._aBŰGŘ-€ć áşiÝrw/ľIŜƺ4«Ů›NŻuÍđ{Šň“UI8››!s+D~Ń Ě‘·*rłI:˝ť­IÓišPŘD›h’Šh!ëHSZ?ß»’¶f0M7G>¨m´®Ş‹}(oď DąłTŢu6ńgÚĎvß…hżqWŢ»5vkÁ¸Ş~?ˇ3ddf(ąW02PŘD›ČŚ”Ąb‘Ś´z6iŰîz4^˛ą4PP.ăT 4Řa™ŘunĚixűüüÍ ¨*±ÇáůgXČĚPrw`, °‰6±ŔJR›ŁČ‚Ś‘ËĺÇĂaJî~0Ľ<¸9č«ęÁ',`ppqíią1Lúz˝żIvWk}oݶ&=žyĆó™ęůÜçQŘäy6yž|ĄŇśˇ˘çAíöÁbß7;P»˛KR§ů?hÎ5mkóČm2w,„7{¦!lŻá>f&ü´ţ&ĐV ™ĄÉEKŕŢĘ? ř‘ą‰‡¨)QTĎi-7Ă´íf´†ĂF­ÍŔF­‰R-uµ¦ŁÖ†îć>ŽĂ6UČ8· ÎC¶Q5;¸¨µ«gţ@ť Ś}&„§Cw»˝|mZĎţ~őÚέ“ŞkúC¶27-ťöţ”jÓ‚ĐşTsjËĚPµ»9µˇ°Im8lR›¬ eR[Őf uVÇ”u'Ó ´…)Ć…B?±4ˇ°¦źÍ~đkŰXşË ČҸú,±Ő]€{-0ÂÓĎp™ˇäÎ`lš6q€Ă&„"˘¬"UĚt·ź`^ H\ŤOâËőÝÄŰöáţĄ‘á–•OSnJ¦Ř¬Ü23TnÁnNn(l’›ä&LNSłLn|Vn{W<۸Ľ¤… ZeËu°±oŢ!íşc¬LŘďÖço˙öĆť´)#ěścRLÓâÇZ!dŻT˙É—Áś+RJÎç„–™ˇB vsBCa“ĐpŘ$4ĆHUńTěb íÚ×A łf°«ŽbTźżA*’Vh Uź 1e™rŰíşŰƧgâ‘X ý™a%3CYÉÝcĆŕ$+(lb‡Ť¬°ş2ř<{y"+vŕßîî»"Ľě˛űÁßńĚ–%{?Üî|–cÄ“~­[ž~ęˇi…¸>>4îúÜ sýČëqŘčúŘäzĎ4O/D ‘·Ź 69O‹Ŕů~‡ëíî…Ő¨řëoꋼ‡QJÉ•zĚ»6CPf†”{ #…Má°‰ ’AEzIÂt±6¬~n†ŻL)[űÚĺ㉞X6šţ¶ ?ĺőfuáÖPžôzxŢŻgf¨×óîc^Ga“×OaÇßĘ„Źk4«z^şŮI<ę‡/ńłîż{Ńîđô»9úî…Ţ\ďg>|qU&ńxľä? ĎgǡŮk+!˙ĐÄ„ F¤ž­ćf¨ŕ‚ÝśŕPŘ$86ţ„±’hZúřcÓ?} ź˝xöDYýhľBOgřĘĚPľrÇ™ln’/6ń…Ă&ľ¨0;•§+|řňŹU%F/Lílqú‚čuzi=ŘN‹ îeI¬ZűwĘ×—Řy”bknS”%űlz?Ě™¬P.3§bT"˘bfą&ŕ-,'ŠŐ%ţĄ§f„›ŕćžÁ,XąĎ §?ő÷ €żJ{Qúendstream endobj 223 0 obj << /Type /Page /Contents 224 0 R /Resources 222 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 227 0 R 231 0 R 232 0 R 236 0 R 237 0 R 238 0 R 239 0 R 240 0 R 241 0 R 242 0 R 243 0 R 244 0 R 245 0 R 246 0 R 247 0 R 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R 256 0 R 257 0 R 258 0 R 259 0 R 260 0 R 261 0 R 262 0 R 263 0 R 264 0 R 265 0 R 266 0 R 267 0 R 268 0 R 269 0 R 270 0 R 271 0 R 272 0 R 273 0 R 274 0 R ] >> endobj 227 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 690.4389 199.9121 700.0072] /Subtype /Link /A << /S /GoTo /D (section.1) >> >> endobj 231 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 663.3418 444.9908 675.0313] /Subtype /Link /A << /S /GoTo /D (section.2) >> >> endobj 232 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 649.482 347.1704 661.1715] /Subtype /Link /A << /S /GoTo /D (subsection.2.1) >> >> endobj 236 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 635.6223 369.1098 647.3118] /Subtype /Link /A << /S /GoTo /D (subsection.2.2) >> >> endobj 237 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 623.8837 196.0794 633.3308] /Subtype /Link /A << /S /GoTo /D (subsection.2.3) >> >> endobj 238 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 607.9028 395.5644 619.5923] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 239 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 594.043 394.3523 605.7325] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 240 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 582.3045 362.928 591.8727] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 241 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 566.3235 425.0796 578.013] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 242 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 552.4638 495.9258 564.1532] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 243 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 538.9146 266.6249 550.604] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 244 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 525.0548 495.9258 536.7443] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 245 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 513.6268 265.8977 523.1951] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 246 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 497.6459 495.9258 509.3353] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 247 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 484.0967 272.4128 495.7861] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 248 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 470.2369 274.4128 481.9264] /Subtype /Link /A << /S /GoTo /D (subsection.2.4) >> >> endobj 249 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 456.3771 357.1402 468.0666] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 250 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 442.5174 445.2009 454.2069] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 251 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 428.6576 404.1402 440.3471] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.3) >> >> endobj 252 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 414.7979 468.3221 426.4874] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 253 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 403.0593 495.9258 412.6276] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 254 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 389.5101 216.0491 398.533] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 255 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 373.5292 495.9258 385.2187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 256 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 362.1012 227.5643 371.124] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 257 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 348.2414 461.0191 357.8097] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 258 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 332.2605 419.4736 343.95] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 259 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 318.4007 495.9258 330.0902] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 260 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 306.9727 264.6855 316.4198] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 261 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 290.9918 495.9258 302.6813] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 262 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 279.5638 264.6855 289.0108] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 263 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 263.5828 495.9258 275.2723] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 264 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 252.1548 272.6855 261.7231] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 265 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 236.1739 495.9258 247.8634] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 266 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 222.6247 224.0794 234.3142] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 267 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 208.7649 408.2917 220.4544] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.13) >> >> endobj 268 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 194.9052 458.3523 206.5947] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.14) >> >> endobj 269 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 181.0454 402.8068 192.7349] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.15) >> >> endobj 270 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 167.1857 469.4433 178.8751] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.16) >> >> endobj 271 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 142.2097 438.2787 153.8992] /Subtype /Link /A << /S /GoTo /D (section.3) >> >> endobj 272 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 128.35 337.1098 140.0395] /Subtype /Link /A << /S /GoTo /D (subsection.3.1) >> >> endobj 273 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 114.4902 359.0492 126.1797] /Subtype /Link /A << /S /GoTo /D (subsection.3.2) >> >> endobj 274 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 102.7517 388.6856 112.32] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 225 0 obj << /D [223 0 R /XYZ 113.386 764.2205 null] >> endobj 226 0 obj << /D [223 0 R /XYZ 113.386 705.3641 null] >> endobj 222 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F45 230 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 278 0 obj << /Length 1158 /Filter /FlateDecode >> stream xÚÍXËnă6Ýű+´”âđ)QËIś)RăhѢíB‰Ź[Jdmţľ÷ň!ÉIDwÚ™i ¤ČC^ńžĂCŃ,˘đÇ"F)2•Q–JÂ9UŃý~FŁ tţ0c”hF$ĺy$ MĄFHôQ’ĄĐW ý©ä>\íy´hfźfѧaB¦I.…Š’,Ő„k%zVĚ>\2 ďDršł¨xrN´  Ţ.'L¨,*ÖżĆç7ËâbYÜÎ/~ś]ý¬^Sçá•8L2ٸj—±”d CE2ĆL`AäORťĆdž(JG…Ěó·Ť»ďuÂ2X±¦ů°ĘwSćQÉöNŇŢN‡IcbЧ`PĎS8äŔĄ¤,w<©ž§íźę‡vÄ’ŚŻ~ľ\نŞm×w‰ĽÜ¬~řĹj5¦EŃoô/řGěřµť`g ˛3NŐ4;Á žť×!ĺ1;Ţ\ŇLÔ„„=”sŻPţŐŇýąĺqS`G-âőö7ĘDŐVő=ô›¦;©ş9ü˙˙UUm{ή– [ÓXȸ¬×öŮ’A(Á`ň-¨Ž™Ä5ż‘RJD*2đ&ŹĚą}WÂś’Λ=Îńď[¶ŰCă”Ń<زőú«!5č·D#:Ż%D6ă̡kË{«tB'ßTf)X˘VRžŮ’YŹ32“2 u2;˛7T1"¨ňÔńŻMÝňÚ–Ĺőâ9‘éďÍ•_é ®F° WăÄMs ęą ‡¸É”s"UwÚ¬†uŮ•I×íöžÇĎĆ'1qŢo|¤mń|D pŁwÎ3Óą·¸1ŵ}ŔĂşm\Ďí žíCąóó5Ź+‚k8˛‡­“ĐĆŮl*8JRÉżË.ţňľo+HűŤ¦ú” G°  =ÎRM 2Ô 2r$4¦*óŠ”"‘Ýrýôě} ă%ÁÚj›şi«5 ÖH“kźaź‘'>iŰ×VŹ»-JŰ`Ś$ł:Ű˝Řv”#~`ý`m«˛Oö%lý ęĎU‹łMňáWs‚Ź,ČÇ89Ó|z>Â!{>TžFµt|¨×|Tëú@Ź>ëś#@M»Ď·Ť1“Öűř]é>·/ y±ĽuĂŹ™ÝÚł>ô ë+î~=aFư#Gé™d$Ô1r"äŔëSý—Q:0Rb»ĎIi.7xůˇÖ§éx3`ٶŤĆ™ď±g‡C׆!h/k +ź»Ď†şm7šŃş»ÖáÖ3'9ĺ®dSD"Äm¬)#˙¸üĹjŮÔů˙Ĺm˙#WPˇ§.‚((Q‹ 4ÎË3l§‚‹bJµg6łwcŮÝ}ňŢůň®sŘK~ńycwÎaÔXŮzqîÜ5Ö_'¨růĹ<řőś`b r1NK§Ř€QćG™+Â˙wéSčô„s=őÓŽĚ –Pp9t0ssź> endobj 275 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/wouter/texmf/tex/latex/SmallLogoInGradientBarTex.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 292 0 R /Matrix [1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000] /BBox [0.00000000 0.00000000 703.00000000 64.00000000] /Resources << /ProcSet [ /PDF /ImageC ] /ExtGState << /R7 293 0 R >>/XObject << /R8 294 0 R >>>> /Length 295 0 R /Filter /FlateDecode >> stream xśm[Že= …ßĎ(ÎąÇygđÂJâ©Ô0‰oŮűV]Ą–şĘ.ÇIěe{e˙zçTŢY˙Žź?_ţŰz˙ńż×ŻW~·ŢRŮűýóĄżýx­\ręĺÓď§ÍŹ×ßß˙~ýzŁ/aŁő=Ő\ŢĘiä\‡~é{÷]b#{˙ĺ?Żżňď—o mfŰîĽîçŻÚđźľm­áS.‡ ţ–Ú®yż˙űÇ«Ľ˙őš}cłßµ–TŞÎ>űiÖKóă5›íÄqꮩ­Oš‡Íŕ×öŤ¦u™öX5Ň'EǤ÷w]–Z™ÍÓ&řUsoőŹ×śe§aĎkŚZÉŇă<ˇxř3'ßh*‡Xˇ9ý~ŐcpÁîŇĘď|ť˝Ůť­ŮRȦ]ż) 9[2ŰşwR€ÜłY5ŕžç™üć]Äké„0!XŠéiłĹ‚O ×ôâtŠéĺˇÎűóÖĐ]1CȦF¶Ŕ‡EżËVĎ›š:^Źča’'C¦(6ÝűÝ!;‚¶O¤Ób±tŻđPŹâR·e-×ÔŕSU:‚H®pÍ)µ§|ÜăăËÍĽĚ·f˙vd ©?Ąávś„ŇózŮ$! Ëj©]rv`›y7ú]˝XüŻĹ”Ä«6ŮÔô¸kĹÔäµbęCČŤÂ홦2h@Ž&jłx}}Ł!Ŕ ůÝÎżóvŔ}ŐÜ {÷ý÷wÍcŻcŐ7šĐ}h†ĹĚŰ €°@qŚ2sŃ;çŮćwѨň÷9¬¸Őč¦KżA”ËĆŹ+fh@s÷ČoďsČ>u•Ă){ŞĚűŘeцv—ĎĆĽľ°@çXÇźŃ!Ä8 ‹×,O ĺ¸éA˘>Q‡âÇ©č+íŮ=)Oß(čĹxkÁ–ÂëWÍĺVħh†Ľ)ý±.?/M×Ŕśš˘ůŁ‚`¦’ŇŹ)şî"€üěQFŤ6°Ë‚ WŞ€S9xˇnŐw]^N]uŢc×.ÂŘ’×y &Äч7zfä—ě„Ŕ`ç·iô ¸ŚĎ†Ć‘pšcŠRřŢ). qˇňđ0‹÷ŻÇ_m 2&ÎG‡×ŚD""1 ŮbMf4ó6,\}€RËŢ3YÓyĎ`‰‡†ć|¬ŔĂ{˛Ĺ&’ľYMËłŁC X*1yëołRŹĹN`^¸ý¤NDômˇ!0>Pš˘špnÚuł˘t¬<Ö}ĘJ˛=,T’Ĺ=¬2ülĐŇÁž%i°&yg¨) fĹ/á̶¤‚¸¶[öäéׇ…&Ű÷¸‚vâSÍd¸řŇ Ó-¦Ň]ČVńÁŔ8…í±śĂĐiX±5ěĹFŮrđ–/™çIˇ)Ú vQj„MHReD­•LAŽńţ˝>?4XŹP“E8«3ĘCcőn´z Č˙[Ľë.;ŢrÜš»xý*őý2J}˝d'eŤËÂć»ôÖ(vI™ ÂßęODČĎiĺŚk–ň^NOú%›“ýČahÄŘ=Zň@:‡-1ĺ˘:öň®-¸cŢŃ@…Ż Ý„íę‚‹)UôI˝žŞěpĐ«př9rŽxSm3D*–t°ź—fÜ„Á(}`5śĂő ‹T/. U/E|S;Ş|) áu ď~"Ŷý~ci“a\_;{“ĆĂpľ/ň¶¦şăčbgo±¨­n°‹Ç:GÝ%SkćF}¦Z;Đé}&Ht™ĄË´cĽjKâ *Mt‚p( í 0ô$Yí~F‚VĆăô/¶üĂä{ůóÜ–fc4U´vź49ĎĄ)ĆŞ©ć‚8čQ E0ź8hŔ(Ó¶@‘fś^Ń7‹!KD«§Ŕ4ţî–łłľ>{’îËýn =8şw5Őś§ůÄjQTZqh4‘śmWŐ)łżëť‘űÜîąťýAu:äöĎçß @ď4ˇ“\ôx*z´ör>d4yËŽ©iz"ęĂŽÝb÷Ź|nŠâ}UźN_;ÝgŐtѬ^QŐŞ(s*qX¬ŕ.ه°Ł”Š“v” $řŕYâC×c°•+A6 ’ůW'^˙>†™N2ÚřĐtÁkůëĎaÔ4T|×ęăÂ{”—¬§.‰đyهLÉłxâ±|—— °=šą?ő)$ĺó©Í:€~(}=1‡nő·ˇóý[ŰP+Ń×ę˙Ů‚Rendstream endobj 292 0 obj << /Producer (AFPL Ghostscript 8.51) /CreationDate (D:20060104161306) /ModDate (D:20060104161306) /Title (SmallLogoInGradientBarTex.eps) /Creator (Adobe Illustrator\(R\) X) /Author (Bert) >> endobj 293 0 obj << /Type /ExtGState /OPM 1 >> endobj 294 0 obj << /Subtype /Image /ColorSpace /DeviceRGB /Width 2921 /Height 143 /BitsPerComponent 8 /Filter /DCTDecode /Length 20674 >> stream ˙Ř˙îAdobed˙ŰC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]Y˙ŰC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY˙ŔŹ i"˙Ä ˙ĵ}!1AQa"q2‘ˇ#B±ÁRŃđ$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz„…†‡‰Š’“”•–—™š˘Ł¤Ą¦§¨©Ş˛ł´µ¶·¸ąşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚáâăäĺćçčéęńňóôőö÷řůú˙Ä ˙ĵw!1AQaq"2B‘ˇ±Á #3RđbrŃ $4á%ń&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚„…†‡‰Š’“”•–—™š˘Ł¤Ą¦§¨©Ş˛ł´µ¶·¸ąşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚâăäĺćçčéęňóôőö÷řůú˙Ú ?ôš(˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ JZJ(ďEč\P84Ţ€2rh:äҩȤÁŕ0(©Ţ’N‚•3D€śb%3Ŕő©eqQáŽ:P±ÜŔv¤V*XzR˛Á”f…BI-Ćh%KçśÔąÝ>Ő×®8ÍI·‘í@!°}Ăő¦Ď÷–ź!NF9¦Ě¤°Ŕ&€č,ĚU8ęj.c*Ŕő©ĄMéÇQQw*`(ĚłmΧ[±ÉSÎ)Y%ŢŁ9§A\łpMÔb˙ÇѢrZELŕRŞ·ÚIÁÇ­,ČŰèÉ ČŘĹ+&r9¨đ]^BÜŠ–8٤.ăíLŮ*@ą ŢĚĆäđM  ”ŘÍ=ŕ>JË´’I*ł®Đ{üŤK;”#©â™vŚŰ6©8ĎJ’hĚízŠcîS!˘Xä ËU›Ł›|úâ ňĺ"2ŕ/z±r„ÁµA=) lŰ-ˇjžÖ1·۱WQ ¶Ü1U<ą‚¶pNs@2És%‘cÔ©¦Ř©o÷ż © emJNÚmš2DCîôÇÔ†÷ţ>#úçWŞťÜnÓˇU$ăëW(»(ißzO ¦ÉşćíŁ-…đ©,ctgŢĄsŽ˘›,rĂre‰wüiĐvź#0hŘ“·‘šdň©©l h•™Ć»S!ŤĹűąR“Î(ş_ÇŁţĚS-eŽďî‚jKĹ/lę ’qŔúÓmc?cňÜÎAő3öĽ±IpÎw)~) ¶ Í×i©n#G€G•b9z8LVf>­´ç´"bAĄ˙«“ëUkÉĄ%Ř QVôčŢ8Ü:•Éî*†{y¤ňş¸# g@tDúl­$,¬I(zźJ‡N˙Źąľ‡ůŐ›ŽţŽHô¨lb‘.egFPAÁ#ŢëˇÉk«ńâqúf›mpđ$ń“»`%sŘçÖĄą†hŻÄ)żŰđĹ%µ›˛LŇŤ­ Ŕţtgr¦Çű?ÚĽĆßż5ŐĂζń·x±ÜçŇ›ä]y_fňŽÝŰł˙שR„nhĆýsHVvjZ×Q6ű‹!㟦iuř˙·ü?ť:Ö ĄĽ73&ĎAÓ´O Ť¬G F(1–Çť‹×ńç?ýsoĺTt?řö“ý˙éW¬ĘŁ$Ł~*žŹ‘[¸‘ lŕŹj:”ţ$gaő n$g#ËRĘ?§‹ůF”Wqßż`lóŚf•í®­&™aŚşJ ‚p J4É?łJ&-żü1HÍ&S"Km:9&EÜGô«7ŻőOł—+éůfŁ[[»·‚)b1ÇÚXŚqV.­ç·żűMĽ~`=€Î8Ĺ“·ígß-»¶ŕĽŹnqIü‡›ńţU.•k$FI¦]ř‘!k-!FŮĎÍŽ:S)'dYÔăĆ_ ţtÍ'ţ<‡űĆĄľV{9f#€>´Í67ŽĐ+©S“ÁŁ©_h«¨ČJ˘˙3Sj“4q")#~rGĄ2öţTb  =ęmBݧ‰JrÉŰÖk©MCYÝDGÖśÁŻ.ĺRÄéK3Ü\FÓ&Ĺ@#Ĺ:Hg·ąw‰ +ç¶qšo¸lWN¶r ťŔ€¦ýTÍŻ qN®rÄÔńY7Ů7Ä>•†âUŽŚŞ§r( 2IÝ®.R,¸Ë4[ĘĐ´±“ ăę)ÓÁ$s¬±.ěcŠ[{wc#Ę6—cë@őąVhZrçplUÝćK"Ç©SU<©Ő ;8'9«žYKCäí heŹú–˙{ú €śČĺ±´d łf¬‘Ŕ»˝@c–&uE%Xc4A|öű63ógö¤Á„ĆŕçpÉ©>ĚßgÇńç8¦ä•2í 1šR[ż¸żZqm–ŔŽ»E%Ňł Ú çµ;fëp§´S+©_F$ rMO!ÝoźP*’íŕć§‘q´sŚRN Ϧj «9<Šš%>VÖ¨ö:‚€dôŔ•´Y=i°}Óő§˘íŹé°‚ČĹĚŚÜô©"bAµ0«#Ł ÓăRŁž¦€?őŤN“îţ4Ô9$S¤ŻóíLÁĆěóRň`Ó0ŘŰŠ~r™¤N”¸Âb„ Gű•Ž#‘JĂ"€ˇ­I‚HÍ+Pö¤íš^Ôśô =((=((ďKIŢ–€Š( Š( ˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(¤Ą¤ ¤Í©;P“ŠÍ'qGńP–ŠhčiWîĐšBÁzŇ'zI: ~xÍ u'Ź÷)ŚĹ DŚÁzЬĄGÖAšTâBqĺŔm˝čf 2j3ţĽQ7ŢÇ««tëC8RĎ5âqŠ'űË@\OJbʬp:Ón>ŕúÔr×e‡p&”€GzŠçî­Iúµú ¨‚E2lç4;Ş ±¨Wţ>Ť$ÜÜ(=8 .N’,źtţŤ*«„9ɨS‹˛Nh›ţ>“đţt ĺ’p3LŽU“;sÇ­9ľéúU{>ŹřP>¤˛N‘¶ 9ö§Ł]Ęr*¤`4˛îçÖźdNvâ“&I•Ü ÎEĚ‘cqäö^Űţ>¤üť# ×Řa‘žź…} QȞک¦ůËçy\îŞöÜ]89ţtůţ?Ň€ąmŘ"–=Í6)VU,ąŔ8ć‰˙Ô?ű¦ˇ±˙Pßďä)ŽúŹ’ę(ßi$‘פ2 ŹĚÜ6úÖ|*)ËrBńša'ě€vßý)Ě_Žę)h$ŮďK-Ěpś19ôJpŔPvĹ:0ýĂ€FOZďbôr,©ąE1n¦1 îŐWN'|¶(ţBOő4űeEvÎĄH˛ĆsëQ_ÇŁţĚTvÄŤ9ęb_Qí{ ľŇÄűĹN\Ëç+ŚńY1Ş›¸éVíI:sg°lR“,A:N LńÇ4—)o·~~n[K˙W'Ö™«Ë/ÇúP÷nh3*)f8©¨#ľ†IA=2:Ôzˇ"Ôc» ţµJĺU-í™ TäŹÂ€”š4纊ßÉÉě)ĐĎčY×=«83UQźcô¨c% ĐBví?ĚQqs3GűBß~ÝÇýěqV$‘cČܨⱊ/öfü Ţf3ߥ]É:>O]”\jLµéqôÎ3Žju"ˇbHëŇŁÓ .G\ś~UBŐín™Ŕ,On´ ÉŮ-;nţ”ů@UŻhRđ6â«Ëréx± m8íV¤b±ł @•şÚŰýťXnÝ“ž¤»µűNĎźnÜöÍ%”ď:1|p{TŢJŇşŔ ŞrM!]X˝,K4eˇŞq骲y Şô«—h‹q`pECiu$ÓČŹ· 8Ŕ÷ nĚu՝ë”\u§[٤˛“Ľż Mł4oLg8ćť˙č‚i?»“ŠK•˛×úÖŮśíĹ\–öć;At¬ďí ŚyľZů[±Wĺźfh˙»‘šązĄżŮ˘Ů»w9Î1UeŇŐä,’Vę¸ÍX±ťî .řÎâ8¨®î¤†ę(Ón×Ćr=čk˝”Mj ä(äůő¨-ôŐŠQ#ČdŰ÷F1WŘáIöŞZuÔ—>g™·ĺĆ0>´ Ąt%ÖśłĘdI lzńśÔ°ŘĹłBrÁţńőŞ×7Ó}ˇˇ¶PJu8ÎqÖź˘ŇI\ ńőżĄ ń¸ÄŇH ĘYÎÜUË«´[lÎ9Ćk4jW+˛Y#_%ĎbňýŇDŠŘwäűôŁA'íaű=şE»vÜóŚwÍC%–űĺąó1·.ßëQYę í$w+Ć ${uŞÇSşmҤkä©Ç"€rŤŤËD»Ś+¤rv¨,ôŐ·—Íy Ž:qŚR\ęB;X¤ňíëLµż›íBŢíłt=1F€ÜnOaöĆCćlŰźáÎZ±s\ÂŃIĐ÷«2}JáćZ˘â’Frz˝at.í÷ă Zś[*Á٬s+É)‘Wî®1RŢé«s(•Ç'sŚć™¦ŢËu4©&Ü(ă’ňţauökT ă©4h/vĹ›+4łB–fęĆš¶[oÍĎ™×řvűc­7N˝7JË"…‘:ă˝"]Ču6·;vnzP?vČ–ňÍ.‚劺ô`)¶–+lĺŮËČ{‘Ň›xĐ2G #zö¦Ú^ČÓ47+Žô»r[‹?:ĺ&ó6íÇÎpsVXnRľŁ–Ú„î]âEň“®EX’ü E•GÎÜ`ö4’%´µű0ażvďlRÝŰ}¤(ß·o¶j´7“ Ö;…>0~˝)fĽ”ÎŃŔ ěę~”Ő‹ę6¨VŢUĂËż;łĆ:dć‹KŹ´FIeŕL‚áäş’6ĆŐÎ1ő¦;­ÜZ‰0m¬;ѲÂ'qn 4Ë›—IDQ\úŇÚÜ4¬É Öiqża¸íôĹYhÁĆ8Ĺ@Ó¸» m8§ÜĎä€eŤ0Ń‚/% îÝ“ž•–ś˛¶Üő¤†wó|ą@š×237–Ő¤XźČO+ËíëLŽÔ+Í»(űHň7ăćÎ1ďLK‡ ľ`ZhK,Űp;M:(„kÉ=M$ňÔÇ'˝=äRz‘šĄĆ±)}߆)î»Đ®qšŤdc9N1D˛•!TeŤ ř×bÎi=ŇĎNÔŘĺ%ЏÁß9ÎJ´P:4Ô‹iÉ9¤iqaÔŇ,Ť¸h şoÇ8Ĺ:Łiq :R‰>L÷Ş›XśőĄeÜ1L7Ž =Ű ‘@ Ď/žĽSůri»Ű®8 }(UÁÍ!n;ĐçŠWž´¸Ĺ7qíŇśE \R‘šE9Ą'QŽhŁ<ĐFh‚h€ QFh Š( –’ŠZ(˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ (˘€ JZ(¤ďKI@zŃŐ©h gĐGĘ)řP,1Dť<( ´‚Ł_ő†Ą¤ŔÎqÍ6Oą@‹Ôâë@ăĄA¸ye{ć¤ţť´g8Ąë@¬GÜ?ZŤNÍŕő#`…TőĐ+í>V}čcżbŽ b¬öĹ US ,Gs÷Ö•6Ř‚¤`ů€?Z€±L¸0Ş÷§pE¶PI±wghÍ)Ś‘@XŠ›|zć««…‰Đő5tŁ`RĐś•Đ)ş7lšVa,é·¶*጑H¨«÷T bš°ŠYwSUŰ»cŚŠşČŤ÷”­8âr™îáâ‰%‡fčbŰ©V4VʨéJĘa€#ŢXeżú„úUs˙!ÇúUŔŚ€)»~íŁwŻza'˙P˙Ç´«$# Ň"ŞŚ {PÔÍŤÄI2? F6a±ĆěÖ‹Eś˛}Ĺ;ŔÇĄ+ĘfHâf…S$€«ŹúĄ˙z¬¤H‡*€aJčŽ0ę÷ vĐŻ:–°Ŕę¤ň+ZGÎŕƵ€: `† ű‚(o\P7 ¸RšvÓÔ*ůŠu‡üzŻÔ˙:ť•]J°Ć…UEÚ č)ŽÚÜĎźţBqýE^›ýLźîźĺJcڏbŞ[±Ç4âA (éęäúŐhÜ[M:Éś• qÖµcD@v(P})ä ş+ÜŠDňčTŇťŹF]Šş§üzŹ÷… BúHU벭Čë‡PĂŻ4ŞˇT*€č0¶¦™~Áäóż~ Đd1é%[‚¬ůů›ü´ß×8§˛†R¬¨4¬%ž“˙‡ýăPj?ń˙oř:ŇŤ5ÄjzńHńFî¬čĄ‡BEĺŇĂźî7Ňł4_ůo˙ţµ©LŽ(âĎ–ŠąëLŐ3%$zśÍ.pwcß<Š‚]ěnŽ:Öě°Ĺ.<ÄVÇLŠrŞŞ…PŽ€R±<‡?,Ë%•Ľ+“"“‘Źzše6—öď(ůBŻ?AZËoÉ˝b@ţ Sä‰%]˛"°÷X9‰5ŐÝÓĆ>R­ŹÇĄB“˘ió@ŮóÁçŇşăH—lhzLkhMíő"‹#0®ax¬ídaÇ?©Č©‹‹Íb'‡%ARONťkmŃ]Jş†SÔL†ˇĘE\őŔëEÁ‚Af÷q˝ŠŹsZl¶Îä`3qďWĄ¶†f $HÄw"¤Đ ,…™‹˘ÇÔ˙OëHî-5¶’\„99ö"µă‚(ăT'©­,°Ĺ0XŐńÓ#ĄGkZ2—¸šP>R1ůśÓŁ˙ó~?ʵQ5 ŠG`1MÄ%ó/™ýěsE‡Ë˘35 bż†b>N?CLŚ}«R‘ăÎÜ VâH»]CB)#Š8†#@ŁŘQ`ĺÔĆU†Ţâ';`N’9n'óÇřV»ŰÂ」RޤT…ARĆ‹ Čw7pyyá@‚šŕÜŢ4eUČ…KcĆĎ˝HÎ:Ó%ŠX® ±.ŕߥ"zĂpéo*ç•éíQ”d…'w3± Ł}ž@ü3ôö¨Ľ›‡E„¦Ns@¬Ë7-żO-ęýEŤ˛Çw÷A4űĎŘĚh ?:KX´ňÜś‚(/©ź±¤†IŮÎĺ"¤žĺŢŇ!ž[!Ź®) ŹL«ÍM5“}–0śşg#×4fDŠÖ—¨‰ €~­˙,żéK3Ot˛Ě»BăńĹ?RŠI|ż-Kc9Çá@íŁ/Vfť˙s}ó­:ϱ†HîegBýh)î®3u¨ ŹÓ4Űi޸Ź9Ř _cśZšć Ł».ďoŇ’ÚÉŮ&iľVëAw)ůmöo´ďműń˙ש®§yÖŢ<ŕ8±ÜçŇ›ö{Ż/ěţ_Ë»vúő=Ő“ŞBĐŤÍŹ×4…gb8Ůß´;‹'Ë5\#]­Äîçr@«–ÖňÍvצŃéëĆ*mu›i˝$ăpô ,ÂKÉś‹¸î,T¶y úé¸k\ę ć*ĂéďöAĚŞKëíQÇoqs6ŠĘ4u*Ă9ęj´ĐJÚĽr„&1ڵkÝCu©ťDpˇ ?'ýŞCiú˘B®YŹ\Ő˝VŃî$eÓ·¨¨-íî.o–âĺ6Á錑GQ4ů†ëß~ˇţ•µYZÍĽł´F(Ëŕâµh)|LÄŃ?ăę§ő«:çüy§ýtČÔzMĽĐÜLŇFTÁ=ů©őxdšŐV$,ÁÁŔú:—¸Sޞ/ŢŚ~ßăÎi«’2\*ŚPŽ|ÍpPśNµcó!=:RHŽ“AśÓíă( 7Đ5¸Ő˙ŹłřŇÎKJ©Ú…F%°qëK4mĽ:Ś‘@ ŚäeÎG4Đ «9<Š’8Ůś»Śf›˛EČ=čXŘ´Y=i°}Óő§˘íŹé°©Pr1LbOü5(éQĚĄ±št ă˙XÔ7Í&ŢÔ¨¤9$qC)¸s@¬Wpô¤ÇË»<木y'˝&q@ÎS>Ô‰÷iq…Ĺ09 czäÓ”äSpF@§¨Ŕ B'z:šb‚9 âŽŮ (Áé@ć”PE€ô;Ń@Q@Q@ EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPIKI@ Iš(ď@8 Ň´)84Šk}áCö   °Ó÷†(±Í#"0'é±÷¤_ő†€Ě­ ÁşS2óB­8 —¶÷Ą'źJ˙Ż#ýĆúP¬dR3… óMî­6Ľ´BbBŚž”Ĺ•Xŕg>ôŰŹ¸>µ€q@6Nň*pzűR««.Aâ 7'<Ó˛c¦?­ą?ž›±“ő§łRǠޤł©ďš™żăןA@îHŚw”Ö•UÂäŇ[˙©ßńôź‡ó /ˇaÜ"ĺŽ29ŇC}ę+ĚüžśÓdn#ŰÇN” ˛y'HŰ$űS„ŠSx?-UŚ–]ÜđzÔjOŮÜvȤ-­ĚlŰFGÖź$‚5ÜŮǵR”Du9©îżăŘgÚ€ą:0u :gśľw•Îę-˙Ô'Ň«źůţ?Ňî[vĄŹ@3MŠU•K.p9˘őţé¨lÔ7űÇů úŹ’ę$}¤’G\•*°u § Öt4S–!{Ő›|–ôÝĹ!'rXgI‰ ž=i&ąŽ†$źAU´ď˝'ĐScőäő Wv/E*J›äSácÎáíUtŇwČ;`Qü„źęhö-Í:@s× Cqŕě'#¨=jťĎͨ nFGZH>]I‚đ9é@ąµ.=Ę$Â#ťÇÚť,© nsTg˙śQKŞ“‡nhmË0]Ĺ;mRCzN¸ąK}»óótŔŞ3*¦ŁŚ2˝)Ú·ü˛üĄĚěiTÝG4ډ»+×"§¬Í;ţ>ćúçLmę‹Ó̰G˝óŚăŠtr,‘  FyŞş§üzŹ÷…4’4Ž:ě¤ÔöŤľýąl{TÓÜGsÁéŽő’Uł7`nó:÷éI!,ÖţîŃ×ęhą<ěŐ·»Šç! ;´Éu"ˇ,Hŕ8I‡—«°cŘ»QZ޵­Ů` 0OăEĂ™ěm+«ĆNTŚ‚*+k¨îwy{ľ\g"«éd›Ď@Ç•E˘˙Ëřő |Ű®nc¶U2nĂ HľPś.7dúV~µţŞ/÷Ť:ô‘¤®;…ÍÍ«$MNŮä đ T·7qZć“еŹ: Óm¸–Éîy§śÉ¨Ű‰yʧ_§řŃryŮ­muŇ“9Aę)ň4ş[s»{tăŠÎ˛5‰U8_`}i×ň‹đ˘ăćv5dqlíŃA'­ÔwHZ=ŘŠ[żřóźţą·ňŞ:ü{Iţ˙ô ¦ő±=ĆĄoo/–Ĺ™‡]Ł8«QJ“F$Ť·)čkÉVO¶@-ĺ±ç±ő«ş?g”¸ü¨Lɶ\¶˝ŠéÝ# •ë‘Iu} © !%Ź;TdÖv‰˙Sý?­ ˘My„€0Éŕý(¸s;#V ®"2Fß(ëž1UĆ©ldŮą±ýěqY0–Xďwoo÷‡ôÍ<˘dŁŕoóqžý(¸ąŮ»,« M#ghô¤‚t¸ŹzgÇ5NBNŠ ë°:]8‘¦±^Łv(.ú’ɨA… bGŔ©šxŇ4°ŘzZǶDk;–` `úR;7ء;w7ô˙ëŃryŮ«ä3ľŐ$7`GZ|÷ nľyéY× #»·ňŔ*ž>µ>«÷búšĚěËŕä;óQGp’JŃ®w.sš’?őkôFÓţB˙Ŕżť2›Řą,«nlăÚ–7 uč}j ˙řö?QI#Nă®Ó@ݍóymą?\qS3…Bý@âłQWěNÄ ŰúŐ¤$éü˙tŇɢ•eRËśgŇI2ĆŔ6r}*+ő-ţ÷ôŰĎő©ô¦ŇĺĘŽ9VBBçŹZ’ŞYýç }KH±€[<úR†Cv#5 ßÜ_­+çěÝÇ „-Śź­9ÝP|ŐTöu=óN<ÉďA@®XIúRsPŽ'lqÖ„Ęrzń@\ł‘Śö¤G8¦Eţ§ó¤îź­$g Ś÷Ą¨§ţ”t b;PĚ­2?őŤAć^h"°n”›†ěw¦'ß4żňÖ€x‘C}ÓMO»@Ĺ,ĄĎ¦/CGđĐ!ŕA8¦žÔŁďP1zŃži÷¨h ô t 4QÚŠ(˘ŠZ(¤ ˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(¤Ą¤ ŚsE&hHÍb‚iç€2sJFE7qíN#4psHS'9Ĺ*’sšBÇ8rŤ˘š NiU· Eb\ŽÔ 7sĐŇŞúÓ];W­*9$ÖLľěÓČ#Ö\ů»{SŘáIö cQv g4ŹňqŠX˛’}i˛ąR CŮC. F°€Ů'8§Čű=ę1+Ç€$!ÎAÁĄH•TŽąëI3”PG­=NQIî(/łŚýăŹJ•×réQ¬Śg)Ú‰Ą*B¨ůŤ řÓbÎiŻéU÷căŘĄ%ŠIÁžC–P6Šč±$bEÁü G¸FÜ[q({ŚD¬'µ69śH@9 Z’Ř;n ´žĽS–ęZ‰çr챎­9n3 r>aĆ( [E 1`;bĄš?56çő\\ČĄYŔŘÔů§a Ž ôBh×dasśw¨Ě¸ów~ö¤·śČJ¸Ă C3ýŻËăo˙Zô'‘wĆËśdc4Č"ňP®íŮ9éN•ŠÄĚ:šŽÖF–2ÍŚŠ©–JÎY\¨=F*Äq¬hz ¨×Rł1 ‹V`—Î60z@•Ż Ëk ±ß»>ؤžŃe}኱ëÇZK9ŢbűńÇ §^JĐĆĄ1’qÍ ŇĂŕ`M«É=M1-¶\´»óśńŠ{K˛ßĚn~P¦/'\HĘ dâ€m"ÍͲϝ¬;Ńmj°rYŹz[‰JZ™öQm){a$‡×4ĂKŤ’×}ĘͿǧÜ@·ínäÚ©ŮŰtŁËSŽ•ufó-L«ÁÚOĐŇÓ"·˛XdŢÎ]‡N1ŠuÝŻÚv|űvç¶i,gyŃËă ö·“4®°(Ú$ý(–4j­µ§‘3ÉżvîŘĹ:Ňăín# 8"˘łą’k‰ČÂŚzcşĐšę´EłvŢsśfť!-ÄDî`ńÖŞÝ]Ę.ŕîM-µöřäó†1“Žô‚ęă?˛ÓúÖŮź»ŹëV.lăž5_¸S…#µRű}Î<Ý‹ĺnĆ*ôł˙ˇ™ŁţîFhĺkb¶î\±w=ȨeŇŃä,’Şă5=Śď=ąyČb8Şo¨\;HĐ(ňăë‘Ú>[QB±B"N TVdßűÍű±ŰĹFúK*¨ŢÇnßCQC:O\¨Ű cé@ď˘Őí§ÚŃW~ͧ=3RU­ü—ů—nÓTn/gk–†ŮAŮśź\u§Á¨†´’IßP;çĄxÜbi$Ąf@~î1V/,Rč«n(ëŔ vŞ#QąM’ČŠasĆ_˝ť˘ł2ÄFxÁ#ÖŤąlIJ±KMÄ1wn¬E$–[ď–çĚĆÜ|»­:ŇŕÉbłĘFpI#ŘšÎ:•Ó™D*pF(qI'› ÇśoRąôÍAciö8™7ďÜsśb«Ýja-"’ 7ÉĐŘëMµľś]‹{µ›ˇéŠš7s¤¤Ó4‰!ŹwŢÍ\¶·KhDqô’{šĚ›R¸’iEŞŻ—$’3;ÔăTŮćrŁĚnŢŮŁA'’XŘ}’YÍ߼tŰŚ~´^iÉs(•\Ç'rsT˘Ôîc’3r«ĺIČ8ǵ{S¸’ÚÝ^"7‘žĆŤ8´:ÖĆ+x^?żż†'˝V:É•ŠgîăúŐűWim˘vűĚ š¨—RťQ­ÉXöçĄj:§„KnĐ´ÇJKKłCĺîÝÎsŚT÷Ť$Qdo^ÔŰKŮv‚äă<ĐW 4´i $…ő\U‡´Ťí„<…^‡ľj‹j]âU!ç"ŻĂ?ťkć¨ÁÁČô4ĺ{Űéë ŮˑӌT·vßi 7íŰ횏O¸’á\ČGĆG5Ü­;Gn „ę}qÖ€ŇĹőTAŠ‚+o*áĺßťŮă2sQĹz٤`7/ý*ĽťvĽŠ<¶é@î‹·yŃěÝ·śçĄŠ?.;€éÖ«Ü\¸‘b„Ç˝-˝Ńmë(Ă Íuq ŠîáČ_LU–ŚŚcŚU/µĚA(Ř*in¶Ä…Ěţ˝¨Ń,y(Wvěśô¤š5”îĆ=Ş8g7Ë”i­s#3y`mZęĹʆ|˘ÇvsíN†O6=ÝCQŰĘŇ3Çǡ$ŃůŞqéN <°‡‘ŚT2LţfČÇ"–9óŻë@]-†ycŹJ’HŘŠ‡ĎaI©$”Ťˇ9-@´A9ÎM4Ŕ3ÁŔô˘9IbŻÁß5ÎJ´P= ‚€»GJHÓ`#9¦´¸ŚÔŇ,Śhî›ńÎ1N¨šF,BŽ”ômĂŢ€M¬NzĐČ硤F%Č=(f;¶ŻZr¨Z6üűłHŤśÖŤÇ~;P1Ädb…ŚŘéÖ1Î )^ip1ŠnâztĄÝĆh ŠR3H Ď4Î(ŁĐ™4¦ŠJJ1E˘€ (˘€ŠJ(h˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š))h ¤íN¤ Ť$˙,ĘǧcjîÎiH`€G˝bŞŹ2v+Ó®'CÔŐĹ”=¨(„ä¨'é@¬St"osJ[Íť6öĹ\ ȤUUű Ąbš°ŠYwSUŰ»cŚŠĽĘŤ÷€?ZPŠAĘg»‡Ž$\îSß÷7JÍÓ˙­VŐ6UTaJʬ>`÷ ,Tµ§wwšü„éWPö¦ěMű°7z÷¦őţé¨ly‡űGů ˛@ ‚2 "*¨Âµ¶¦j0‰fGq«V*VOńŠť’69eR}Ĺ:%bŽť÷¤ú ~Łţ©Ţ«(‘¦v*Ź\PęŽ0ŕďH-Ą'RöBTžPÖ±Ä3¸1­`”ÁaňC}9 nApĄ4í§¨ ć)-TľžTu!…ZuVR˝ÁˇUp€íL-©˛„µ–&;WmЦžsÔ©5a˘‰ź,[ÔŽiä=Z@ŁbŽ—ţ®O­VŤĹ´Ó¬€ä©µcD@|µP\RINA‘žŮ —B¦–„Děz1âŁÓżăîoˇţu¤` bG1(ŞőĹĺŘΔ‹}SĚ“;O9úŚTPFÓý©ĐpTăóĎô­y7‘U‡¸ĄEUPľ‚‹ —S Ěżaňyßż?…h2ô’­Ô'5gɇĚݱ7őÎiîŞĘCTő‹‰KL¬Xz±ĄgĂ(‚+¤;ÇqšÜŤ€ÚšđÂîăBޤ Ń`qŃŻŤ:7#Ťäţđ§JâîćÝb!@?Ö·`€AíLŽ(“"žĺE!’’ =NV”ăß<Іěn21ą,QI*#c¦áOU ˇT@(°rô“,–P@ —Rr1ękJý zHCŐBúUµ†“rÇPiŇ":^ŕô˘ĂQĐĄh†Mbőe`?3Yi:¦ź4 ö`GçŇş(ŃQ  Ł *6‚“sG~ą f‹ ÄĂą‚H¬í]‡çŰ'"ĄŢ/uŢv‚ 'Ú¶ŮUÔ«¨e=AآŠ0|¤E®ŃEŔ‚Ae%Ôr¸ˇQő¤ň%¤Çf c5˝,0HŔËl{ĄŔ ·1E…ěÎnyEŇZC%Ővž;Ö–¶1eôqüŤ]Ž#rŃG·r fť,qȸ•U”üÔXj2;řňýÁT#˙ó~?ʵUUT*€¦˘ľgŻz kc7R+řf#äý 2!ö˝JGŹ;pyü1[ęC¨eô"’4Ž5Äjާű˘‹ —SD6÷¸!Ű Đ±BšyÜ1»$U—†pĎő f¤ Ň‹ŤŚý#îËő8¶˝›Ěqřň+J8ăLůj«ž¸˘Hă|yЧ2(] ¨˘fł•Ŕă ţ_ţşWIo J e'5®‚±Ä­•D ě(°r”$gĽF»ĎáŠ"C4“˛‚?ŃuFp÷ˇUUp íE‡Ęf,€Z´g;‹fź,l‘BÄqŹëšĽcŚľâ«»×öŚ0{Đ.R"kĐÉśpi±·”%FęF*ú*(ůJFDc–U'ÜP;Y©{ž)–yęŐ"Ş®v€>”Çb®|«¦-ĐÓcBŃČE\eVűŔ­( @¬S. *ťÁ§8(ń“Ó¬„@Ů 3J@#÷ ,VQćLÄtć‘X,l§©«J({RRr@ͱ]””Ó‰ß"â§<Ži €±;łO„pO­<€zK@XŽ?őŤC|˛äô©đh ´|±=©ĺ­BśúÓf°ĹĐYŘŞqޢ ĆQę3Sʛר¨Bł•˘ń@02Í´śH’Gť)Ň+$›×śĐťŤ»«R-¤F$ÉÉ5<‡uą>˘˘Ů!< ššEÄGa@! 8>™ŞáKŁČO"¬ÂżąÁ÷Şĺ$MŃ€jĘĆäő čČ8ÍHđ%@ĺ…64yeV~‹@†g•ňH*[7,ڧť˝)ŽŹŚPŠšÚ#ÝM[ŰÇÔźŹó©o?Ô­Gn¤\9#ŽťIt B@ëš ëő ôŞçţB?Źô«0!@zâ«”o·îÇýj`úë’ë8“LŚ.ü°ISRÝÂĎµÓŞÓ ŤäźÎŠB{‰{˙ýó«ŐJí§ŚŔ˙»LkvPÓľôźAOÔŐ/űÔ–ĘϸcNżRń(Qži 쎕ĚvA—®ĐP(Rç w3ŃhĽŰAC´~uGĘťÂŔ@NzĐ)žCq,1ç @Î=M;[Ď,`ĺ@'J’ćÝ‘Ł’.v9ö˘ÚÝä‘ĺ—ŤŔŚzÎĺ]†H$ťîR?˝ †[fä… š¨až0Đr9ĎZĽůVf>§iĎÖ„D_úą>µ[iĽšff#j’ô«zj2Fű†9ŞňĂ5ĽŇy`?˘·2 \ś†  ?ţŞŤ‘­– ‘Žç«Kbßbd8ó Ý˙Ö¨î q8că9č(™kS;¬Ôú°4©!‹K:„â—QBÖˇTtaNŠúzÄܸúPWS/Ë?fűNößżýzŃ’C.–\ő)ÍQň.vý—jăvěć´f‡fžŃ/$.>´"b·"ŇÎŰ&>ŚMgŞ5ŇÜNěw ´´ŘĘÚ•qڱŞ/ű’’^3ž˘€kD]ČÚr.ă’ĹIî@˙őÓv›XťĘ ć*Ěš{}P`ʧq˙ Š('ş¸ŚĘH€źJBł”ßę#1 ąŰŹjźF™ť6$„ÁŐĚ3ÚÝĽĐ€CçŻlŐť2Ő­ăf“‡|qč)Ť'ĚU˛˙Ä˙Vţt_–¸Ôc¶,BqŇźg®«3‘…%°sďK¨[Ę·+uŚdjŢé^Ňgłžć w* QUÄM-¬·lě]\źÖŻYYĽŻ4×` ďŢŞ›{¸Ő­©W`s‘Í"ZvîîI¬­Ó$qőÁĹ:%6˘DŽYçľjk­5Ĺś"3—óŚçšm¬Ý^‹™Ŕ=;‘@ěî&˝÷ŕúéVő‰Ú> >> endobj 281 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 701.8656 342.3127 711.4339] /Subtype /Link /A << /S /GoTo /D (subsection.3.5) >> >> endobj 282 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 675.2861 412.4363 686.9756] /Subtype /Link /A << /S /GoTo /D (section.4) >> >> endobj 283 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 661.7369 324.0703 673.4264] /Subtype /Link /A << /S /GoTo /D (subsection.4.1) >> >> endobj 284 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 648.1877 346.0097 659.8772] /Subtype /Link /A << /S /GoTo /D (subsection.4.2) >> >> endobj 285 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 634.6385 482.8863 646.328] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 286 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 621.0893 181.9186 632.7788] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 287 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 607.5401 465.9771 619.2296] /Subtype /Link /A << /S /GoTo /D (subsection.4.4) >> >> endobj 288 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 593.9909 384.5551 605.6804] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 289 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 580.4417 482.8863 592.1312] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 290 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 569.0137 174.0095 578.4608] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 291 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 553.3433 420.0097 565.0328] /Subtype /Link /A << /S /GoTo /D (subsection.4.7) >> >> endobj 279 0 obj << /D [277 0 R /XYZ 100.3464 764.2205 null] >> endobj 276 0 obj << /Font << /F18 200 0 R /F15 235 0 R /F45 230 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 298 0 obj << /Length 2884 /Filter /FlateDecode >> stream xÚ•YKsŰHľűWč¶tUDł|í-‰“-OÍÚł±S{ť-R2+©T<öŻĽš¤dJ“-WYý@7hŕT‹ţÔB)ă›$ZÄ‘őµÂĹj{,60÷Ż %4KG´śR}x¸¸ú¬’… ü4HŐâa˝0iäÇ6¶°[âë$4‹‡üwO].UŢÍíĂ—»ëŻ—Ęűřpsw{ůÇĂ/ź.6µ~ŞÓđüQŞ·gŃ@`}c#ŤgS‘o•RĂQĄîŰćri”—ďW} Gjj<N KúihZţđT\.u¬˝ŰűknÔ°4ŰҨń:řU^ C?.uâIŹčEÇT«f‹;\Ů9Ď÷ ˙6ýŚŹ+•w}{ĎS]Ńm«Ľr»«Š-ŤÔ8×g=,/›ş¶µl‹‡Ę‹eDˇ@7ˇMY(bť/ëřü]Çý;ŽgËc(3Dmv0…Ů#˛®Ęç_.ëů—K *f­ÁęM“UŘ‚s ć ç{Ý9 q2Çýţ(3đA•·˘łÉ&$$lŇ;>YÍÚVŢóDa84'>*Ô¶4ĆzNűŘć«%F^Q3Q»'kĄvă~÷-7`ĂľĘß9eN|˛Dˇ6ŢN‡p籞;ÍšżďG€[pKVŮ®'VÎf¬I˝u‹˛á*±Sbşw†'xÁ&?rw@=˙Ě-MŤ>‰áEK‡3Iâ ćín‚XLÚŚ÷ŮňČ×ë߸Avż˙Ô·ă.oŕ‰xJöFYw‡{Č5Ů> @úÁĹU6 śŻMŤŢĆäíh`q4"H{bÚ;2MŔd†W¦ăkáB>ÄěŁ/R28ĐĆ«¦ÍŃń»ń>Ł—7BDLdŮ á= ż; €¦ŁÚb¸Bťp4f ŔCs€ç,Q`éńR§Ţ‹ )Ě= ŕ9Y°‚*™†¶…‹c#¶Ŕ"Ë<䉷}­ů™#EĄŠC"’8î>bF=lÔŤČ‹ËÖ$ď–;N]Ř~ăĤ ž±«BX@|`ůĘUVU/g\鑣(¬R–ú©ş¦f’®YSÜ%ń2 żŘ&şx7 Ľŕ{MĎŤŚ!™`:SrlĦé$¦*´–ămĆŞ gLŤ¦ĂČŰfýŢ©)ڇ¸†S]ź=Vă§?ař6Őˇ°Ť©Î;Î…@ˇĽĂéđO;ŽÖ ď̢Ńѡ7ś‘O‘ N˘;äUˇ˝‡śm™tŠÝĂ€)4ë♬ڎ!ð|ĆöÓŰŃěC3z,dof†â!ˇ™z|7{ç|.ĺ­›v[ä­IÎh ÷+žůĽÉçŰ ]ćŰéT„˛@#ĆĽM€"5† hŁßa–ĂŕKťS`{ȡ<(x)ë OŽ‘PV’™0´c}Ëçžp<ťćźŠ3zű+ yż^scLÎB‡î0:b`„‰Á·é™č•ĄÚˇoä˛$îeŚD] Ş#B—‡»}pßl˛*f“`¶ÜTbČ~Î:Žniô'Ů$«3tŕ—WN6Ńî éî(ŕDvp®ž9r”,Ú5˝Uäčµ!7š á…_Ë,Dšfć” ďĐZďŰ ZOš3±włĆWˇE(=GĘ ;eŤŮĚžĚ÷ńQ#*y¬šÉ›ŞF G&Ă1F0"Ť*J5€t/¤mAĘŕ°ĽĽe8śVÍn,*äĽěöL‘B®ĂjŻŇeWqÍOxř˝ŰcŚÜsgČűĘl´>LTqÄ•Ýôöô˛)W•ĚJISŘ’R˘ÇŞ™žWMĎÇfÚ7wůî—óŃrSpqT›EŚŐPŞŤjĺ'*Ń ă§a’Hyu¦†šŔ|ś.–:¶˙rlIÜHSąĽŃźä}˙…śV0=šf ÉĚÓüžË*m‰!`ňŇÄÉż+ȶ3‚ëfĆĐőţ„ĂŃ˝›ŔŹăH=k€0ĺg±¤Á´q?+ L&5#Ă–ÜK ř f©ĽkłtIM ÇĎbŠ…¸k.5Ó7/˝†ĆI&šE> I}ăknr˝l řE>- Ő”Ül\-€ć´lŃ µŤrTćé7ŔűśPJâdĆ~¬ôčćK ćy!8Ę0V NĂ*vcĄŹĘa2KČäŕ_ąŇ5OąMźËoxžĺX““<ëÔśTqu»é–güľěf F‡T #•zh†¬­Ë”8ł7V¬Ŕ9LĐ’ŁXĂB|+çśQľ1jęŚzέmśqrbW»ćÇŹ#k=§ 2ËňĆMˇ9?ŽeÖ–ÖˇDĆŞkÝHáGls4+çR•ĺ„¶ëÉL ֹƿüH>}ůň¦8u&ČĽçôo7GPŮsßńxN__Ć‚ßvşâúćógbűéöă'hÜóđ¤ęÜćŻEÍ,#¶ßú°ŇrŹ$¶—JhDűÎg m•ŐîĹ˝tĄo35##fdĚAYʵĘmŤLţ y±°p˛)Nű.ĹéŁ-Ŕ÷čcĐ~*Z÷ň<ýŔ€Ůăú}ä$*„‹<ýĺ9}^ÍHďLiú ʦÖˇbţ>tS±ŃĹ‘îňŃ`Gq§ä´śĺń˙ńEŚ#ö”ĘaÍV’'Č—ÝäBĹAĆWJSŤOüŁď¦îC§ŇÚ7q˘ć>› í‡i`pîűĹď‹h~ąĐH“pń ťŔW)(c{ˇBíG*Tn¤ş¸żřĎĚ·`Ą­źF‰żżÚ~+Ť#úü ®źhĂń?Ta:ML„YAY†$d”LDĎÚľßýóęę™PďŮç»öHšĐE}ŚÉWm!%Ţv…+ž®šˇPąŰ\íÚMµé®Ü·#Ľ J‰7W+t´ô*Ż;ÁŇéŃ—r˘ŘW6M§Xúóç&Fßčż?â8tVÍöęžż±ěŞâ#ťżOôű–K3łWľŤ=µŇ}mTzţÓ}¤|­sâË˝#sT(Ź=ů…~˛—cř*€ń–endstream endobj 297 0 obj << /Type /Page /Contents 298 0 R /Resources 296 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 300 0 R 301 0 R 302 0 R 306 0 R 307 0 R ] >> endobj 300 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [417.6558 308.6947 495.9258 320.3842] /Subtype/Link/A<> >> endobj 301 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [112.3897 295.1455 136.2005 308.3544] /Subtype/Link/A<> >> endobj 302 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [134.2079 295.1455 140.9328 308.3544] /Subtype /Link /A << /S /GoTo /D (Hfootnote.3) >> >> endobj 306 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [252.7696 234.969 334.7133 248.1779] /Subtype/Link/A<> >> endobj 307 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [332.7208 234.969 339.4456 248.1779] /Subtype /Link /A << /S /GoTo /D (Hfootnote.4) >> >> endobj 299 0 obj << /D [297 0 R /XYZ 113.386 764.2205 null] >> endobj 6 0 obj << /D [297 0 R /XYZ 113.386 727.37 null] >> endobj 308 0 obj << /D [297 0 R /XYZ 129.9737 125.6658 null] >> endobj 309 0 obj << /D [297 0 R /XYZ 129.9737 114.7069 null] >> endobj 296 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F23 305 0 R /F24 214 0 R /F36 207 0 R >> /ProcSet [ /PDF /Text ] >> endobj 312 0 obj << /Length 1955 /Filter /FlateDecode >> stream xÚÍËnă6đžŻđĄ€ T,ߢzë6Ů"E‘>b ‡¶ŮVbˇ¶•HJłŮŻď<(YÎĘńŘC r†óćpFj&áOÍ””ÂXog™·Bkéf«Ý…śÝň‡ ‰Ň „•:źY!˝ H2{śI‘y"ŘĹŤo®wzvY_üz1űőŔP‘[ăfićĐÁ$}·¸řć˝  “Če®f‹»Y®E0RvąPĆełĹúŹDĎSP[&ż]ÝţňóÍíŐ<5Ć$—×ďa?yőŰŐ ßĎUr…Ŕ-ăßázń;m!…1–ö®o.y‘ #4Ó~Ç{&ąa*‰4FH+9˙kńăĹŐb0Č‚‡Bţ¶#M:&"“5 -FAŁÉ‡(/¬Rj°YˇÍeűŞČ¤Ţ·ĺaçžO\&ȤŰŔąŞĹ…JZRpŐUő[2˛A»Töë ě­#vŤlĐĢách,đ#˛(bIÇ ×ÍuÇŔż’=Ç2Ů1”°Â´šOČoÍ›ŰH2Ď$,]%ÁIF8›k2ůaĐŞŤşé<éD–ĘŘ«Śábűň1¨DĚSkňä÷y°d5‘:ŮńNµgV·˝¬Ţ›°§…ńŽ2oKňĎJ3đ\ű šĐ<Ŕ ŘÜßOY:„ÍyČO€)EŃÇ ć'#ڮ誶«V-Żďę‹qÉ8.5n¸čٶ‹«¦Xq*€Cś’Ébs6Qb öÖavÔqO ĂŔŕ†!ž=Ú7­ŠŔ·o0 vMŃ•÷uS ^cTL ‚i˙¬¶é[®ąćPáwW7˝ŚžMG”[Á· 놹sT7@G őŮIĂCM% a˝{(°F-™çáÝńo3.*¨Ş÷MŠÜpÓĂ@Ńń‘ǧ˛©€vâş"Ú o˘łľŻw|kńfT,¬;s ±öŢĆ"<ş^čĂ>fXÓŻń@_¬G7čîĐě†1oˇ÷Á Ě«Ž”JśId‰ScK´9:'TŘŻ}ĽçŽJ-ýÁť|ŔU±ú»ě0;s’ŻbqžvÓ8§Öia^W1‹-kř'DŇP80˘Ö ëś—>ąO<ŤůWSyşOWŰąÖËŞł#?©ČŃą - yä¨3!łIŽË´­‹®Ű3ëuóN›DI• şÁY­Nčö4çZ(ż‹.&{o0F˛ç›[`\@m«ÚľbŞ˘ńfÖ\©|îúbäʬ7mrď{Ţ >wMşŻéYęë«’úëŁmHĚą­Ó¨7mUďŹŮ!Ö2OÔ9ýó` iúFŢEGěđU•ýX›é2ş/¬§›7•|‹U%Ë]ă@ć •] 7xZŹ›§Š>%Ńđ“´B­ţ&Ë»šn  -v±0Xş1Ł=W…b[},°}Bý”– ÜĽů˘J íBÁmĘ3*ę ŕ&*ŮUĽ>EĎĦ)ŁCµş\yőců0eA5těÜÁÇ~«\¨‘hm­WžôHťČ3+ńíŐŔ’´yŹŤ/ľéš’‹rB˛áę#^z­těp4\ŞˇK;ÎŞxn·ĚC.ĚÍły!šGF´ŚŔĘÁšpDP„›âX^Ń1Ă·ŠGFlč1d'Ŕď^U—É~$MÚMM-Őűck Š@Ů÷¬?š @čó¦ěĎöňiqv¦b˛ŠK:@ăňËŹü 1űŞ}Ą×áŘ~rN*F˘pDÚđýG>:řW7Q7tä:|–ŇČdÔŕ\b“˛YŤĆťâ>")@ę i rR•¨&Ăs‚~@ú%%č›Ef?Ë陏X2Ín̆ŞńĚčĽIľăć™Ü3ŐÓź‹ž,>™‰‹Đ0Á<]±1^ŚżŻřEiĎÍPÝ­0泦}•|ĹĂôRÄľPu›ŃužM łĂ­ôúqĎ•9YĺŘOcőD°Lüý¤8â©ă”F˛Ńă‘î'XDVűŐ˝´.ăůîńüČ„łâOšC)Č\,.Y”„Ŕč©•’ĚĐĎUSRň.–É<Ćš>k0Ń›áÎbś€nÔňÁj:M]ĽžŮÂ\Í÷ IÖS9XtŻžÇe;śYÇé6PtĹr[ľ=Ű8ë/6Ó×·ź^ütyŔű×ü:Çëww4†C7 é= é÷üacü]uřę•Đ:É«Q:˘šř S™°ĆˇW܉Oą˙‰Wtendstream endobj 311 0 obj << /Type /Page /Contents 312 0 R /Resources 310 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 314 0 R 315 0 R 316 0 R 317 0 R 321 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R ] >> endobj 314 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [313.5309 652.4149 329.4629 664.1044] /Subtype /Link /A << /S /GoTo /D (subsection.2.1) >> >> endobj 315 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [389.9546 652.4149 405.8866 664.1044] /Subtype /Link /A << /S /GoTo /D (subsection.2.2) >> >> endobj 316 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [389.2699 640.9869 405.2018 650.5552] /Subtype /Link /A << /S /GoTo /D (subsection.2.3) >> >> endobj 317 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [466.9543 640.9869 482.8863 650.5552] /Subtype /Link /A << /S /GoTo /D (subsection.2.4) >> >> endobj 321 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.7189 524.9358 212.1357 540.4775] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 322 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [176.8401 511.3866 201.2569 526.9283] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 323 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [166.5674 497.8375 190.9842 513.3792] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 324 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [172.8704 484.2883 197.2872 499.83] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 325 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.3553 470.7391 209.7721 486.2808] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 326 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.0826 457.1899 226.4994 472.7316] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 327 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.234 443.6407 191.6508 459.1824] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 328 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.2644 430.0915 224.6812 445.6333] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 329 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 416.5424 192.1357 432.0841] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 330 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [166.5067 402.9932 190.9235 418.5349] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.3) >> >> endobj 331 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [184.7189 389.444 209.1357 404.9857] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 332 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [229.3553 375.8948 253.7721 391.4365] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 333 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [205.3856 362.3456 235.2569 377.8874] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 334 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [196.8401 348.7965 221.2569 364.3382] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 335 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [173.2643 335.2473 197.6811 350.789] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 313 0 obj << /D [311 0 R /XYZ 100.3464 764.2205 null] >> endobj 10 0 obj << /D [311 0 R /XYZ 100.3464 727.37 null] >> endobj 14 0 obj << /D [311 0 R /XYZ 100.3464 598.8065 null] >> endobj 18 0 obj << /D [311 0 R /XYZ 100.3464 145.9313 null] >> endobj 310 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 338 0 obj << /Length 2011 /Filter /FlateDecode >> stream xÚµÉnŰFôžŻĐĄŔ¨ŘY8$'·ÄK‘Ü"6ĐC’MŇ2ITHŞŽűő}Ë EZ”- ofŢĽ}©…„?µPĘD&KiGZK»(¶oäb gżľQgVc¬÷wo~ąVŮBÉČI§w e]ät–µ,Ň™5‹»ň“ĐË•’RŠŹW·ü~s{µ\cÄĺ‡kŘ×WŻn¸X*q…Ŕ-źżÇőÝź´…ĆÄ´÷áć’.2‘fÜwĽgÄ PÂăHF°’Ë/wż˝ąş4Š] ‚:űşÚÖ©ŢVMô6Id¤T‹TĄQ–Ů„ô.ëĎR™Ş]Z%Ş]A/3i"ö¸Ę‹ŻUŹwđĎŮLü˛ň-¬kÇ\$8ÂD6všÉŻ€ľűş˙ÍR§â ˇŇköËl |2QVlŚĎŇJŔĐQ) ¨*5Zh#,]"tĹńOČý%»űŐ=\ÎËoČő-ĎÄŹOr䏪§%°ő8ä—µ‰RĎYÚL •©ÔsVYäÔ,çÝŞŘ´%jy_÷GzH 6•§—¨4*v6Đł‘M^ĐS^“®Éű~3%e=ťT)+”Ň2ĐQQbĎČ…¦ŘłŤŃýČĐheÔ8P•&Î D%ÄË,ŃrŢĚ6_w§Ž”ž±6YŚÖ´Ŕ ‹2u†ţ#Z’ÜÔŁĂň-‚ŐŘńŕ$›9#¬Qž*TźˇJQŘ×ĎcB°"zZ™TR¸Ě“R‘ÔgĽĂVŁ>aTç¨Ů­‚)Č&§\Śg»T‰4°‘çě@AU”hě—A5řLk'3PJ’3ş˙EáŢvuł›š1”¬wé’6gRڬ¸Ţ*RwȧoŞöyJ]ň1”qÔXfóÔ3ZUąëä‘T| }Ť)y¤Łft·Ě ¸:÷ůłCĺŃe[ôÖ=žqę7ä+ŞáÄŤ¨`AáGjľĹ‚d˛T¸DQÄ`FËů<ą9l‘ń9~" ,Ęô•ÜÓűäé}¬Ë|ës6ü~L|ŃnóMýwŢkßRqĐÂA*»˙T$Âý·–Ěx/-€Ź^Än’Ş!Ö}žđ°ü¶ ĆLŔ–V“̉ű~ÜĎiPˇĘť§bEޤH D'RrWÓĐ\Uä¬ŐŘŐVZCᏡÝBU2ăŢ yÁSĂőŇ€Îy Y Pć;Ł6PRG—?€ib‰¦ÁěîpÖ#eŠž’OC“ÂĂj¤=š¸ĄZŽX9#ĚZ§e´ ~K4>5o"-żňÍOď©O@ż…­ň)§&›•m×qkÓĚ›új9q·8çd‰ tČX\Ą4yĎGä "±küÖŕ\D®·¬2Iźs„„ăę;Fí&'ÓaÉDňŽż%çn˝Ţ~ ŕcSĽ-W ht÷ČKĎô!ËWsző‡!Ś;¶iŃŕö¦äťA 4X71fî/Ý#ţÚŰż¦CĄ eű´ÇxRMË—Qí¶éy„*š ďžÄx÷3(çs¸¨ö=#Rěĺâzf¨lf›Qă[ЦĘKźÖ kŠĽľjýLˇyŹžÚÔ$ľo ű–ĆŁMEľě˘c˘M’2L»xČ0ź|ša?\R˛‡b2%)N”řáX !1'ێחżó—‡3đîŽÁŕC˛Üiv†Ż%p6ŠkŠŤ,-WK¶/U>ÇŔ÷ŘĚÝ €ós)S‚c¶´Ó‰«чGO5°#¶ Â%€Îëq˘Ä{˙Dq6ű: ÜŔL°P(‚í}ůoBß cEčFŞĚz[%‘3 <]t[bńn—ož;¤ß˝ťsŤWĹ ŮPFăT|ĽF^Č Ä~¨ů‚GGs Śň#z÷¨ř—§C†»ý±·8ÄUÉ7(÷xĹcTQR(!Aş‘AW©Š´…&0±kőťű&Ő1¬Bq*™’ďR(/5اZž¸QúÂć`\ *L*Ă7ެÇGo3:eč `’Ţ—őš¶ŐĘ®03Ń’oHć°¦ČDąj 10jsŘ”ĽŮVUË»ćjGúEČ?3BÓž"žsF|Cľ†'·:—˛FOr°K_4Ś˘Žśg5Ĺ Ţ!ŻF–a™a»FÔ’][‡SžĚ´„ĽšóC”›–uî†0¸Řd”u.W¨äÍ-ßl™CCŻŢââzÍ;÷ŁĎořš 09XĘÍ÷Ă \4Ű}˝©|ođŹmˇulýcź2jÜ«qö>PIŰ­G÷çęÜő¸çqôuÁ»őżh+z¦­,µ'Ý%ń?Üśé0>ş’lrµŢńÝÖż ~¨ÉÄ–Ř«8Ő÷D\řsŽQBO+0¶ăpŃWjýk­®ü‘ďpëuN¤LŽĆ@ ÚG5l&J..Cßč§ŁĂđ28 űµŠˇB­'M×yÇ9×öľh¬4źęQ™]RE+ŻŠöÓö!D«ß<ŽŻpś7Ô™!äőPOÎ\+ŰzőJźčá•÷—ϝȱ‹Ń;Zâ‹GŠäD’îqMi?HČ…˙Eg †Wýă Ç@†«ÂľŢĐ`ÜŤäTţaÓ†!˘ąy?üjz2’L'‹“`ě^ĚMx1?Píóď%Ź1} ę?»†ß‘°żÎĚëż5Źć~j~A µLÎţĚ;ĂđČhHendstream endobj 337 0 obj << /Type /Page /Contents 338 0 R /Resources 336 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R 348 0 R 349 0 R 350 0 R 351 0 R 352 0 R 354 0 R 356 0 R ] >> endobj 340 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [232.8797 699.2754 262.751 714.8171] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 341 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [250.8797 685.7262 275.2965 701.2679] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 342 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.8796 672.177 214.2964 687.7187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 343 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [179.6069 658.6278 204.0237 674.1695] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 344 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.9099 645.0786 210.3267 660.6203] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 345 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [218.4251 631.5295 248.2965 647.0712] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 346 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [198.3948 617.9803 222.8116 633.522] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 347 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.7584 604.4311 205.1752 619.9728] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 348 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [208.4554 590.8819 238.3267 606.4236] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.13) >> >> endobj 349 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.2736 577.3327 213.6904 592.8744] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 350 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [186.3039 563.7835 210.7207 579.3253] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 351 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [224.4857 550.2344 254.3571 565.7761] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.14) >> >> endobj 352 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.6372 536.6852 218.5692 552.2269] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 354 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [246.1056 285.353 253.5527 294.3758] /Subtype /Link /A << /S /GoTo /D (cite.rfc4035) >> >> endobj 356 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [234.7286 129.8501 242.1757 138.8729] /Subtype /Link /A << /S /GoTo /D (cite.rfc4035) >> >> endobj 339 0 obj << /D [337 0 R /XYZ 113.386 764.2205 null] >> endobj 22 0 obj << /D [337 0 R /XYZ 113.386 462.0483 null] >> endobj 26 0 obj << /D [337 0 R /XYZ 113.386 364.0978 null] >> endobj 353 0 obj << /D [337 0 R /XYZ 113.386 301.2075 null] >> endobj 30 0 obj << /D [337 0 R /XYZ 113.386 208.5949 null] >> endobj 355 0 obj << /D [337 0 R /XYZ 113.386 145.7045 null] >> endobj 336 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /ProcSet [ /PDF /Text ] >> endobj 360 0 obj << /Length 2152 /Filter /FlateDecode >> stream xÚÍksÚHň»E•Ąť‡žÎÖV#'ě%°ärąŰű Ő‚„%‘Ť˙ýőc$d‡p®«ýpE3ÝÓ3ýîé‘řÉÂŃ®ďßu”Ţ`ąż ,ľ»’†ČĄă  \Gřn$Çpźş ŕ»MńÓdŻăňęţjp:P†Näjo`~č¨ĐÓHúvqőÓť A&'‘,ÖH9ˇ¤‹©˝`°XýËRCÄVĎ›MçńĐÖZ[ăÉŕ­»8‰§8ąJ+ĆÉś×ß"ĽřL(¤ĐÚ%Üd:f r´ŁvÄ8mMůií 1ü÷â׫xŃ)ä‚…Âč˛ ŤÝ'"••č«|ňôWJÉ:pŔX<@`=ŘË€i] Ě÷-‡€”ţ0šĎQlł˛.‡ZXŐ>«*¦É ^x‹DŘ@JŽQ%0ż×—E l%/r}ânşV Ǹ"˛n‰°ąX…ÖÓţĘ#.†ÖŹL 6B 4Ď›-ě¤iĹč;Ü=K>Ć€O’kf±®*÷ °¸č„Jł/‰ď>ˇńřšë 6€*(»ÔŽçFŠdźÎÇ@ć°–/,î;‘ö=ŇUF‚lT¤»§:‡=őÍ9Óx®Ł•t RŹóß…ÔYE*°‰ Ž4śGYŤQ[Z‡*kŇ&/iYYĺšÉZŰčȵ˛ËmŤ[Ś‚)S±ůiăסçY)ĆĂŃl㣅€¤Ĺ¤ŁĽ zn,µ.9Ŕ d#`…Ţő!ŇŘË)E= QWÜ™~c4Ä9¦¨ëĎ{®Ł´áyw,Ú¬l¶™Ů *Ď]n¸“5wíLý»đĐ7ŰÔ“×<esÎ÷5«őeÍV°[rv? )n9Ó)ËÚP—;ŢRŐśý)ú׏(nŠ.'7“xM¶âĹ5ŞRńüWŔSĂ® M¦gc3-t¤/˘~ş»&Ý »YćĹă1«ž8‡mNá:š?ä O8ż«GŽöéׂÎÓ¦$ žR®yŻ©S¤TŐŘ1tŠšŃĎ’—Ćçk›Ąń‰Ž f#…WÖ°Ős 3ÂłJP„^“Çá˙Ç÷ÇS]‚2ĹaŔfiKš¤(#ÔĂĐVTŃŘ•Ĺ&3&„Č4EÖ“xĄřP‰vŮdM›Ě:đXQRp™1äź1žÎy˛ÍŇ|!}k<۵ęmY58Ő çŠ'm1;Öz¤ 1ÔX‘Î)ś÷¦d!bK— ĎSöé·|?„$Cí·ËŠ p NXspTžÇ‹ťĆµĂą»ŘbP©"™‰á3i‹iľ†^Çâj%¦Va8ź¤IęĂÎ ¬®__xÖ ç»'&, SbCJň‚9ś‘挪%éGĹSKĚ–h?†ĘÜk$‡Ďa $iQ˙9¤s 6śQđűúsmcŰfBŢ–W,kľˇ„PSXću^íővĘ>ŻyąG…Űţ@ľYˇ M†L%°úŕU”˙“ŇuC ?_“Ŕ)·©I"»éByĂlĂ´˙Â@ Çeă=ţ ˄ɲ×w+Ć@BŘügő*á˘Ę—é]« Ł–ieś„Ў̲i; D±Ň)X+UŕrÖ!˘'Ú/QCAk].p#íňŚď>ŠkĎš“Uş Ţ©äKâĚ‘đ—Ő6=ő‚₯K)Ç´ö_äăŽTNJJgľÉÉ5u{ťk ĽÓ}guŘb.¶Ŕę˛ImŽ‚Ę+ÔŃSĐ,´ćÚő­6ÄjJŢ}6ŻĎ)Üő;¨IgV„!Ę#ö5+†Ň¦Éöł”ň°¸ý '¦G wćBî;„ýŢč1O•@Q3l´ěÚźtĹR…˝×óbÓcî_¨]ČĽ1éÜvÇ:ălŽÇ”îÂd{ÉŘşł“é$^D/˘^VN» y?)Ú’‚ň›jŇ]Üm™ˇ`)Í5N˛´&©ňĺ÷÷pמĄd•˛ă‘šşÔv|gďéS"sËö[Ż{áÔ%ř{7´=Ą°ßÁáĺ“…5ÁSښϰ˝1š|łřŔ€‘‰Ňcłĺ6şM•Ńu¶ěat Ž‚0ťôĽšáć^űŽďűásĂcŻŇ–Ĭ>×zŘÝľ~Sµčj˙©€Ł ăş?»—“1zZ˙AAĽáő~÷É˝„&ĂŔ#Óź¶ËíťRîÓĽ%ióüî9…6F1Pľv·ŢŞ˝yú/âČ…Ç®ŚŔ6đf†{ľ˙$ţîiÜŰ}jz{j:‘ĎáţÓ¸#ăž zš›. Áľ^Č]ô›7č/ϲůĺ}<ÇÉĎ?ŰŚ)Ër•Ý0p˙)Nľ\óĽęá§ł8If‰YÉW-.±ZďŇMm«ŹozlĚ’4‡Ž¦óĎqŇÜ"?-ŢĎ’ÉâËKüx> endobj 361 0 obj << /D [359 0 R /XYZ 100.3464 764.2205 null] >> endobj 34 0 obj << /D [359 0 R /XYZ 100.3464 727.37 null] >> endobj 362 0 obj << /D [359 0 R /XYZ 100.3464 675.6257 null] >> endobj 38 0 obj << /D [359 0 R /XYZ 100.3464 617.6392 null] >> endobj 363 0 obj << /D [359 0 R /XYZ 100.3464 577.4598 null] >> endobj 42 0 obj << /D [359 0 R /XYZ 100.3464 429.4774 null] >> endobj 358 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F52 366 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 370 0 obj << /Length 1457 /Filter /FlateDecode >> stream xÚíXYoŰF~÷ŻĐ#„›=x:iƦ ŐHJť´é-Ň™tHĘG}gv–¬$ËŞ‹6 zŕĚěěě7;ÇîJ 8üÄ@ĹTŕ |ĎaRrw0ż:⌽9FÇî”ěM­×łŁçg"ÎBŠÁěr Ü…2đÁZŔdŕŞÁ,űĹ’C[pέI<ýqśL㡭”˛NGg ·ÎâIś q2VŚÄ”Ć_#?;×"ÔPĘѲQrJLČ“¤‘LY –ŃQŚ3ŕřđ×Ů»ŁxÖ{ä„ ÝĂn÷Z{üv·üVś))Áśđ#„Đ~Ges;”•#¨š^šşş"tÉ&Ňă]Ś‚ű,TÂx!8ę†[†¨Ó¶7Ő5VWzžŁˇšPöZôĹ‹ˇíJײ_˝zG§ńäĺK›$ŐőĽĘňcb>~Š'_ž]oȓϧăŃ(1CEfäŇ㡋nD·Ë ­ő.Wé˘1Ęßjú¦©Y Łď‹ŤµŤŞ0 EÉô<ž!foÇ“Ńěňééh6'ŃűnÂ!d°Üµ‰›Ć'ČôĄŞŘEZłˇ-=`G˛ÂĺÖtuÓ¤`ˇđ­iäĂţeöęwîý92€˘<ßµĎárĐőw`Ň”ŐUŐÚM^ßäuĂĘĽed»lÚUĆ@X4Ţ´08‡Ô–˙ĘÝ˝{(9÷¸/.L\©°#<îôB l‰n÷Ń{úV}\çő=‘mqŐ%«g–˝jňůˇxNăÉO}r éC'áLšqţ6NŚţyn˛7Z/L-(cI»ęX¸U‡L~ľ1hF?c'„‡Ę»é Ú*Î~~&ůV;ň xж”b"pL3JW÷MŃkŽiÎv sč`Đ>¸Ö~­»¬”ŇšcóŞJwYŐW •ŐV4X”CZ­ip‚ܱ‘ΰ˥ŘëZRĚ g§e†ŠzĆmÓ+—Ť–Üi¤š*µł˘ˇŐ±‰ŢčN ńÄݲ}ÍËaÓsťPjĐ·ËbŽZKHq.­eÚ‘¶řÔKZé+ěÁŔ•8ˇ%˝ę’ľsô.°˛śŘ,żé»řŞş§–•!°&îµz«SZ /´˝\[(Q$¬ëőZÍ3EŁlŮä §ź°>-6”)H-Š›Ľ!25:éş]v8 ‡Y!gů ś‡éCü 1ĺť­7ByĚóĽ`{;QZh|{Úî§HÎ<8© Ŕ¬ëYYń• Őç­‰Ś lÇt}‹,kuŔeŞ3±¨ÖC:ĐaŞ‚“÷ŃĎó˘ä IľA˙)pK¨c eť euň»˘i \uA b!PZ¦ZÜ÷­ vrOFBłPYHHJ$ęüzuOä-ZE‡0¨E4pQ´$Żň´Î3ęŔj=PÔŃÉŤŐhAĐŔVçëXÔČc!”w›.ávn¶ů‡‰í梋NeÝ”ERŁF ÖG€kű}3sByŞONőG”ŻuŮQ˘:hř%éuł'HT% ¤čWF´vcľZg; Ó}nMÇ0•&îHź$ŁÄ´ĽVuWĽ¦AAýţV•ů3"ugŘÔÓĺ…ßµŽhUëíHۢkT8 1ßí¦u•ţ|@¬\×ëÇuçš»ü:Şpzŕ:OĽŽnŞ?~íµţ‰ëč8žLĆ“ÝۨPJO˝ŤţÝ['˙—nťełJ/VŻÇĚ\tűŃ»ź÷őĹ>řŇe>—ęiOSI ÖϮdzC*Žf'xbvlŞ?ž˝Öw|¬üĄôŘ}¬üW)}şTŹĄË˙ď”ďöNŮŞ—îY8.˙벡´ďO—S'xôŹ= ţ•8endstream endobj 369 0 obj << /Type /Page /Contents 370 0 R /Resources 368 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R >> endobj 371 0 obj << /D [369 0 R /XYZ 113.386 764.2205 null] >> endobj 372 0 obj << /D [369 0 R /XYZ 113.386 497.0765 null] >> endobj 46 0 obj << /D [369 0 R /XYZ 113.386 442.1829 null] >> endobj 368 0 obj << /Font << /F18 200 0 R /F15 235 0 R /F52 366 0 R /F20 186 0 R >> /ProcSet [ /PDF /Text ] >> endobj 375 0 obj << /Length 1968 /Filter /FlateDecode >> stream xÚŐXÝoŰF÷_ˇG .—źNQ@‰äFE#×’Š4w˝š˘mâ(R&©¸ľżţćk)Úa„öŢÂŮ™ŮŮŮůřÍZjâÂ?5Q®ëh?ô'Qč;žç“láNîAřÓ…%;VŽďzÉÄwÜĐŹQeň8qť($…žţcżIo—{o2Ż/n.&7'*v_; cÇ‹ŤŞď·oŻT >9‰›¨Éön’xN¬]Ţ%ŽŇA4ŮîţiySÜv­őbóëőjłÚZkkľĽľuµX/VH|*kĆĺďq˝ýL,ÔĐÚ'Ţr5çEâhÇcÝó´µbĘí¸¬Üéż¶?_,¶ý…|Pśś˘čŘC%şrŕM !$n|J _)EW~÷nj^`Ýóć™É®Řç—LşüŮ·y†ŽÁq6Ć0€Ó†›?\¬dÇç|ÇÄěxĎ„§ů«ôe_J¸®ž3ůió›ĺ?0˛nŕZMöu'Ç(WănČj0Ě*Ü,Ń!d_»Nŕ†!™śUíÓÔ‹­CŢpřď ÖM˝çŘŻ†y¸|ťÄ‡ŕŞdęŔqŁaľI„QµOşgň JĂ[Ű?ţřq1›/Ö?ü`3§>dőΤăć·Ĺú˦›őűüúÓląQŃGIk/>ĺ»2˝oEů±áď»ÁYĆŽž­6źkS†ůŰöăőząýňš?ź/·ËëŐě—ľÎxÇmP[’ľř€‹Ës;޶Lo[§9ÖŽÔÇlőej{!VĎďf§§śDEń‹ť|Ťń“FőÍ ˙Ć–ţň}Ď˙Y re˝˝ňÜŃô='P±'–Ďm]Ö^޵mŕ;ÚS>8‚ÚWÓŘçfM»#ö)ĐžZő~ë=+rž@Ěmťł¬čX’VxJ¸ő›VřÇuÎtiW|%qůĚŰďꆉżĚ6&±Ş0Jv¤/ »•v?á«U‚ˇ]˝O‹Š‘ĺńŘűDAT댅 ®}'Đpq>0%`G"¬[ű6Ý=BI g$°¦ TíŻĄ] …:‰,?/AHĂ- )2Ę:”äLËĽ§˘{`Šl"‘"Hö&C®dŃRŇĄđ0Ü‚ńС†aü2Ća /ś6’k»ßçA…čXÓ>ΩbđW|ĄŔ1Oü "Ě«|_a:đi†¬÷üŽůÝC*TĆńóU-¬[H2©ă9¤ •MľÓˇ¶j±ľ«YS\ę °'ÎôŇ |2„·,ĄĺÁ°™Ý Ĺ˙ž[6vźWy“vy;ĽíH5“o^ڇ\T¬»ú@¦ŘŇ÷}¸ž/Xëčĺ}ÝvP÷#NŻ®·ËOżÂv/ßC7vH„Đ™`ĺzýi±^żaŃ-hAK±ZiĽ¬™Ac x0™Ńpő…éŃ~˙Ä+Âö+Ë1»ľőŰś'÷ŔPŃËX”6Rľ@ďÓ»\Y{N3w­é^¨tŃŁ¤rrʍOč¦|tEŢX>Ĺ”ŃQÜ‹5Ǣ0Gaq•9ŢŚőÉADŹt f!Hy9¸™XĆÄ×ČíX …6Ľ*é­¨~cgfRýgxqn˘îĄ;Šßö) „ü‡ŤA†uěA]PŕŔA€v(„vé(ĐAT±9/°Bä`€ĽFÍäw®„[j!tăâ!EďܤUËĚ'Ôî+s+IÂP)äČMîý OęňÝXáIĎiĘ~ş&ͤf0Pc3€¬ľa‡> endobj 376 0 obj << /D [374 0 R /XYZ 100.3464 764.2205 null] >> endobj 377 0 obj << /D [374 0 R /XYZ 100.3464 463.3904 null] >> endobj 50 0 obj << /D [374 0 R /XYZ 100.3464 414.4339 null] >> endobj 378 0 obj << /D [374 0 R /XYZ 100.3464 269.4894 null] >> endobj 54 0 obj << /D [374 0 R /XYZ 100.3464 179.7608 null] >> endobj 373 0 obj << /Font << /F18 200 0 R /F52 366 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 381 0 obj << /Length 2309 /Filter /FlateDecode >> stream xÚµYKsŰHľçWčHŐZ ß"çfGň®·9%+µ™šŮ-Rk%Ę!©qi~ýâĐ-ʦ]É!I•ŮŤFŁ4ž-äŃäűˇ¦ÉhšDnxńh˝{çŤhíźď|Ĺ™¤IëjőîýµźŽ|ĎÍĽĚ­6#?ÎÜ,H§D-u4G«â'O|Ďóśĺüîóíân>ž„ačĚn® î\Ď—óĆľ3ÇŕNÖŻ0_ý‡AŔĂa7‹™L27tÁ˝Xč,„€ď(Nčz.ÍĽńW˙~7_Y‰˘,"Fłřm±-ÖKąďLnŁD?q#ß÷El7ÂŮ>±Dâ;ŤŢwŐćHŚ%Sg‚OâŐźžVŮ€ó˛îdyq»Âü†V®(%Śf?=§i! i>îsŕŤ&ďúľŞüJ´4MśĽ.d°0jˇńCő×8 ’Mť‚Źg6eŤµN0qjCë­ nhHs^bqh~”é÷Ä` •µîxOCgő­¤–ĄläôF‰ćŤŕcÜvyÓ•D„L¤×8Ę–é©ęľář±$I*G™¬Ax_Ó: =€—&ď*‚ĐręlŔ4oZ3fÉŚĐź`ę9ë˝H 6ö[Á“ŤYOČ4tHš(śkŚ A©÷ŠéNänó‡˛wB^í†eĘI–($¶äó·•‚vG‘ç°Ä©jĺ{¦Äâ‚€IL®1QßJËc÷Ŕ¬)»„«[ˇŞ§-nábË%čÜ.•‘ş}S"ŻtŮ~˘0%ű™ IŇjźAs0ié´ż¬ţĺ Ôj.JŁľý`ÍhI{L'á{r.Hç ˘őކßXA´ZéáDY­Ř#á{÷ťBţéĹ^UO/Ą€G4.ŰĺcîŞĹEĆ­8ř#ě4LĽšZ˝…ž)ApĹ!«úqĘĐ9i‘ |ťŃěöÓĺÍÂŻw7 ŠOAŕ†Ó8fö/ë|{láíoCˇ"ŽÜ0đ#’Řłr“Ă[¶P™ŔŕAy`VÔ‰(ŞQ°÷ ĹţZŮpwT$č“Őt©ű:x?POë{<â€5ěíă8qŚÓµ$ÓĚ*,_Ödę»A<ÍÎďl·Çq,ŢÁľ\±«w°=?ĄÜBwÚ°ŰÑà §ţ¬łÜPz&ŻĆĹ qi XťPŮou{ÇćČś0UŘC!ŤŞßÁ3ŮtbňşS»őťA# ë =7Śâ¤źvM;őäđHĆDűsĐéĺÉ•3$%ĂÖ™¬A »Çmąłé©8ÖůN5Ś9ááVŐ› Jî‹"A$‘ ś/źgPí%śe5żŕ‘íä€I(וײňPv2`n+Ą’Zrą€´ůÖ3ź˝_|].ďY˝ßw=<2ş·łąĐß4űÝP(vxáś}!TRő'}ţ(ŕ §’ťŕÖmţ*ď]ÜiáëC´WHPąBTrbŹšÝu®’ď‘XE xd†µ 2}rżŁ Őčî'»"lďĹ”&b&ŞMcn’†ĎMŤř„kśLŤbßG‚\ý@Ńcm* $Ť}W2¶¦„‰5Ą  §q‹WĘJěc Ý7ź>ÓÁ‘(NÉk™$ ÷˝źJÉćf´±WŁŘPęť_e˘ëh÷MŁäÇidŐ ń¬udN'hß‘Ďʦ2۸Â6®JJ˛ž ź:Ş ŃixSÔ˛Z8 î®)ófŕepeţć:ßץ6ň5‡>uK\7űŢ︨9ŇF&†#&Ř îţ^’2×w*/ŞLFş‡ČG/Żqő{#©0”ŹO_•®<Mćçőě–m© ™^ÖqqZ·›RŁ9ËVý´– {§i—ťďŹNzú‰đŮ®ă/ĘÔ`ŽÉ™č_$§uɦäŕMŚ:eK%ćF8K»ťÉíkśŔ߽ҿý`#Wc/„‹öZCש`kĚÝU\řąZÔi!Ř˝ćĂëÚFÚţü Sťf jčžţe.Iů‡L4óDx ¤ş¦şkćżd“ׇÔÁ—ę´+Cć\•É  Šu^‚qéĹ-Ćţ­âj˝ÍŰS;GN÷Í–/Ú¶˝rî@w)}`kšĆREËt„bőč.Őxě™Jˇł†Íł±5‡ěÚ×˝-×]?„šo×ěZ›t’¨P Ć JęF¬éCbě…˘‚cÓrzŢd2ČúÖY‡˘D¸‹e9Ć"9ȵÚR´0fy°…»¦¤Hâ) ™WVČ­ ŇkQ Ô[oľ<Ĺc흸G‹XÄĘ_1…FÍ»%ĐŠRď2şçŚÜC۲xż¬ěć. śl·20UBĆÔÇČšéüh|I˙dT°­ä2A'âăJ.oŻôÔ?@/ÇkÇąžŘżI„đz[_çr›Ćµ8$&˝÷#„ăŞ^oq™uÂiŞ•önĎjE¬łŤíĚÓ Ô×BěôňľčS.$4é+%—%¶l(­Sýfź˝†ěŹ#X–jĄ·+»jgmŔ'ˇ0Ďě;Ćň~,ą*Ŕ¬ ë}ľŃú±c+ȶĽKŮŘ”ň¨€m…=Rľ6Üú‹ë¤wąęËRë×ŢŰ)]:ĺYt[W0e©vtőŮ[Bń4±´)7(dÉĂůÎ_±O}«¸0mť) Ź˝0jbgĄ††Kí×ç3<5rţřSw&çFP `ť(ťľ¨yG«ĎT51Ü/ç×4űÂŹzD/ňcđé‘ «Mů¸­ú/;{29™/MjŚ•žŻ>ł€ŮB±uN^ś$»?‹ĺîóß8ĚŹ Ĺ€ ßţa§‡4ô»Î3R`ĐýG•˙&Ägäendstream endobj 380 0 obj << /Type /Page /Contents 381 0 R /Resources 379 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R >> endobj 382 0 obj << /D [380 0 R /XYZ 113.386 764.2205 null] >> endobj 58 0 obj << /D [380 0 R /XYZ 113.386 727.37 null] >> endobj 383 0 obj << /D [380 0 R /XYZ 113.386 629.8135 null] >> endobj 62 0 obj << /D [380 0 R /XYZ 113.386 586.5247 null] >> endobj 384 0 obj << /D [380 0 R /XYZ 113.386 531.606 null] >> endobj 66 0 obj << /D [380 0 R /XYZ 113.386 499.1392 null] >> endobj 385 0 obj << /D [380 0 R /XYZ 113.386 441.4932 null] >> endobj 70 0 obj << /D [380 0 R /XYZ 113.386 386.7765 null] >> endobj 386 0 obj << /D [380 0 R /XYZ 113.386 341.1645 null] >> endobj 74 0 obj << /D [380 0 R /XYZ 113.386 270.1714 null] >> endobj 387 0 obj << /D [380 0 R /XYZ 113.386 213.1314 null] >> endobj 78 0 obj << /D [380 0 R /XYZ 113.386 144.2595 null] >> endobj 379 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 390 0 obj << /Length 2183 /Filter /FlateDecode >> stream xÚíY]oă¶}ĎŻđŁ ÄŞD}÷mÓ8mŠnŇu Ü ÜöA±ĺDXYňJňîMýť3CRr¬l÷č[±ŔŠÉáđĚ™ˇăĎ<úçĎ|Ďs0gIşJyŃlłżđfO4řă…Ż•©ď†žĘfˇëĹa •٧™ç&1+ŘÉ?ŮIZđÝí^Í®›‹łĂ‚~ęfaÍIśş*Ť¨^­/ľ»ńS˛ÉÍĽĚź­włLąiŕůd]ćúA”ĚÖŰ˙8jľ ł=gµ|řőţîa9_Aŕ\ßŢÜąY®–whü0÷ť%2~…ţú_,‚F„,»˝»–Nć®Ýw" ś;YŔw´Nŕz.őĽůďëź/–k{ <”f_w˘ÖYŚ•řČĘŮ÷ň9;ńc7ô}źĎü®Î«—®¤˝»ď±99*ĎŠB7P~H;A{ý\˝aâ´E‡4ŐçąJť˘éťc×Kݬ»Ă|ˇ§€ęFK{łÄ§cŃľHóöÚE#vÖĐ|&cX ·ÔiôňŢ’—ÜęEm=?ă[˛‰N@Žđ]%ä?pŁ0SlzwüÍóc^˘,jL‚A‰GfîxŹ}Ţ—MM†DQě<ő–¤eý%źtÉ®BÚĎEľĺS{źd`ŮNDwćZ©Ý‡ ËŚÇ»=:yUÉ1IIěČiGnôĎěF\ źÇ;=Čľi MkVčĘjt&‚Wßhě6¤yßç›99î#/Ks\ąíSŚĐVŠ"Čó 7*ҧŔp¶‹ç¦ëë|ŹýăŘYŕ“8W‚tjĺŰm§[˘qgâ$d6Í<ŕăŇ]ÉřŽ$;€ĚâŘň±$oLŔŃă÷ qxe ¨7Őqk}"ňĽĆWÁ4¨ŕŠóJ|˛ZÉ·¬µÓ đ0íČ˝¦-{¸őE4:ŤdZDÍNO5đßĘŐË÷ŻC: )Zýl+ĺIŽcú,¶Ťňb¬ÍÁ©ÝTL ‹Ř6lkŐŕëPxŔV1 ~řIľVţľRť€‘FÄĬ*#Šő“żĚä"ăybQěG÷u4ř,*ˇŽ Ă,ŐÔąmRŃ“j\Uons@Łź<Î@€O5ŕëŽößGécę!ÝŞ“(ű¨űćE'ĂzŠtĘ=óA±/ę^´o˙}łzčĘsc¤âşy€ú‚TqĚnÁF4ş3LI*Ľ*·t„Pk` °rę4đÇ+ ~) ďÔň9rIđyN,WĺVKëî čŁĐüćE‰o”úUŢËuő˘˙pʰyGjľ(äĽŰźŮ‹}Ű@şF21¦łçýúöýŻżH‡rD©‚Z’žú ¨eűBЛ٩;€XĂv$BjýroY@ n)ُ"W7µăĐn‹×ŰÖzÁ»{ęqZĽ}O-jŹÂJo§;J†ĺSýu’WcĚg–äwMďq%ÜjMş&Ě.ĚWli0Ëkô—&J68÷q[č„0šŢŽ &QL©e˝ä‚űŐűĺŠW:Źw$.Úî«Q’ŤÓAaM_ęÄ›6äXj|‚XL˘^7dOęŮH˘ö ä÷bďŕ –Ě^4Äfб5@;¤W˘ět(˛čĽ ™Ž»,´W/Sb“GŚM•ëP…xę$/ńÖ!EĚ SF+ÚR­qâö_F)ńz ÉČNůî¨Ë*–s*ĄďňzÎUwŐŰ­ž(wʦ6yâ0Ú /CÚ69ôą0… ű37\łC!ĺ߬+˙Č+­Ľ„ĺwVKĚy#Żźrç \ô-ĽńO­üO­ümµ˛ďY}Ě·¸7,đBţŚň'ZLĹřSĹá9b ĺ‹0–v4 µH€tĆŞPUHÜač5‡Bö­šŽ9ÔO¦yŔ7¨ô“ł`ba'qŞkd?–0¤ď«şXŻŐČŕ{ň¶+t`ź-ŻqÁä– Ŕ!˝óL ©dâż«(xŕGPfLSaä± ěŻ#ÄŢžą ÓP@2—HĚĂa’:ŹĐíE…ýچ©9#ó˙„_ĎĹÉ!?"2Çňîtho[•ämŮ™‡Ś0ÔŽ7'Gr­—·o ťŔ¸JłëPs‡zµNëžň­ę´Ň #.-5ÓAާLß…TVĘX•? ?V˙O0ú6ŹőÇšëš/ě?ó›*ďpyY†‹Ăç,"#šk_–Ŕ?úLhŽ#‘uő—BnŽ­8ęLyHî?’¸ŁPąq§§Wtb¨”F0ŐpÜk`.ě"ă0¦ěr2Pi<ޤrô>Ć h!˝«4’P„ ŔA-cÚU*•j jŚÎW‹ż`SşZE•Ťř\Ą©ç9äS«H@(AáPąy‚ä'ßďoÔfüŚú0ďÉTŢkxK6ýßřŢ` ;˝=ŐŰÄm;ŞHI|Â:ZˇˇłÖŽ=˛•^ţˇ,H¦8Ép5í7=†OľúZ5~ínäŃ»-¦ßÄô˛ág ŹÜC˛¶ošł^m%g›ýů“`Ę„¶îEÖd¸ä˝Î‘¨ …Źó­¦ <úŔN214ľĎ«1ŮëY«Őąf®Ó3@Nă„Ĺ4»Đ™;äł‘h#hÜ—SP7ÔÝ&*Č©sýž4ШĽZVúąr)B“[Đ–›ˇĆS)U©ž•Śäś lŐ•ˇ o<âŽč'Qµ‘G+4RÇÚú3u¶ĂŕŰżŕÝ @2ýÄ'Á/(wăÔ`)Ő+NJEš`«ÎÉUW[čěř{­e,ĄöqI˘kKÚH?Äçv y°žnőa5uDďyuÄďűGBëIŞÓż’ Âů7ĘKó‡……ý+Bŕü!Kť˙řŐ5†R쯑#"Ô®p_˙ 9übHˇŻŇ`ň/ Vi1ŇšřkJP;ő2»|@ÉwúŹ;ţđSŕendstream endobj 389 0 obj << /Type /Page /Contents 390 0 R /Resources 388 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R /Annots [ 397 0 R 399 0 R ] >> endobj 397 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [296.6954 296.0552 321.1122 308.9568] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 399 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [292.9112 184.9533 317.328 197.8549] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 391 0 obj << /D [389 0 R /XYZ 100.3464 764.2205 null] >> endobj 392 0 obj << /D [389 0 R /XYZ 100.3464 727.37 null] >> endobj 82 0 obj << /D [389 0 R /XYZ 100.3464 673.9767 null] >> endobj 393 0 obj << /D [389 0 R /XYZ 100.3464 606.0009 null] >> endobj 86 0 obj << /D [389 0 R /XYZ 100.3464 574.9795 null] >> endobj 394 0 obj << /D [389 0 R /XYZ 100.3464 519.8763 null] >> endobj 90 0 obj << /D [389 0 R /XYZ 100.3464 477.4268 null] >> endobj 395 0 obj << /D [389 0 R /XYZ 100.3464 408.7744 null] >> endobj 94 0 obj << /D [389 0 R /XYZ 100.3464 354.8969 null] >> endobj 396 0 obj << /D [389 0 R /XYZ 100.3464 311.2217 null] >> endobj 98 0 obj << /D [389 0 R /XYZ 100.3464 268.7723 null] >> endobj 398 0 obj << /D [389 0 R /XYZ 100.3464 202.2411 null] >> endobj 102 0 obj << /D [389 0 R /XYZ 100.3464 170.6135 null] >> endobj 388 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F52 366 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 402 0 obj << /Length 2155 /Filter /FlateDecode >> stream xÚµXKŹŰ6ľçWř(±*Q”lő–Íz‹-Z§őşí!íAkѶPYr$9Îö×w^¤äD»}‹Źáp8óÍ 'üÂIF~´H&óDűJńd{|Lö0÷Ý«Phf–h6¤şŮĽúć.\LÂŔO4ślv“¦Ăy·…Żq4Ůäď˝h: đÖˇźŢ­–ÓYEŢíýŚ{wËőr…Ť·ÓĐ[băço°żůŤ†"Š´·z¸ĺIĺG~ÂÍ7«[; +¤ůL˙Ř|˙jąqÇĐ©öS•Ć/źŐQ}yX\6 üH)`&ľáÔxŘ7UV>µŇ~‹€ŠâáŞXâPĂ^H˝z·ą˙ń' ţa:SJ{E‹ßŘËN0vjŕŻ>5Č,ë Ď´Eµ•¦=0.Ěkř.<#ë+\Ů Ďă©4Gz¬¦@#Ă—ezqÜ4(/;ôUŁ“ŤŘ dRˇŠHwÓ…öŕ°>ö> NHx˘‚Z-Ou53ü uŽYQÉвŽ;„–Ćš ‡[ćĘfÉ_Ăŕ\ÁŠ-f› C˛HůÄ;2$á…Ě7CášâŁłPŮí» €v® ~%xľđň3ňś§|<ȸ[fG™ČMIëPźxž eOk h¬Î:Ô›†3fŘb:ag‰KŰpŚýé,^Fř>w.?ˇ·ž‚»zżŢŃçÍýŁhŻNAI`bë˙áŢ7Oč€4ôK€ČĹzŤGśłä4YłŰ|p¨"ß…Ćź„Š)L_x ;đ9Őśá 3u7ŁĄ‰ÖúÜŁťA[š"†ě)¸C.äŘŮcŮóë>sBŇ'öřŚ<_@mxě/Ü@ix҆:†€­Łř=őž Fňć¬$>ŠsŘě,çglGs›őĄÁŽYŮÖÜĘ «ŠíąĄ/řÂ<ČKAD«g\»^ţ ť_îהРů#ţ­6.Y)~·ggSŻăŐ;´`Ă\A˙/ľř*điřŞz_žÍ MĹ0 !ú°‰źŘÍgâŃOĽÁEżŞfJäÄ#»#iĂť•=|ŔöŮ4…i_ډágAq®Q,JX.ÂŘÎN:­Î){Á79·u“‹ý`®Ţ ˝…ŚýUW±{ÝÜăŽ(š@Óg?$uˇf!]–çĽßvŹč=KÇ٦—m+©HR¶čKzP‹¸AşD$“ŻŁá÷ĺąÇĐÎB`,Ëř×eügâ8eŃ/ľ˝`­űžľV<ŰŘMz-B§˝Ę9NěLň=긄R¦/Ŕiđ:u>MŃxEĐÇ ±Â ˙Čggv_+ůáŞ& L_pĽ‰LcŞŽ§MC5ÂĐ ěJö–ůË˙P¨çËBŰ!Ë3ʡXUW+Z*GhŽá«?šŠ{ AŰíŇŘÍ·ěř*ˇfAç˙"3čPĐ Űő±™SV><„_tüÍĆĽĺ ýnM1r˝öm184‘#AXBč¶6ŔBçî ď·_ »K§ťN?†»”š°A‡>qB&U Ę´ŐŕHÇ);3R“ 0Ůč„BXŐ+‹wÉŘz …¦ßš)O$É#–mD}Ž^JľÄŻ.źËň˙ľ¨Nú˘z Ecď#‰¤Łt ‰$ CéŤ^S:ľrĚLDŢdŐ^ŇŚĺźm;Ó°üŁ'ńö*e°ŘJű_x=\Ży wW©·mawĆń-VNŞ€3ö Ó›B–¸‚*Ť(w=ˇ cž @Îł-¸q6“•Á'XB|Bźz=ć Á'Ł_3âO*pMp+«äJd‹r»Ż…öp­>Ż7#ő ÚűÂÝ —ńľ´ Ě3qŚL®QŚJYńaęJ‡Ws, aÎČçZ‰h‡rXcŔVţ nŔG‰!€ôbe”©ö¤+¨jŹŽ9téŇ߲/©{"vwŤÁ5Ţőâŕ6—Âą‘¬«áxŕĚĹ`-X2ąp'„Ź ćän2ceDLsÖJć˘Ň Ű—ń+€NĽ·‡ş°őŠ,gýĺ}iaůQ\ţ ߥTĽź3`A5TÚśIą"0Ł…Ôš|÷mDń{őG˙’ 0Ő‰˛+ńi÷Š„kmZ,"Ŕž_é‹{›Ú·ôŁŹDÁ‹ź  i*žák4psXšpŹüQaiGĄ°Đ…Ľ&ŤĹ,í§a” Ę#ťö±ĂđUFPžÚgŠGT9c™Š)ÜS´íS—^HŔ€†řrJď\(÷˛Fö/‹¶ł é;J!†hHáţT–ÂÚ.ÍĎĎ•Áä?`±‘ÄĂĹ Üčé|Ä˙G.É{ĺĂHŚqŇ‚-müsió"%ŁÉ¸@č!ą›™«»‡¨ ý4ŽUźî‰€Ć6řĽXOülD1Ó¦¬zgóÜX’ęŠjôĺH2ÜÖü‹ŰŃm!Č䋡u=ÂÂÜZĆâšBł±µsŇ a'ĎąÝă$‘'Oj˛j~~‚ţđUş]ź1Ôi(ľWugd’/¸ë¬éư°Ł§IŠp‰\= ˇţž?ś†_ţşÖď8¸ÁP~­Ś”Q č%“ô@8ń1\”3Â×q{¤ QFwâ8îků*–:%Ž_¸í] âŹŮ/\'ŹŢŤ%ĘłY Ž!đ%” ž†Óöy=d§ŃËOđ˘±řĎXá‰BőěKřČŽěĆĹendstream endobj 401 0 obj << /Type /Page /Contents 402 0 R /Resources 400 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R /Annots [ 409 0 R ] >> endobj 409 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [159.9655 256.3563 167.4126 265.3792] /Subtype /Link /A << /S /GoTo /D (cite.rfc1035) >> >> endobj 403 0 obj << /D [401 0 R /XYZ 113.386 764.2205 null] >> endobj 404 0 obj << /D [401 0 R /XYZ 113.386 727.37 null] >> endobj 106 0 obj << /D [401 0 R /XYZ 113.386 684.1133 null] >> endobj 405 0 obj << /D [401 0 R /XYZ 113.386 615.4846 null] >> endobj 110 0 obj << /D [401 0 R /XYZ 113.386 555.7995 null] >> endobj 406 0 obj << /D [401 0 R /XYZ 113.386 498.5988 null] >> endobj 114 0 obj << /D [401 0 R /XYZ 113.386 468.1332 null] >> endobj 407 0 obj << /D [401 0 R /XYZ 113.386 413.0538 null] >> endobj 118 0 obj << /D [401 0 R /XYZ 113.386 369.039 null] >> endobj 408 0 obj << /D [401 0 R /XYZ 113.386 309.7171 null] >> endobj 122 0 obj << /D [401 0 R /XYZ 113.386 236.8237 null] >> endobj 126 0 obj << /D [401 0 R /XYZ 113.386 164.1178 null] >> endobj 400 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 413 0 obj << /Length 1878 /Filter /FlateDecode >> stream xÚŐX[oŰ6~ĎŻđ˨U^$Šę[Ű8[†Ćio+°îA±ĺX¨-%’Ü$ýő;RQ%k‹vŘ <$Ďő;”ĺHŔźI!B™h”(TJÄŁĹvOŚÎaóç=é&V†‘Pé( …‰,˛Ś.G"L 1t¬_v‡ÜÂóĂ­íW{ďöFďnJ¦‘ŽG“ÄŘPŮX#ë«ůŢóiA§0©ÍWŁT…V ÚĄˇÔq2š/˙ ôxj‹ŕdzúöxv:O´ÖÁţá¬Ó“é ‰×cL‘8ĺýW8ź˙AKȡuĚNaqźięĐ0ëËŮţĂ}ŠPŚ˙š˙ş7ťw†Dŕ›>í<Ç3é3‘©±ě›*••íD&ˇµ±![—Ĺ!u^Źcäĺ‚°Ŕ&6 .p–->ćmKilźµOĆ}ńś®Ă8JÉ-'%VµĹę†mţ bˇCX‹€’(O¦&)úĚ·?ˇŕ‡’Šk8¶Şűrb˘DYŽ “pjPƧ±˛A^ŁAz•á EąDˇĘ ŐNłÄĆŃ“BĺcBô]PĂ„7yv×ţî#Ă-:´ń ćó±ŐŕĆlĂRJ»)۱J‚3đ@rç–jĹą°zmŔ€,ČIĺđźJŇ8P†ô:Ěv[Ľö±Ű4$ ć jô‘ĚĆ|Á”n×93Đ…Ů6çĺlüm_ĺJ˝Í6Ĺç¬-Şu“JJEQśŠďŞń^ó&Píȧ/k§d“mÉWNhÉcgŃ•Źzť{g ôĺă c$/†l(ĐaäÔ >ȦäKĐ#Q"%=Ś4\¨ `B†i+,Ô‰Ra*#‡‘5śĚ€ čs@=ĵj{‘Ťµj´°!ăMÂ*ÁXç \ ŰUŮ`.icP#Ú›˝áůzăĐ Ö[2-[äŹ`*Ą {jßaŇìŐVxWµč+tMîř&:±€¨xa’ÜÂQÇ2łäťtfĐ%rE9ČtĆCą Ǔ؂gQs˘U0«0uq»]g­ă§d«Űˇ¸Żjr(0*´ćjDZK‰„ŕ[b dĂî ˛:gby×7 ´x†;:Č6fé Ł"«.YČ… 5˝Őâ C\főŤ»Ň—l5\±Jrú“BtpŔĘ«˘v•qF—Ć ¨WbžTäʍ€ÍÝb†°†ś9w›Z—ËŕĆŠäÉž¦Óëiä!ß×0;ľ_kłĘÚ@YßŰŕ‘‘ęďĐ—L¨l×2’P$}éǶ im©űě‰TAšđü˙˘cpĺŁęţkýŢżFř÷5íB»vńűXÍ5Wč›EąŰžQ“Ŕ=\đđ ëŰĄ:Až\rÓČ('K«ÉëOÎÜn ě:FţË]^Ü;ŕI«=¤qçúőŠeźÉÄ—Ľó¬¸Ex+))ÄlŢ/¶żľííR>ó•ČĆ 3J’3˘v©–ń0Đ"Ŕë9U?sŇş‚ô*:¸kÖŐŐ^†·ůŇűĚ0vľĽT&B¦¤ćË2ŰÜPŘ›Cń‹ŁÚLÖ!÷kŤ{—KTŻÁhĂđĆ ^WuçÓEËš ¬gkÜ"€]‚ß ®óv‡Ó2ď[׫†D†*NŕkKŔ_a\5D®Ę ®Zź+Ô"|ň›ˇZB!ňm^BaŢ®ů‡}jş×”ú‚"€w &Bä!’Š’·Á0K~Q ±Ć|—ÁďÄ9N¸"Ő9%I»ąĂ!ú^i~d!Żâˇ „KGwĹěx~xôvŚď@šw‘©± qeQQ(–ţü3śT®‹Íc ~ŕA@5]Ä\4gÇ0!x‰IýŰü‡Ź'gď÷ŹŹ€ĺĺ!^8ăĹĽ®ýţ}•š/Črő IľźŻ2ôÖ¦ĺçĹŞv΋˼děR‘ßąĆç^0˝ÜŤ{®íŘę(Xîą«đ7,ÁŻó®®›ÜÝĐu‰«{…„q¸Mý~82˙ěcýÖäŞę÷ërÂÍ´đ7QR–çrřÝăMtĺ‰öµëЬűśűv@çÖĚ$Ą,Yák5vµ÷kµ¸^ŐwJôđýÁ /`RĐGO°Ńăm'pîhzrŇ˙ň1__ ľKĹ  ßC'ľáвnxşWÓňs§O5<ěňYä1sx°CúĽ`Ŕ„;IRűYűTj(Kńŕů›ˇş<Ŕ­ă“Ł)śG×(ŃóšĆŔ[¨răÚ-ś°;‰F?‚küć˝ŔÓ·Â sň·Ěý‚/c%á@É0ŕĐw‹F?¨˘gyşc¶HsŻ×Ęßg°Ń•#Đ㽋˘Ą>‡ĺ+JOr $şhřä–«Í5.ŕ§/Đ‹şÂˇ.˛¶Ďá˛m«{čyç±Úˇ(\r`ůöŤĂÉ;އKw®čËĘ,2ŽOĽÂ Ćö‘îšyŠŇčˇ{Âűżv?#°ZÄŕˇÓ¤Ç5đŁo”mEÚ CŹđ§ßŔoŻ7ţ ¬Tjiendstream endobj 412 0 obj << /Type /Page /Contents 413 0 R /Resources 411 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 415 0 R 416 0 R 417 0 R 418 0 R 419 0 R 420 0 R ] >> endobj 415 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 699.2754 183.6508 714.8171] /Subtype /Link /A << /S /GoTo /D (subsection.3.4) >> >> endobj 416 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [156.234 685.7262 172.166 701.2679] /Subtype /Link /A << /S /GoTo /D (subsection.3.5) >> >> endobj 417 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.8098 672.177 203.7418 687.7187] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 418 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [194.5977 658.6278 210.5296 674.1695] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 419 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 493.6905 183.6508 509.2322] /Subtype /Link /A << /S /GoTo /D (subsection.3.4) >> >> endobj 420 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.8098 480.1413 203.7418 495.683] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 414 0 obj << /D [412 0 R /XYZ 100.3464 764.2205 null] >> endobj 130 0 obj << /D [412 0 R /XYZ 100.3464 584.5045 null] >> endobj 134 0 obj << /D [412 0 R /XYZ 100.3464 406.018 null] >> endobj 421 0 obj << /D [412 0 R /XYZ 100.3464 343.9702 null] >> endobj 138 0 obj << /D [412 0 R /XYZ 100.3464 308.2981 null] >> endobj 422 0 obj << /D [412 0 R /XYZ 100.3464 245.8435 null] >> endobj 142 0 obj << /D [412 0 R /XYZ 100.3464 194.501 null] >> endobj 423 0 obj << /D [412 0 R /XYZ 100.3464 129.3191 null] >> endobj 411 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 427 0 obj << /Length 1312 /Filter /FlateDecode >> stream xÚíWMoă6˝çWř€>ĺ§DőÖ4N‘bá=t{P,9bK^Ii6ůő;3¤d9•×E±Ç"€ĂŹáăĽy3$%gţäLJ͵‹gIl¸RÂÎÖ» 1{€ą_.d°‰zŁhluµşřáFş™<©ś­63™ÄܥΚăĘY=[ĺ23ʤ‚}\ÜýţŰňn1Ź´ÖěúöĆŮÍâăb‰Ťźç’-°qç篰żú†ĐBkCc·ËkßqŢî§ľżĽ»ö#š .ć­~˝X¬&5CÔşĄĐőĆ˙oĆI´/MSSÔťî(‚Ůş8ˇźv{:!VŹ)F¬š2 [­ź=u°¸ň—G‡žŚHC¸ˇáë‹&_i9 î_»",zÁ!ô 2V|~î34€HLµH•l Ô7ÚCśťâł$`]…Ô“¬ Ť@w[{®`ä´rKĄx •›§<!hóÜgq3·ś5ý—8I˝lýTtX©uěŇ›źPjLŞŠÖŰfťß#í@ŕ“°BqÍ40“l¬f%ü*<3Ó98rŇËăůĂ&ʰ&kŞĹcíHÎ1˛áIʬ…dVM找śŠ}eXĘy١l5TĂ1˘íÄC+«â€hąV“÷.Şíň¬Ë˘®Űî ÷UĘž÷t °5b›XöÎ žŘIč*ÂtÚ{dŚA ÷ĆúŕĆ©‰™t6@µ8ż©:šÖź#ňfŔ‚Ü–BëK&“*÷ě™Ň?ʨ2^Ç|ăÎĹ tO4áNEÓ'Ë‹ĽjĹ©W%ĎźCĘ)pŐ“jĺ[ű۬mŹŁ(e/LŚÂ¸łđ÷ÁĎăj%|?C9%ďá(jŚP7(Ś>}ĄAZö"9±/zOçž8.±>µ\ŕ,M@ęDuQdşró:Ć1Ć%$ÔJś­| ´¦ tëčósŃeÂP§Â˙ ČÓńŲ}¨`ł|ĽAźą70ç6¨˘ň Ŕlš¨Şń .wţĘ—ěÝiŕúĽSĆ1}Ö鶴3(ţciúÜM…ŇLžĆđʬćN0ý±DE…QŘaŹ®ąLtýµžź{›Hö#žąIj<ŕ ťůŞ|šËňy‡[źÚQS´˛5zőDŢ…˘ęĂM›f»ţîÚŕ11ň9łË¶ĺ[†O1ôO*Áŕ~P‰4ßŐ)˛ýâ'1E·NÁßŃÜ]2ýé80n{˙ȇ•…x*•¦SŢţG)÷SĘá<ńÓÂó(rp"QpZ+eŕF‰§^uŃđpp{Űđç껼í–|…ţ|Źř˙ySŹ<^ÎSĎ;MDÝđĽăďżőúŹłXÂ'śÓßţ¤M}ŃľBÇ}éM~\NěřŤĘendstream endobj 426 0 obj << /Type /Page /Contents 427 0 R /Resources 425 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R 435 0 R 436 0 R 437 0 R 438 0 R 439 0 R 440 0 R 441 0 R 442 0 R 443 0 R 444 0 R ] >> endobj 429 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.2736 489.0053 213.6904 504.547] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 430 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [198.3948 475.4561 222.8116 490.9978] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 431 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.7584 461.9069 225.1752 477.4486] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 432 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [236.5161 448.3578 252.448 463.8995] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 433 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.9099 434.8086 210.3267 450.3503] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 434 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [186.3039 421.2594 210.7207 436.8011] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 435 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.7584 407.7102 216.6904 423.2519] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 436 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.6372 394.161 218.5692 409.7027] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 437 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [221.4857 380.6118 251.3571 396.1536] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 438 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [250.8797 367.0627 275.2965 382.6044] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 439 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.2735 353.5135 204.6903 369.0552] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 440 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.7584 339.9643 205.1752 355.506] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 441 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [230.516 326.4151 246.448 341.9568] /Subtype /Link /A << /S /GoTo /D (subsection.4.7) >> >> endobj 442 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [241.4251 312.8659 257.3571 328.4076] /Subtype /Link /A << /S /GoTo /D (subsection.4.4) >> >> endobj 443 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [209.8797 299.3168 234.2965 314.8585] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 444 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [179.6069 285.7676 204.0237 301.3093] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 428 0 obj << /D [426 0 R /XYZ 113.386 764.2205 null] >> endobj 146 0 obj << /D [426 0 R /XYZ 113.386 727.37 null] >> endobj 150 0 obj << /D [426 0 R /XYZ 113.386 600.1676 null] >> endobj 154 0 obj << /D [426 0 R /XYZ 113.386 174.1354 null] >> endobj 425 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R >> /ProcSet [ /PDF /Text ] >> endobj 447 0 obj << /Length 1918 /Filter /FlateDecode >> stream xÚµXÝoă6Ď_á—2°ćňC”¨ľ%µs—ĂŐŰ&ÚâzŠ-;ÂÚR"É›¦}ç”嬲čÝ] ‡Ă™áĚoh©‰„˙j˘¤&NâIšÄBki'ëĂ…śě`ń_Ę Íś±ÔŮ$2‰ŠLž&R¤ ôđźúMžńţć 'óúâç‹ÉĎ'…ʉ,6v2K'´łEŻVﯕ›D&35Ym'™ÎHÖeB›NV›˙EńtfËčvq÷Ó‡ĺÝb:3ĆDó›kŕG׋Űʼn¦*Z qÇëW8_ýB,”0&&ŢÍrÎÇr—aľĽ›3Ç)äô˙«˙\,V˝ 1ÄÄe_›—™ …ČI«†N*m„N`9U©pÎ&äĺ¦ü]*S4S«˘˘ZÓ¶;“&Ń#ÎňőǢCoZř“Y}Ţđ.4Bi‡§Hş6Î4©Żfë}łŢÜĂž˛c?—Vj¶ˇ@g˘uÁĺ¤ď,‰ l7ߡî×Ę6ł#č©>Vđ·žę4zFj†ĆŐŹÓ0Ö5 .Ú[< $´… Ç©ÔčH'™Ç)ałŃă*:î‘5•wµ¨U'¬q‘ŇÎx­ĘBżŇŞĽŚ|ó„Ę1ÔQÄ ÄÓć»ös»Ą?ÁX›F.FŇ™péAzŔđŕmEĆ'? Y ‹Ôkµ.3‘5Ak"ô[ˇ§ wĺöe¨x`˘×•Z%#ťŻË8~C×§)„´hÚ˛®ÎÍŠ{UÜ×^“„ĽŐt?KĘ^ÉŃlŠĹ3ťÉ2ý™dÓGCK§#Őź*Őč Ţ;l±©ZyR Ě×_ÖĂÖŻ¦Î@Hó=«¨Đ@t䀩}Oů<´·Ţâ¨CĹo‰@/×tÍäë÷çĆAľXŤf¸4ŽËF­Xxđ[ç(´é#…°óIÚ=řś˘#ó/Ž| ňÝPeNsČ÷ĺźyWŽÖĄJG™ŠÓě5‰d˙ŕEL˙=f·Čob{V!{žq±ů¦ÁL –™Püďńq̲ĎW´‚)6`E - Żţ1ňj€%2k5"ďLk!…†`4t±Äw1ő»0m=! xŢĺł®ŰĐĎęřL‰Pjdý ÎĽęps^sĽväVŔ™†üB{Uâ×F¬ŐężLl›úŔŰî>LŤŚ.™ťď[BpŚĄÎŔŘRDł8eŁK Q’D÷ĺn­i¤ÍĚú}Z‰ň›ö]O] ©6ťĹ6‹–żÎ?Ŕ1?^Ţ,™ń„&M‰–ăb Ł‹nu7kůž<‰*ÔWÇ’ěÜ8s¬ćn,čĄDBâq yŔ Aě CFRi‹Ť1‹c8ôŹGâ6]ââ×ňČÁ*9[ĽrÚZöŕ°G#µXćLĺí­`âß5rźŃäâÓ2Uô’”U—-ë>óđ0Z” .Ł-&“Ń>Ge»ľ"ś•y¨‚Ąë¦Ü‘áTUŔXQÔĽ.*ˇˇ¸÷ĺϸćj°”¤ř…|„zP™ 'Ňśř†ę›1'®ú×[Ć5|l‹‚S$+„*ů~jFg¨ŐťłGš®ŹuÍŚOS›€†cáá o??†# Ä™Ţb€|ŮítŮ(s3Ž‘8aÇŕmĚ$XM€V[ňú˛Ę÷/-ŢoűýX ZŐ*†`QŚŽ;>ŞôxzőúÉŰÖűSFmOÂČ\ú§p&F.UBŰ4#€KµŇŕâ3€»Ď7¨ę *ýe†Ćďň{ …M‚lRއ†.ćăF<Ü ÷xŕK}ać–őń„ {Nđě7A - ťô˙mPCCňWů.äFçs¦a›}źŰRłĺ0{[7 B’ OsÚu'YţÉ÷°ń_Ż3ü„§–ăˇÜń[Ś:•2çÖű—^428ĚL/€ž/ŃŠX…ŽÇŻÜQWŇÄÉč¦cĽją‹4^9w+ ^˝Öńő„{ÓŚŇo~›P•}2šsS‘Ńç$đnoqő›!](HwĘ2ę¦`Šl˝§7EŃđ«oąb’§ë‚_y?Ľ•oĆ75? ˝übމC׳†^7›đîŔ\¶¶Ţ)M‡1 …Ă?ă|ú˙Ťw7V_‚aů:˙“łüĎŹôµŕč É´Ď`Ä6I ;fPdÖ{čU-3ňĘŹÇîË‚î©^i‹µO:žóh‡Ą1ŽÁ=tc]]RËůŤ«J|5 ĂŹýĎßV-óŃü .PĹ•Ôę_xµ uS{±0žWFźď¸'ŕ:Ňë}Ţzö%ÚŻą‚p ôęm 6‹Šß,¬îŘ„Äd«q,}jz«é-r¤jنRžĚŕBÁ·©<€ë÷0ňÖ?Î9k‡ŃúŻŹ T„fô+Z/4HŤ|+ŚS ťĚzeh˛o|¸9ń/ îHendstream endobj 446 0 obj << /Type /Page /Contents 447 0 R /Resources 445 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 449 0 R 450 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 457 0 R ] >> endobj 449 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [176.234 699.2754 200.6508 714.8171] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 450 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [219.8401 685.7262 249.7115 701.2679] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 451 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [172.8704 672.177 197.2872 687.7187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 452 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [205.3856 658.6278 235.2569 674.1695] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 453 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.3553 645.0786 209.7721 660.6203] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 454 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 631.5295 192.1357 647.0712] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 455 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [173.2643 617.9803 197.6811 633.522] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 456 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [237.8401 604.4311 262.2569 619.9728] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 457 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.5977 590.8819 205.5296 606.4236] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 448 0 obj << /D [446 0 R /XYZ 100.3464 764.2205 null] >> endobj 158 0 obj << /D [446 0 R /XYZ 100.3464 519.5219 null] >> endobj 458 0 obj << /D [446 0 R /XYZ 100.3464 423.0374 null] >> endobj 162 0 obj << /D [446 0 R /XYZ 100.3464 388.5936 null] >> endobj 459 0 obj << /D [446 0 R /XYZ 100.3464 328.1074 null] >> endobj 166 0 obj << /D [446 0 R /XYZ 100.3464 295.7847 null] >> endobj 460 0 obj << /D [446 0 R /XYZ 100.3464 235.6971 null] >> endobj 170 0 obj << /D [446 0 R /XYZ 100.3464 189.8252 null] >> endobj 461 0 obj << /D [446 0 R /XYZ 100.3464 115.7899 null] >> endobj 445 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 464 0 obj << /Length 1331 /Filter /FlateDecode >> stream xÚŤWÝoŰ6Ď_áG ~‹ę[ҤC‡Ĺ-loĐőAuäXh,'˛Ľ$˙ýîx¤,·®3ŽÇă}ţîHË‘€?9’RsíÝ(w†+%ěh±>Ł{ŘűíLF™qĄ®ćg¤IÁ QČŃ|92*ç^x Ú5Ţ7(IšŞ-ń»UEÄü=)ř†25™â?í‚ń·‚Ĺ-f2j‡ٱÜĆ…@˘Ú€ëéŘc6Vžm`ܡZłnCBOŔۉ଻UŮ‘Ä vĘLĺěß WńXđä‚ďŔřVGńm0ŐńllŚa“śŽ~ÜŁ˙I ¸ń v¦ČĽÍ°úSNb˝öB™ ílÓŁB—MůđşEÍŰwDzb ×JČJĎWuHľ`ô•ěkü=EŚnEéB5á,ę† NĹěa…âš×-Ď©dŐË"Ôę±#±çUJ~»W{őPÉ âô%ęv@µh+Ô0,ą˛yŤĄą5=ůűúfęňăí*Ë®đ0TÜÓ˛­şęl¶´¦r)—ĘüJěç˘ ň["©’@ÄJÂN(¦JŮ-ú:Č‚4°˙RÝE~ÝWŠPD„ĺë3Dç¨EB tq%ŘC }pëłV>Ä }ËEĘ1ęhî‰ű´fş&av$¸Ő‘ĚŃ4–Ü[Ó˘jq±iéЦ9a€¶žűĆ]#‚čHüÔ/z]˛ľeB8ÝôZăTěj «\ŃxšVËŞ­Â0YLáśLÍć–;!ĚéA=”˘A}Đ@?)C7ľČŻ?U0v…ToXMRošŐ‚kkóC»0 _ v 9¸ŁęI†EÎý~o—6ş”ˇĐĽQě6ŠýQ¶In3ŘľŽŰ·ĺ–đ˙šy“6Ëqî<›E©é†„b鬆 ŕ"RBË8{>·™[0p-iv!Řm`ÝŐcjůţÜp°Ő©˛«7ˇŻÁŻe©7±Á¸ž ?3ZĚŞ`+Ś‚ş{%ćÍKGÚ"U›J.”RŃw× #: ěpc)f„¶Dá<}źŰÍcčŢ;šoł® —NŮbŐh^R¬ÉÎA¬·ˇ6 ĽtVÔ" gS’őĐQ§ąłp呟«®{|wqńüüĚëŞ[ňM{Ń.řŹ®ňîĄűU´Ć*ÓGű«†R–Ţ˝ŐP©S •ÄBC© uŇ꾡Ţ0Ű7ÔĐîgD7˙‹¬X»řď™u¬¤CŐµuj–ŁP/$ĎŤMHżŢ¬Ë0¬ŰMąO ń}ä VŻńŇ­ÖUžRĎ$AýĽT,ö.˘·{fۆ+Ł‘^nnZ“łilŔ›Ö Ţ…ĽÉceĆřdéĘ0_ŻńrWp™O6¨‰^0kĚŃÁEç%“…ĎŹâT:É”oUţ ž“Śv#Ď ‡%]Ž°ß 2mVü aA hÄ~6bĆ5Ľv1ŞW˘S›Řćńˇ&<ŠĂ+şQJŻ©ŤO¤Ď]" Żz˛°{2 (áWIÝsĄ—{nžH-üů±»TY”ńřK+mTO:ëăt‡ ˝'MO‚„¶XécI—ÎAĂz˙Öt€Ľ+ĺőéá0:ň«čGUśî—żŽXü›d endstream endobj 463 0 obj << /Type /Page /Contents 464 0 R /Resources 462 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 467 0 R 469 0 R 470 0 R 474 0 R 475 0 R 476 0 R 477 0 R ] >> endobj 467 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [322.2336 671.2487 346.6504 684.1503] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 469 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [193.014 545.0815 495.9258 557.074] /Subtype/Link/A<> >> endobj 470 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [193.014 545.0815 395.4589 557.074] /Subtype/Link/A<> >> endobj 474 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [393.4664 545.0815 395.4589 557.074] /Subtype/Link/A<> >> endobj 475 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [290.4506 508.7137 495.9258 521.6153] /Subtype/Link/A<> >> endobj 476 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [290.4506 508.7137 492.8955 521.6153] /Subtype/Link/A<> >> endobj 477 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [490.903 508.7137 492.8955 521.6153] /Subtype/Link/A<> >> endobj 465 0 obj << /D [463 0 R /XYZ 113.386 764.2205 null] >> endobj 174 0 obj << /D [463 0 R /XYZ 113.386 727.37 null] >> endobj 466 0 obj << /D [463 0 R /XYZ 113.386 686.4003 null] >> endobj 468 0 obj << /D [463 0 R /XYZ 113.386 589.1496 null] >> endobj 357 0 obj << /D [463 0 R /XYZ 113.386 593.6328 null] >> endobj 410 0 obj << /D [463 0 R /XYZ 113.386 541.5946 null] >> endobj 462 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R /F53 473 0 R /F36 207 0 R >> /ProcSet [ /PDF /Text ] >> endobj 221 0 obj [178 0 R /Fit] endobj 220 0 obj [178 0 R /Fit] endobj 472 0 obj << /Length1 1045 /Length2 4255 /Length3 532 /Length 4958 /Filter /FlateDecode >> stream xÚí“y<”mŰÇe/{vE–cŚ=˛Ť}'$1Ć0c™af0öě[d_Ë"Kv˘…BQ–;Iö%{0ĺťşźűą{ďçĎ÷ýëýĽ×\Ě÷wçďüÍq#,hj!©îŚuB°‚$X ¬hYZ‚Ą°”´´ť°°& ' ±-8©€eu/ #€Ą•deČ/ť0 ‰őňǡ]Q@TSěg‘< î‰Äˇp `' ždܰŔ"ĐH‚ż îá˙ÜĚ‘x$Îé,EÎhpBş˘1t ź™ô0.X@ţOŮŮÇëŻ%_$OţŠ)C:c1ţ€3Ň…dŚ%ź†$gůßőOsʇ‡1Üó§ýŻNýÇ:Üíá˙Ż ¬§—‰ڰÎH查ÖČ?Ă!ťŃ>ž˙\Ő#Ŕ=ĐuŚ«ţSBăah"ŇŮM@ ÎůKFbś˙™Üą_ @ú–0}-}‰]ęŻES8C°ô÷ú·ëĎę_ ţ›ÉíÁˇ‰€ť4ąż`r!ůó×7ű¦ŤA`ťŃW@*Ŕq8¸?y|ČÁăŚ$H"90H %·äž.XÝĎ••@^äKÁ:˙Ô˙”äŢŽGý­( $ű· €°äż @ů›"€\°>¸żY@űţVA6E`=Čcô—˘HvEü›Ŕäß Bţ†?C˛źëo( €Pż!ˇ˙Fňh°ż!ŮĘë7$ďĹý†ä–~Cr*żżQFá^ş†–() HĘ@ €< (HK˙·2„‡Ä~ýˇČó» ÉS†D‘şń1,B9Ň-«1úAö˝ˇŠSâ'4\›’Ťë»†;č#ާśđ¸ßgŕ-ţ©Îć°2—őĚâ©E?>ľ=Čě5l3Ě;9{ôǢŻăbn@ ŹÍv®‘˙‚—Đ~ÄęٶƑÝ5č “wźú¤Ű–Ľ¸»ŐłZd*ŞeąDýQ˘Űηˇ;/RNŢ–ëaU'4gĘö~+3éÇ”žJ59âCÓ,1ńŰîĂrxʦ0í‡ĹâtB¸ŚFţű¦A·Ë1ą’\ “×µ\&oŮső÷ꀄťňŞ»sŞFZ1ăműž ÍX´ÖvűSŚfiťÄ_s-őŠR)â­×©+aŚćT«JÚMUFLîxʇşQŇ2eÚ»çŇŐňLÖ‘×J˛.–70óĽ‰ŕĚÔu.s¨Ţäô«L?˝T5©ť¶­ŐmĽvćZţóó©ßxO´kX˙`©ě>YIˇ9fĚb3[ó*~Ţ=ż#Z´*<>âçč €ŢÝĐpV_qcśD\´Č(Ą¬řL3óRRˇŕ­¸ŕ2:Ç??ôÂt©˘3Ő~´®´ťŚĚďôĄÇ1ěĄ|8ş#e¦wÓU‰ÝE€Á2îĹs°9Äv.y/ŮńË4 š) ţĎLHçýű™ ří:pĎž•Uq:ů%†îT¤ú Ć§Łž.[žu´E…úW¶T?Ż”+Ţľém!vOM€ôŹJ±c5Ń^«r&'>Ýî;ŞAŁž‚YR¬ĺŢTV$”vU ‹F íő:â*7—ŃątsëQ ńýBBůěNśW——ơxýŘśş™GôGUďŮY/ =&Ńëró2BI¤Ńá3ě­Ň&ĺţŠRÓíÝeA©é·gů‹RłŹç5g˛iré8F3¬’<[›¦Ą…¶Ëśt-Ż/6Ź]/OP±Řß(ţ†éJ7`ä8AńtŇré Ý­~o”Ž·źvŢkë—žYZąÂcŞ‘߀˛Ę”ĽIQMŁÂ5‹•UĺÝ(/ë6µŐ ZIĎ®¦7Ć|·&Ĺ@7?ăgýzIŻbAYCsźG\6žÍ8‹=Ăľ˛Q˘ŠŹŘ»©×K˝@bĂ/M%łŘ·?Ó˝Cµ}ń­× ŇI–ôŁoéŤ_łO[÷x7VT¬Z\Ąt%µÄ±ćDw‹~E/^ý’Ź3yS‘ZŤř‘™LcˇÍŰQ'rD˝»9~ŠUţćgvµŢ”¬ĎkÉ#«V Ýa”@XĘóľ•–^$űŠYÔĆţ©Ő{! ĹăťÓ•úeüş7SÎńhż»_sJE6¸]ßg¨=’Ś„C¦ů4#ÍDžbx)}ůîV÷Zę°ł»ĺ(^Ą Źă,®tę˝Fd}4%Wn燭Řä×ĺlmĦJČťŽž˝@«áLĂV<ëUűśăřĂôă(úäëď@IüčýOODwĹřuOܶcě?şź‘}í”÷b€yĎĄfá´Kýź=˘©Őěë„miĎ  z(=ˇhdÍřŇ·ĐfnP•(8¶®<)ĘýzfEł«U7L‡*­Ru݇÷ÔY±:yľUť%´Üď”-\Í’„b¦Â† ¤oéŽíÍص¤˘’µÓđčĆŔĄ4őf¨XÇ<§¦ţŇž"é+ÄLľEdĺzI  !ľ&'ĽAgOśo©4’Y+väiţ1¤ćŚ"bóÓݰł8Řö¤ĽßářŕÁxwąpďRÔ\FčňÇé3Q¬h&Hĺâ5öăęĺ´OŻá‘öŰ®¬Ę=±qËUâ…źĂC1BëŽ?.¤DŃ@Ńx!wŃF­@Âőšě/ßEofŐkSŘ{®G=ÎzDzµ"E\룺˙C“˘ń»´ĐŰF¬wńµ`ĄŚSďżĺqęľyńĄ—$·ÖŔslĽbĄńsâŮśÓ°hE*YOą|gž ·šîĆoi蕺„ć¸4lG#$lë{9v eĚAĚîD©YÝétŮŢ›#Ş,éxu±¶ąí¤Cú Ţk› éÍëÍ]C¨Ą±C23•_·l ęřü§Ć”G,ô6Á§ě‹ĂIĽˇrÜ‹)•÷;ç"|ę')·fI|eău¤ IĘGZ*•©ŢUL3qś :á¸ĆEó^Š^ëÉD‰gúËănv=m~ˇcۨü–ÚפËr{Ń@>5eě}2GOK›«mŕl]ݦ‰˙;‰,kKg§Z1ŞV˝[ąřĘß­ŹI‰MşSłś‚N™Nµę¬ľZ«"NíöpçR­ŢŃĹňěĐRV˘\ń’©Ĺ5ď9|ü őRzz:v!+@ă€OŐÍ~=3Ń0˙$ëŻŘ’r¸ü#K=IţJ> ŕńďş7]ZSTŇ<‰"»Lö1i I„Î9*ýNłVę#ůn“`áă»*”Ôi0ŁP)YĘŘ™0Đ=Š­ú $ALj6ď.ałćÜŢ5P]AIôc2 žô§D¤3ưְÂ^–oŐΦ°i đ}ş1&?BuycôIŹšč‹çuó粌Á6¬‘ľ6É=ąjÝ?nĘ@~đp°©űHčő+ýišteNŇ7ąß\áä?kˇp›á·úíöVń[꓇3Uđ~ťDŚeę©€X_ĄËK wřşč˝­4¤źA»ďOî~%1Š˝‰lmŻi+Ź3……IłôÍżq‘PA© D1đ•ă~VÝĄďŹ*Ęî™­~üá’háΖF {(iMńňĚűQąşśÖf/««vBľtÇëC&nůÂ]± —;NŞ‘@’Ă>uü2"/(>&pŚ­ő9qäq­«đŰ aßx¬îgźęÁW¬#Ę…)KIogÜBĎu )€âPpf’5ŁďĚÉB!Ë ŁőýůĐĘO%â'(ŠoŘteÇÚM4ÓeĽw¤Š‹kłˇ­ľ-ˇ$ţ#t'?)0‘ŢN5ŃÇP°·”j¸őÁî”0XśÁŞŘr…-ý!Î.¸dűµEü¦ůý-L­ámď\‡ŻÔ!ňˇ»$ĹéÍc9“Ěž űřŮ´ëo;p<đϬ÷ç=¤Î^ß«oŻ3–áR#vĆ?ćžżUpĄĎ/KiP}Ó öjK€‘Bwwź+U=iş´T(PĽÝ|5Ddaé1© ućÂ"™Aű óy_lYLâyń;‘řŠ;Ľ7šę»ž´¶mźC…Ľ2©‘Iă+›Żi¬\Žy»§ŃđoőJ׫Ď?Śu˘űęBŇéö>{ńŰĄ|šĄĺh[ëˤtćá!őÍ%vo}Däšv+…’˛ĎŰö‘hs23퉷uxgn©KT î;¨ăĽĐň¶úë€|ăĐ=Ć«RzÍ0Ë2®p;¶H?żšQ¤JÉłó—/Í4rüQÔĄ{óĄe1ÔíyśÜ2ël¸ÂŇb$xĚ4"Ó—@łéŁlŻÇR?u*óŃVţkQü‹ůGîű}ĺÖĽuÁÇT1^Ăš­L™F­ög[5Ó “*O¨]îčPĽ<®x2ě¨tÝUńsnmŠb»^DIŮČ<ÎBúc:ńůS±·z62ŠÓř•ŠCFů°¸/[Ĺť™#vŰ\M¬ôD’đ®Šk‡a\ĎŽNX•‘w§¬±,M5q/ý&^t\ëińŽŹ1;<šĹý›×-–™KÔ<Ź´Ś~ŚĚĂĄÂax•ćŔ!ˇ¨d>skҦq›Gtč>ôÁcĺ/ů}†˝\¨pĹţAÍ›¬{Ż'ă»Uzv† w»‡@›ŃI„Ăń[ÍĄçą>—Č_đśá ¨ Ôäuů¨ÄĐ×đütüÎťrĹ„®ÍÎěŞjI”| ‡EďđR™}ެů¨ůśfISB×… öţ] ĹÝ`«#ţžĺ żţŚă.çN ű5IąŢÓÄĽ ŁĹ'lŰÍ­CééÁ‹np+đÇG˘\O4löMď‚Ë5ö˘ć®GÎÜ›2ĎÝŘôU‰ D;=ĺ]žđyX¬>ĂnĽ>ŕˇ,¨KŠÇĚ-ČÂP:Ż7žÝ\„@"QYŘ/Ą®`₇O‡Ý»óÓöyËbZ8_oÜłq>„©»ş±ŁŤă ćč`üwÁ AŃđĺ»:¶ ±cůűŰkNĄËCiq‰Ł(‡­ĚÉz(ŹšďüĎYY,Ž[sÇĂ1$D÷Ň™¤ä3b€qóÖí]ç˝÷e´ÇŤ'.˘\UŐHć…¨)ŽŃĂď+‡óĽ›ÎZUyËć‡AňBRÝŔ‚r:öˇË˘€Yň•lßëmŁŚevcšhÍý©¶Ô:Dę:ÝŇĎA+Ľ4Đsi'kzpůH7GI.oýÄ2ëţ¨WÇŚń=, ú?–—hą>DňŤP•1č’ZÓ˛4E3e°\ÚUe5˝Át+ň¤Ýa;ë9lÚôŢFZőd×^čÎxqđ÷ł»Ś6W»ľ[V«+ٓܒ¨*Ě[6Niě˝6ą˛žN´ÉŻQ_Z°čźYüŞ–É˘X0`ô±ęw5–}tĚľŐ\Hw;WIĺ¶Fá×'şă¸ó­Ť_»ŢgqM j`ÖX+eQĎţ¸[ĐMц˙&ţ­ÍSpýfUMëU”cş*mý-xđËř„Ę'ëł7_Рź˸ڠÖÚčÉ6Ą=˘\˝rePĆJá,oRŠA>LnPôa{5>O _@aŻ¨Â¬ĄROŠâ(݇PűL¦R'MĘ%lŘŚˇŃ}y’áČKRÎ%Š;ă҉x×{ŹŇĐâ!ń¸łÔ5â?ň ŽÁüń÷<€9ÝP6óşęTÍV‡LčjŁŕÁKdxíŃM^˝é•h©ěFý'1Om¶…¬Ďźö9} äńô\NŃä«ĺ DQżC„ăĂTLJ–Łô6Ż6éw;ľEVWŠM(Ů»´pşŠ®ÎŠo+ÖŇÔT‰_U>~™ Ě j˙¨Š`;źĘ) ‰řrŁ˘†iv›V7$›«p属T©iTËőLVčęç×ÚČb*»béPŃUÉv"kŁÉ¨¬<ĎÝtęQŕír¨¸4âő×.;g—Íc«¬ť«BŽa%ÎT§ö Y® Oá9%„ËčJ… l^ŻKOyJö|8׸ř jż: 8LË>n\L*Š„S{Ç„ TÔěě|l1ę®Ě‡*~Ű$€Čp-j:Ͷgb·X:ÍäŔĽŹrZúřĐýżÁ˙ „Ž#`=á8wş˙öáÝendstream endobj 473 0 obj << /Type /Font /Subtype /Type1 /Encoding 478 0 R /FirstChar 46 /LastChar 120 /Widths 479 0 R /BaseFont /JTFJDJ+CMTT10 /FontDescriptor 471 0 R >> endobj 471 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /JTFJDJ+CMTT10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-4 -235 731 800] /Flags 4 /CharSet (/period/slash/zero/one/three/four/five/colon/c/e/f/g/h/i/o/p/r/t/w/x) /FontFile 472 0 R >> endobj 479 0 obj [525 525 525 525 0 525 525 525 0 0 0 0 525 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 525 0 525 525 525 525 525 0 0 0 0 0 525 525 0 525 0 525 0 0 525 525 ] endobj 478 0 obj << /Type /Encoding /Differences [ 0 /.notdef 46/period/slash/zero/one 50/.notdef 51/three/four/five 54/.notdef 58/colon 59/.notdef 99/c 100/.notdef 101/e/f/g/h/i 106/.notdef 111/o/p 113/.notdef 114/r 115/.notdef 116/t 117/.notdef 119/w/x 121/.notdef] >> endobj 365 0 obj << /Length1 1673 /Length2 9586 /Length3 532 /Length 10539 /Filter /FlateDecode >> stream xÚí—eTÜͶćqi‚»7ÜÝ-8  ‚6 Ť»Kpww'@p'¸CĐŕÜ!„ ™Î9÷ľäžů8óiÖĐ_říŞ]ĎłwŐżÖ*:*U VIS°1HlçÄĘÉĆ)”VŃÔr˛qčč¤! #'K°ťŚ‘HČ)(Č ”t6rq9ů„xř„¸xt@i°˝;ÄŇÜÂ Č Ířg?Pұ41˛Ş9Y€lˇkŮ5Ŕ&– 'w6 ¤Ť PýO†#P䂸€LŮśś@SK' 1ČÜŇŔţÇ‚ťČ˙ď°©łýą€ ŽPS@¨IF Ô˘)ŘÎĆh 2°żCµ@P'˙7Lýçâ˛Î66ŻŤl˙,˙§I˙۰‘­ĄŤűMŰÚ;; @°)b÷źSµA˙ö¦2µt¶ýĎQ'#KI;săß!KGYK7©ŞĄ“‰Đ â úWdgúź mű—v)ui%MćoçżĆTŤ,íś4Ýí˙YôĎä1ç3C›±tľç`ăŕŕ„N„ţţű?ý˙Đzeg6µ´ž^> bä€ (ń=9–v¦ 7 Č ę—ťÍěMB[â 4Cv“‡ČnoŮـ̜ţ ý;Ęů_ŃďŢ?a » ŘÖÖč9 d·p··Ů=‡ř ąĐM›>‡€ě ř9 dŰţa^¨ '×çq^¨ľ“ô× . »Řňŕ†,]ţš5çmÚ? µćrůË´Aě ˙Q/?ÝÎňo#*´˙•$řg[Ë˙ĺ¶9:> ţĚ˙|¨ g‹|P’ĎŐ’~&¨Ě3AE^ýCüĐęĺž ş˛ü3AËVx&hEĘĎUPy&¨Âëg‚*Ľů‡  jĎUP&¨‚Ć3A»ŞůLĐŠŢ>T]ë™ ęÚĎU×y&¨ú»HÚ<Ýg‚ć=(Ahžń3AóLţ!Nh˘é_­ôţ9"!´óżZĹ_­Äň/„ĘÚü…P]Űgä„ęÚý…P]đ_Őµ˙ ˇş!Tňţ9•!´…N!´Î!Ô•Ë3rAuÝ˙…˙űu#%vódĺ˛rqsC?.č‘đţÓLś!ĐÚé_÷8ôĘúo6ł„Ţo Ȱ46˛Ji )óyU0UŽČ+eŢűşľűkZŕb¬Mń’ÓZťÎ]E:.Ć.â.Ąë©cx»—ڸ왿ClęÜÓ®‹ánşG ©ÎeşŠűŽ=őMŕf[ăěŹc^Ř73kŁe‰ď űłÎŽňTd4÷W¨`zŢ»|îÉâăבM·y\GĎMĄŽ•ęPƺꊕʰ:čcŠŇĚĽ|nwĆą+@ÉMx2€ą5AŠŕ’Ę^lš´ MgĄ`äś0Đ'Đ1ľ;÷ܵł{\¨`o.ť%pn>ľt˝`ÜĆ«Äd2“—ď R";ncŐ»‡LĹY›ëĄ§Sđ^Đ'˙d1TLâ7µŘ°cÔťż±9JČJÄćĺBDËŇťůA’}źH»bDŰśý”îŔÉ-Q'˙3XbůśŮ7ű‡5ć&çÂśň}xyëˇă.¨u”’ŕ•úŘ‹“FáŮZĹôýJp.µÔňţ7ŮF%ëlvä K‚‡8ŕ|Ř´˝®tŢőÎZ SŞD„°©1ú¶#“Jµ-ĘÜ’Ď ~5ńaG+r2¶Z{Wízc±P Ěňr67ÍhŔ·sjłřć2Żkb[˛cŠĺŹf;ňÝK=‰Ă\śÉX÷҇¤!\ě»’ň®ÂłÎ%ô>x4aZ˘$ÄýÁuL©!ȲˇťëNKťŃß%Z™ş3|q2RWßšř'ÉRĹ µŤüJﯪK …¬3Vĺwt|ž2]Ć(«'ăÎél +˘0żÄ*fÂóJ37˘í`Ď z™=ÎSÚhżĺs÷ËQŮő3$W)$•ý5¤ €ŰëQˇcíÔâZg€ůµ[)ďčźó‹O5Îśl{ČĘV©?î‹÷ś6Ś”¶n-«l©!żF‚ŠOŃHOçkÝ™Vďý«TašŇ<5ĘOQü–;Č6ß9`ů›ý>´w—7g´q2ąj'mw[r±J %·:fŇĚ3đcś\ŢĐPm'«I6śĺ@'?lIL­9†aŕjűŚŞ÷˛ P•+G@6‡˘-TcęW ů9ţöFóh8§AĘE014ë¨Ń·’ۉéŹű#6t­¦žŚb–dsZFoéîěó1iăřSK©ŐúĂË,mv”ĺ×°Béµ 49Gc[^`4ZĚ3{¸üŠďźy_ʸ)®݇ ¦]˛˘řčA0‘ç”đÖů‡]źP¶çVÖ—ąäFĹÄVtĹť]šŻŁÄ(kyÁv€ľíꔡkÁ®Ú >ۡî˛%°\n­L÷đ‘6»=˙ńÇw0ĆŘÝ0Y/ěŰÇ^˛¬ťĽ"ëĎ“ú#Gnا% d†˝™“°WűˇWńuß›ä*sju —¸} _Pş.xD<….śWyz­µcĆ„WAÇ WxébŮIĄ5h.ö¸[×:Ť˛ŐNüćU‡go·đä¬Úşüsľ|[Âcť4N ó o>ĎĚIgŞ„đ^Jx˛ŚüzJfiČř|QůĂĺh>fą´[.A6nXsVČň|¶9ztBłi{2˘ŕű<ŢSĺęjcü鼋7vÁzÖóZD™Öľ´Á|`Mb^|1ë€v¤‰ŃTdů˝·"Ö%ko‹˙ ¨ťS˛ł,S@d–§5R¤Ěy{‰ŻŁ^·]Ž_ŔD;Ĭ|r`%5úŞ] ýŢ“G@¤WĆ–ŞČfLŞJ^NBxűt!7źÖ §JB/N_zů‹Qˇ3\赟’ż…zµúډl(“5!nÚ‘¦b, ¬€—Íĺ”/¬qśb|¸Şźř‰eľŐ/*=0űí†DűpFÍś_ȲÎę_ž^8;»ľÓĎîć+‰}U‚Ô‘@ˇ—ż·Šňâ±T ‚%)n‡#ě—]|;şR;S°E|`OVÉ]§Î›ŘëĎŇËű r®öą§‘fÖÔG‰žĘ<Ú/w¶äëeąć„®îľůĂĽx97˛xßÚ‚ÎÓ÷Ľ'˘Ńěrë:vD+r¦aŐ6Ń~#6~ ^BÎ2€ăŚžđ#>~˘SŻ3ÜAq= Üł2+cXOÖţ}¨ S1>cΓt›r*Ąďp­ý¦ßVŢť±ŮŞTcôŇ'Q¨ÚŰů(Şhł–ő`¤‘Ă8ËŚę×ËhÂ9öąÍđőĹBËńä†1Ô¶/uî¨tduĹoři»oO¨ZßDO©)ń”§ż‹üá$N»ÎÝ ř^´·¤§˛®$şŔIo˘ÂâőŹť,Lśc‘´‹ßËĹŁçáó9äŚ_ěͦ0 $g8&‚XÉ. ‘óŻřĹ~‡Wq—¶5Ę54nIŕá+ ą´Ęöđ&3óĹ ŕMł-Łú¨ßh+Śóôťm0~gnâťśüüČůÍ2);KNŘ0.Ş$2Aß`1Ý5LÎçřFůK 9B3.üî+(–Đ&xű@]5ă–í[«rÉ@ÜÍBq+ď<yv<.UH–¦Éš‘•™R< řÔ©ŰIhEÁcÖůöŐčPšîÍízť­~ŇL—ăč%Gé‘ĐëJ°‚é¬5D]EŹ>ž»¨ě©«BĂ5Ş7Xß4QzOĄ!Ŕ7ÄřÖ0†“lč缯çâ@ĹO˛cÎöŰŔ4öä Tť–‘Ő+vŔÜ‘#‘Ěä·˙pô-Q•»‚÷:ąlH1‚8 ‘Ě”$ëóńŕ:OˇtP·ëftöˇ[P üLÇ}ť‹/a¦vQ ‚1{ŻĄSĎĐ<üz ů ^® gŻ–ÁýBšq{Öüéľ8 ¶óę°Żľ2^ÇۇX—Čš‚MqG+±ÎÜ]K… i0Nűű,‚çŇ@‡Ş“YâcŇŤ>©hűE»lď€řŃË4űµ‚lĽT)ÍžqÄ'ď«/÷2ŮĐ—zg6ą±óŻ80@Ç<žXłMŇCLZ·1Ébk`4ăwSđÇ®ťąęĽ'‘öTĄ8NLţ/übÝăž _şhĂĄ|ŢnĹ˝«]µ?tßîŔЎČďâÎ嬱ýÄ»ś\˘»€É´'j)ŠS4ŤDoMČőŽW«&/I€Y™ŇÜoŠ–°”„ŕkĚ´‡ňu;BŠôÓ<۱^ĘÄÍ›ůXŹ$çŕu[É„űŚ8Ľ2R «ć9DĂČŰË,­RęÖŘ3¬Dm-P~Ţ®öěĎośÇ¨ń CćxXüJpl€LäĐ7-ˇ4Ąű¦ĺĆβps௽JĹë©ýÖâ”OM¢.˛Žš]g7…M÷ţÂxm,¨_iŐ‹Ţw„P¶1'5oÁű>‘⼒ V®ű©IH(Šĺ©»@Ň:án’7ëťÜĎJDG¶ 48Ę|ŮT¸„żŁóŠ-诎ŞRpB?jôzlѰˇtŃ2ó?OS 56?ž Šr†°„ĽřÄŞ¦ŘľŔÜf.•ř8·¬wQ&ˇş)=úSF"”Ę …Új1nWŞň0BvŁďżwŔw:%lÉbę‡í™ćśśśhî%ÉôĹ ˝ôţĚŕ‹:őď$*(jć·NeZ"Żŕ3ńiČkU–YMŠh§™r_řč\=uŃÖŇ ĆĄôTňë©NĐy˙ LşŞµ5ę(~_J× ům ly’ŤJ‘ÓĆXŁLt§`Â:”Sľ§óHř9ŚĐÚw’ň«A©á 8Ć%W«90ô|ż×Pűpú*ľAž˝Ą4™öm—YfËÇV+Ôf¸§ÉĂ=ľń˙;3ŰY‹Đµ@tĂ74ýŚTă@ěF‡ĆŃ[Ä:DPJă‹9bDłRú|>Š”Ľü^ň¸o…yΧń(­1LĄáŽ|O1Á]~ŻŐżđé!Ď˙Jř,"sůNŽu…?qĂ»đ öḷ>“ÂOcĎoȨc¦Gdť*fgąź÷×÷ŮT3űŮ5v´“˝)ĺtňś+Ă N yu\šb}Ö ä\ś"Ë´«9miq’”˙bßjpń“¬%ô“IMKďßHˇŻň|Bř@ŚŮÔÖŐ^‡BTő-IŤů‰y8Z×púűÄiäkĘ`8¬‚ ĄEUÔűÇz•óĚôţřúď°˛ŰQd>x­¬}kźx ?±mÚ8nŬ…iťDësY2IH¶^}•íýôs@YnD˛iĘŚÇŮ1'+ü€„ĽTÓ9&¨Ĺ€uT+⯶‚mĎxŃŤ^­&îŁĂ Žć±5ó^[e[4:u^Ţ·|RÖ±ĺFuČói­:jěµ'ÔwV# É‘D‹ •É™uXµÇ ­T.…Rj–!úÝ&:™®s—ÄÄFG×W JU]|2äŘ Ş˘Vć-ć<4˛Ť—<§V¶C wžsśĘ.úʉagŽ(˛Ed^ą w5Ůĺ?˘EńĂH}łťöá—yÚĚc˛e9Ćš@Îą•ÄL§ ڧö]ìmť(×A˙čí ł¸†ń»l_O˙{U™§ă}b(*|_ß>É5 ĘҨsĺ'yĘ“Á¦u’)6xE\†.ˇ>Ť/ËúŰ‘gďŚ@kĘűŃmü•SĽ›3FÍLhĘiőĆłwn z˘"łĂ*íq 6)ąŃ(ǰ(Ű%ś6É6âťąaM(Čì6%Á¬ŢŇvőÄÖźo‰Ł8µł÷:-öjqóJnۆCt3^żd0Ą!ÝĂŐ˛]8ŕĄěű1ł1©2±„EVˇŹž.1mŽŞ1Ż–§ź22ĺŐŁWöŰ‚·ČĹěĚď„p2Eڶ˙z'“­VŰ?Đo®Ĺ7Ĺw“ ő!/ĘEýŚDY™ŹüҬŢy÷ÚbŕÚ–?kX-ˇHXŤYă·č¨Ů}…Ůľę§IŁaĘÉ„™y×vľ±Ý»lçLz€‚zÄí_™w\lFHeçQkL/ţhĹ­K}q0—Ь(…”=ŮĚj„K \@ŘĽ˙gđ»Że|á‡Í˛8·›ßT^t¬€LÝ.…&ďZé­Ë˘¨éăý)Ý•[Ú<¬˘»»¦Đ Í˝Cj_ÓŞł„–f(ĘuSŕ=cĘŰQ0#‡Ŕ\s_˝ßó/ď%Ú.Fęe‹läÉÜ´¬éČđń[­ŐîňŚř¨ŔYĆŹęöä”ó=’g‘ÚWj>z(Ę!‰îęÉr€Ľ űzUő^Ěą®['ţÍ?ěĹ$>"ąŞ"řµ& dOäEš0g'a//žű@“PôŔČŇĆG6py&şs͆8›s-ÜšQ†c/wÚ[Ď^đĐČo‘"UC籋ĆÎů"‰—ž±©;g¤ř* ąFîďMůM[Ł]Dż»Ą †ĐXŠżÜjÂMç<íÖ19ŐŤ2Dˇ?rtţÖD¦‘~.ŔA¸ÎĽŹ“:ĺ®Ü—ɧKŔjÂbM­ó0ÄĂH“­ŤäĐĎbŘŹáĚAŐ˙UÍŤ´\GĘĵřţ¦Ü§öý±‡ż{$wfŁ)«oO€T¤Č1†ĂzÂŤĎK«jťCżě0)ßŐ«’Íűٰ$…éÁErO_‹řęVĽńˇ1Í'lŔśhß›%ŞO€ĘaS‘¸”µ+ÔYn ÂĚ҇*ţ˦d,ŹÚŇ"¬Ç2ŞTpĘX28ŇôÉ–źÜöá+^źR=©%yůž|‡Va¦]i®¬•ń…4,\úĄśŃµľâA—Őćě%Ç›đFZ=7\ŹŁż•”§´°Ücô˘ük‰aŁmÄaf Átk¤Ď[ż•Sp<#X˝żŤ_ $Y˝ÂĎHú6^+f[ü©âNŕ0ĎŢÁrŠ6ëŰ=[ęΫăó)wWŘ3>ěSř‘-JŃy¤NšÖPíŚ÷@ˇô¤ßS~ľ>Ł˝¦*ę°dMľJ—'ç´ęˇ{AgGŮ«syŚôM])’±&^ÍĄC=ÜŘW 0;…É™¶x©ˇ“î´ŠĂ“^ă|Óz¬iýźO ;áFîq,Ťˇ§ ľD‚ÔI/©s÷ig:UHěőQo­A*¬v-‡Ő ™ä‡öµţ8Ľ©4˘'_v^×6s»nN}·Ĺq3Ă5šÝ·\ËHG 0.ŰďŕTĆÜü#UÜÚ“-¶6zNMr·ş—´URÔŠoĎv3¦±ä΢‹´2EʵŔmx¬#YmÓc›G;­z{ŻŤg¦¸2t¨Xź+­| żĚݤ«;1–łÜÇ˙ĐîTz'ND»#Îűʆ î϶OšY– & ç^uŻqëúş óƸkqx’D]®…Č»YçÖ|ůľ7-ëŮ âúĺ4ůJqm·*›vĘýe5b[­ŞaUDĐ”°hőŹëi˙|·Z…°ĺ*ˇczÔÝńIső3ă=đ#®D‡PnUgᔤ¨`˙ťäĘía®SUŔ@®s™č\č¸V’÷tvé aú›RUújąĐ±YGą:jQVšA»ˇs°|8ţ]¦`v†öžaáz®J5™ŹµËţŇŘ•úVĐ<«Éš&=i´c;ő±č›)°ŘÝ‹,fI´Č/âÉŠ,jC°Öďů'˝8|®ťu™—NÚyW(߼_aţů3U`Sšš•>Ůí’EŔOp… Qř±¦űRkMŘ€>ÓŞÜ}€¶żw8bcľŚ÷ĐX•Ź3W÷ü› usÍo‚xęU@·‘Ř+I‡şÄ‹Ťâ„ŠŁ#ü]–çü1‹ČŤŠrH}ĚGáZîn$ë3¶ţRQ>%qëőB¨Żňő,0HĚ2ĂČČY0™Çę`xŚ6UŽÉQ@M¤Ťš4¦yžźňŘ81Î5ŔsŚ:Ŕěź› ó>Ţţ»â{ <©űá^tső&DFi!‡Č:ťg{‰Ć”*ž08‹*eůIPކ‡Ę˙ńG]Dń]n…Ź—r®ß¬˛đ‚ł$ł#QCGµBü)UÖ~͸UěPlđ\^řPl8©čqÍzzÖš,tŻ•BţË!®}îGAť`ůz@xŽÖ=cÓ÷Źăź“đ7‡9ś‹gż"©ł—đY6űTzeŤÔ„^¶Łš©\ćHŮk‹ňUą0ÝĐ(ř´ŁEć›AŃłN®Ţ#™5[J}¬Ž)3LH˘ŽA‡ĺóŐa'H;bŘ.÷–Ť6±Ĺ˛$ď‰^ŁÜ¨ \őץŰéQ‘çFM°(aď¸|] őřýÝWÔËI®ókBÖ‰Hڤ”Ú&p%zúĆ0ô¬uPG•Dë¬ën?± ˇ,ĹJQĚőÓĂ}¤—'<˙™Eâ*CĂÚFw ލěPĽÜµĚTĹG2QŰ ŞźĽ‰Ĺú…s’–S†źrŞńw’¬Ëř0%<Ły[ĺ4ż,nT _Ë=B‰TRÓ¤TŽŐeřňśŃÔk­› %púÔ;ʦgxŹWUÁĹWéčľâďHzĹ~xú`pÎő“Ťřä1 -ÉÉt öEl'Ç“±x1¤Ő ŐÔ”_ľâĎ ű1ńĹ]b%ŞČŁĄ÷ !.®Pclęfs~5čişk–ÖÉöeËŰžŚî$GĘ!"Ö 1Äcž×ëDŠp[Šď[±h´…Ct‘Ä7lĚĘŢs]â ś[Z–ňh3ĎŐ¸­ĹsdĂđ{bů?Ľ>ҰhĆP±övĚ!ňCÔ[ő'±ď2ßeNľ%BgX(¬ž™4*:lÉ44˘F[pN¸ĹŢ1ľgš Ps¬ýĹ4ńrˇnŁSń§žđşŻµČøŢ#ë­/äňÖŐ ÍC>ČA”ĘTůŕ­AKV7UŤ^¬Ň=WęQ¨G%ĚJ.ŽBYâgcQ[ď:Ţ'Zůaȵ.SQŰ ŚŔů‰ź?y‚Şz-kĎwő"=§Ś1§Îd©\ŕ\=íć ÉnÂě†ţ ‹z$LnC‚jĚEe—Ľ¨ĚP{!`ľŮS–°-+ńSt…%ydX‰ÍÍH•żÖţCYYĆ•ň9ú{/P¬M+Mç+ő'‘#„¶"1ŰK'z|˘űř—ʍţî?ů~çűGµűá'Ë *‘W×Bߢ;“J$ďx6«‹ťŢž<áî®ţŠŽ°ną…%7×MOśňaÚ!j8©©Ŕ‚ĹâB!–˘˝çĐĄLÓĚg˛éšÇ˘‰§»ŽÄZ[%ÂI+ ?@Ěf0 Ď|)ňľgąÓÄř”Zy ÉĎßf·V%Ň=ş” ą§3g¦Ż±‚‰â’žť ůýY­t +á €Y@ŻĽfę7űŠ%vm®ţdKTÄo®Ňg 1śťŻÓ?Ă艞zÖtmŠĄ|Ąű&rl(.+ţËËXřŕsÂśęŠéq‚uĆžż@ývÁ;í®Ć‘ Ę´XxěÓŞ%:­sË“ößÄÔˇC/q‹Ź.ŚĚ+7•—&‡äëw2¸(“Zű‡C1Ą}š©ÎýcZf0JX4Ů*sŮčé°8ĚŘ=.h»vô›|ŢĆ+Wg&~`ŰEĚJ[Zç~ĚźĎÎ;Gżz쎄±ćˇDf+ęĎR/™µ:yz˘"s‘ĎŇ)ĐDBb˘* _jÇZł­›m׳ęľ+Â6> Š[hťŻzĄX®ţ4e󋉖’őÁŢxá~×^őJŃŃ” üĺ–öÝÄ ^ĐĂĄďŠ÷Y{Şy:bôćĐĽ?CJťÖĆí8lÚ'yQ»ôΓÁű7"µ¤0)úť©’eMů{Ł9Ű}źŚ%DIúLÓFĹřňß™4’Cc¤Śü^Q„żoĎ6!{tŹ®„ŰŔŇ[úµ˙iV¦~'ňWąvÝUL~©V#K©N–hŽL”C›oký#ćkHńç©\#˘ęť,67„;˝KČdú˘ű”ĆŤ!)¸ĹÍŢíűëx®ŇO4…¶UlľWAťçj”#dˇóĺZłk÷u% @łdxĽ ^Ô©dë׍őžż ‰ndńű ôý™(äaÍąîöWŢš+G@¶ŃÂú.Ś›\>˙B*icěVâpÝ”VČí7‰k„´ő’Vn}łúÚŽÁŢß»Ŕ1˙4c^ż4Í%¸®pĐÚ2N…˙Ěš#LD߼۫CŮv=·:)QťyŔ0;Űď)bn#±dIşľČv‚Íć­cV‡wËnżÁV<„W"f4ě)ľ´mS4ÚK§ôĐ9a“×WéÓzŰ€2+řž|Ţâµü ą°á0[öŽh%`¶{÷ ‘Áw§|Í…ţéô#%Ű«–f%>fZ5-“—ńʰy€ĐşćĄ»w{ű¸…řşÓr’4±,#nl?ŘćMNOžj'%čB˘b×LݬR!˛<Á÷yq˛€+q™€ŹĘ1$Ŕ\ř "GyÁ¤»ËB–ß‹álć+R>bAWÁ<ąa]°Ěď–•™1§Vë(¦°pęĎYoŻU($1WÖ(Kýâ´E?ŢűÔŞ+=xVüN®#)ÎO3u@cĂéÁ+‚!§EÇ2»uxę{§ëGWC8.đ@źUÖ&˙ŤĂEn­†€Ż0?§‡Ε?G§ź,śňúÂŤžÓÚęĆhtOihrNľŹ÷Ö2fĘ2ˇ®`ŕ@MPŻÜ#ë!eG„B”Gć'#Ľú“A¬'΍Ȧ¸ôřűűÖ©'ĎčŢ‘t{|7X ułK=ÍdÔ›»ÇpgtYΞč bľd7I‡}͢*3ĘHúśvĆüŁY*9¬ołź 貛a%T¬#Ë«ç„đĐGj„ŞH`K«ź ,űµf5?ČůĚÔ>aöÝ×Ü(&=ˇ¤ňý ˝öÉk”ý…YČĺďŔŞÖĺ{ő ŔSŻ9ެĽFF1j }‡ov• f¦Őí´¦ÜOës.‘GÁJs_ÍrßÔšńcĹWJň«?GąÚ ÝvŤ;űfË’$qyXw¶ÍDCű&¬Ođk~QÎŮ[™m\ȧĄň(§Ą_{MńÝśçH§Â^ď_kâÎ#pč®” —.E´‹†"#ŮDžśŚ}ÝßÖi±üü5`>íŰ ŁýÂŘG–3‡ËĎI*Áד!·×ă-Ô}!/ †¬ß+č%˛álWŇEpř´îÔ<´ĹOL ľeѵ ^e>béŢ-x…šř^Î*bŘç"EdžŐôĚv­juiőţąÝŃ0ĺ®1}«8nLó@—ń>+ &µŞF¬ůOŕú|Ľđą6lf„ů±h8ŔŹ]ĘĹÇ<»S^ń’ż–ťES!~Ż.J©i™ŔżĘiHëĆ+;čB›¶PúYą€Ü*ÁNČ!]ËŢGm„GkËv7Ěď@éÖš)ńÂ'7XMR”±ßN㻸¬ó‡8ÂĘ–ü»Ĺ¶ąĆ»±äË–ÜcĹZjÚ ¤…ŢJtŠovőÝđšGĂ`$ó‰ ˛®Š‡MK ‘?ŠŻTÜÇŕb‚±Ň™ßŔ7ŃZSy(BŔظ˛śMůA´Çn}â~oëć9VřNľ«ŘP 5rř Ç*—^´Q8ţ˙˙˙'0±AśŔ¶FkŔ˙ähĺńendstream endobj 366 0 obj << /Type /Font /Subtype /Type1 /Encoding 480 0 R /FirstChar 40 /LastChar 121 /Widths 481 0 R /BaseFont /BRXCKT+CMTT9 /FontDescriptor 364 0 R >> endobj 364 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /BRXCKT+CMTT9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-6 -233 542 698] /Flags 4 /CharSet (/parenleft/parenright/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/greater/A/C/D/E/G/H/I/L/M/N/O/Q/R/S/T/U/V/W/X/Y/Z/a/b/c/d/e/f/g/h/i/l/m/n/o/p/q/r/s/t/u/v/y) /FontFile 365 0 R >> endobj 481 0 obj [525 525 0 0 525 525 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 0 525 0 0 525 0 525 525 525 0 525 525 525 0 0 525 525 525 525 0 525 525 525 525 525 525 525 525 525 525 0 0 0 0 0 0 525 525 525 525 525 525 525 525 525 0 0 525 525 525 525 525 525 525 525 525 525 525 0 0 525 ] endobj 480 0 obj << /Type /Encoding /Differences [ 0 /.notdef 40/parenleft/parenright 42/.notdef 44/comma/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less 61/.notdef 62/greater 63/.notdef 65/A 66/.notdef 67/C/D/E 70/.notdef 71/G/H/I 74/.notdef 76/L/M/N/O 80/.notdef 81/Q/R/S/T/U/V/W/X/Y/Z 91/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 108/l/m/n/o/p/q/r/s/t/u/v 119/.notdef 121/y 122/.notdef] >> endobj 319 0 obj << /Length1 1171 /Length2 7454 /Length3 532 /Length 8205 /Filter /FlateDecode >> stream xÚí“U\›ë¶îq .Ĺ%‡B°˘ĄĹÝť !@ÁÝĄxq-Ĺ­Hq‡Šw((Ĺ)‡9×Ţkö¬}yÎŐůť$߼ăĎóŤ1ÂĚ ˇÍ%iá`•s€»pńróŠĄUuyy€ĽÜ< Ôüńáń'ú\P”WŔ ”vpôDŔ¬¬]€lŇě% %íˇ Ş‚]¬ˇöŹ5 `; ¶uńäJÚٵţşá Ô‚:CnP n//ĐqšC­`pč/OŠpK ĐżÂ®Ž˙}äE8?š˛ým“řhŇÂnç ´€Z@jŹjĐG/˙7lýgq9W;;5°ý_ĺ˙îÔ˙8ŰĂě<˙+ĂÁŢŃŐŠŞ:X@đ˙LŐ‡ţËś*Ôćj˙ź§Š.`;Dnerń póü+s–y@-4`.k %ŘÎúw ·řO'ŹýűŰHKGCRCŤóżFű÷ˇwŃńt„yţÉţ›y˙áÇ&!`Ŕ7<Ź]ć}L|üţ÷“ńÉÂ!0¸ďą Ś@€=ŹKôHĎŢĽ@Üę„z<:qĂ\Ż;ă ´t@ţšëăčA–Çţ…|Źű7ň AŽP wůwLŕ9díéh …˙;$( ÉüC"@ěżI豄ę?ô©öoć‚4ţ!~ Hűßô¸3 đ?ôXňŹKžÇ‹ŕăK@˙Ŕż^âx4ü>ú‡ýŹ:¶ŕŁA»?đQ×ţ|"ţ>ę:üŹşŽŕŁ.â|Ôuţ —?đцëcxňř…<˙Ć˙ąiRRŢ\Ľ‚ü@.ľç<É EE|˙·L+ń8Äż˙ÎŹ űßl {Üq(Ô ĚĎ8@ÄBlRÂJýdóÇĘĐŮťiŇ‹Cľu„ÖĄ‹qď-‹O!Gu t'DˇD6°r”_Ę Ëç+” ’>}ŢÚ Đ9˘>žá@ÉI;RÄ$Ŕ^”D©1†××–çBRP›c×Ĺzf<1şúż±U ‰uó¤Őmř׼"ŻşçăP|łaÚ‡:‡ľuő¸yc»/˘Ń?ŕŤŢ•ţ–¨XmŞP6¦Ł¶ÝYĽIŔě“*öp.3µŘ"Â~:9§Cąë1_I;r‡Ľĺ¬#AQŽú f()ÁTDGcoDdłůÍD3S¦†Ŕ73čćŔߥŻÁEżűŃ~uŘTkHĹ0<4&ôqH¶Ëُđ"ĆçůYňYülµť†‡ĆHş>Qźđ=ů4šµ {8Ë!iboßűnMě‹h:»zTŔ—ű)ü¸·ő7ŤŁßŹĄ,şâ°ßZ&Ą"ņC9–IÉ’oł,Ő»—(Ý%C)śůU×éŢG•Fž©ťŁÚäÇšl"ZČ»&6ž×*nÍOhŽ@đ# ín?Éš6ŢÇ[-‹pg§Ř‡>8_ćD?ě úRáŢG~„s~>ř6ëT¦űăa.‚25ßÖÖ@wQf’N?´“Ťb›¦ ™tT‡!űć|ĄJ7 %[ę9oš€/wu0žKĚ®čŰNiR7ľî× $Ps„ eOžp:eÔ]!k;OČmd¨żó´ -{ 6Kv0R üŽßFłÝ˝ ŢҤ˙‰¶<»KÍĎô… ~Ş3nHAe±(iKŁýíXäyx<{•ŇŚa•˙ <[¬@ËÔȿΗ!ş6TâvaY*qä÷ŹFË4Pß’ şˇĚőH0ârgĘŇ4ˇ\Ů×ëEąÍ/ś±—źvdv6lďü®7HR0Uţîł}Pę\Óŕüç˛ü·:á©Ďd‘Ń”F—ŕL4ϸŽ,Ŕj?ű¬ş5LĽT˝ŕ?g˝Ă‹Ą»˝ÜLzwůFÝ»‹Q΢]ë)ˇ'7ooKeV:U_·›“ńÇp«˛SN˝%F?ă©uÚ±řb‡p ă¦>Ăj^‰BÄÁ¦cQÍ ˝…L=ç]©ŃϢP×Čö ßß&Y¬¸žř-™~es>")|ÜŢL0ă3‘2‰š÷&zó/ô jTä>wdçő>±LŘ*<‰k†¦2öě{HŐH5kĽĺ±*bä?˘ä€rR¦ŘW͵ô›5fÓ™IĚ–đGÔ1Rď{Ź~w×±¬µoÓŇŇONÜZ~>mɰp2NÓş¬Ę Ś–ĆĄňŠG÷Ü—Xî_ěÇ’đöŇ„küđŮß ›Ĺ«ĹfyiPH”Ĺ”~K˝ËK«b›gîkú¦żvŐçtׄGÄŮŻ[f ZµŠ˙lFŞźK˘íµ®@”çĹ`™˘šaĂtI?‘żÇ]ZSÖéoÁ’Ma4pħ-RĄ­ľm'|{|bnE4°ĎaRŞG‹äŕÔ5.×}ŐúĆ’ÝĎě‡ű%5–bĺD°Ĺ"ý? přGÚŔýÝseA¦.zvHź€;Ź^ÖS ßt ˘űŰ6 ĘS´ Iě#¦vĐčŐ·˛µ „q»MOîi”fíką°çŇʦŢä!Q˘ŘÉ\K4>ďřZ?Ĺšb‹ĘµwDGMéXQ‡,ś™ťš7ÔŕLr ¨6´“nŰIDxŠ-éΠázěFg ¬t•ôµŇfúĎi+‹ăgĹm#˝Ćh3\XŤ|_0©ů ŃvÔŻŽqxM‹:NxVÚ¬Űüó‡·Zé˘\‘`’ěHW¨gˇÁwô…7Ł ąş7vĘ›•7#>Ô}+ŞR–UůDđ»ťx?+c0HÍřľxŔ\ç¶§6îÇ=‰˙Ěe¶-x_Ú7t¶ĆżMl„Dň\}ő˛a•=ńžÖ‡ż•ma îD"Çá·äě­Äň7ądŐЧX€ş>Qb“ Ż™!«?™4$r>™Ôłi™×oY&ŕjŢő XűĚv9#‚JîOž㾠$ĆĘ.´[ŔŽ븢~Ő†9ľżbŽŤÝwţíě˛^‘4$oo¶™«FÔĚUşs®'Ýž˙bňsLŁ= ăAź!¸-:’ KľE$Ô‚®Xs×%"NB˙Y˘»h•ÔbérłńM°ŹÎđËصѬ° 7“(«CP§Üa.VÄSľąľg”‹¶Ţ&žŻ9m˙ÖÄ™-ţvh‚.TQµŕěňÚńňE=)¬[ŮëůşŹ¸y­úÍ@›pő/Â3íâč´Á{gŔG˛¨$ZÔ•wSŽćw#q 3†ˇˇČbSY Ž™Śű4EŹ•¬]ČÍÜG\ćÖp…#'Źe l©MŞâ>Ňśk X|.Úâ­Áwqw–‚ {WFĚŰ-§ińWdÜŐĎE}p1=—ÔW%±3ř.7‚ä{é°(Ä%%˘uĽżů‹L5ó ™»ëäD“¨ź=;OPđŽl—áŽ"JîÝ@>}‰ă;’3&ăšśť®:j)łü;v9ż&Wwšíw,:¤Yľs='’‡‰ĆYÝŇgŇáoÔ š<MMÄUrWľ{“¸Ý#I0?w J˘Lš7µ“ńwUzéGő2ez){çöáµŢäú÷EŚŕYŮÚ{™g^q ¦+˝kĐOčŹ=űÜ}ľ5kr)*wŕ+ÝgQmŮz"ĽŰńSy«Rj­]"BLO›FĚ\–‚x§Ô@şSu4ŽĆ^ź>äWź¬4X ¶V' ˝_$NŚb ŚkőŰź‘Ż©×wžh Żî6*ťś”ďîL+ňy“Úb¸ąBď5’ë&TýĽu˘r?~EÓg`ßf¦ňdŽ+|ůž#µ/ÓţĹĚŐ"ďÓ˝§Żf(Ţx±Á4P>4äÔčOéíµá‡n4e’ŁurőśaßEвhÜ`|JŇłÜ~E¬Ü2(+ĹTźČtĄýȧíÚĺT©»¸żU˛ŘŐnˇNĚŤ‘y%µ~¸!3‹Š]ŮzSšoŠÜ>{9_űĚrRaI„ÁÇţś|Ďz§·A­¶ĽéjŔIöÓők6 ç‚îŐQK.kÇÉ ;’ŔW+x?~^&Z\~lś'ěXsaţĐťGŃMâ˘uĎsˇŞŠ×„®:šH­d ň°‹ŻĚ(3ýPq_˙ÜúŞŘ+©ůó ´~Çůö&qi˛*N$ľć5´Ý/ۤőVźŔĽFuĂ0đ#Úg‚±ú°fąMNŢn\š2FĹB@%}[ČăŢOtŚZź‹Éýj™ň¶&“šĚ€«7ŻTIuË˙îő/6źo­y ĎQ4ý}¤(q,D'·‰”ílעs.¨ŞťŔ|âßnťó[Ţ7-¸ž>jźîŽtFŮxP6Ž˘±IkP—y~‡ěQŮiBµ•祭Ŕě$Bś§» ÝWy¸QŮ(ďꎪхL^’S7EîśŐ„gď}ĚfˇęY…ĎNIh«ťŁJŕ˙‚ƇjĆíŃ݇ÓoĹIÔ“@éE÷­j#RĂ7‰Ňé–Řű0yÍnMË\ÝzĚ“śďÎűÓ5«‡© ®Âň¦ěO#wUťňąĹhĹ—łSóĚúľëť$n2m«§Ď2‰hâ{ "ę§.‹­ÂbýI›ÜO؇ĘýϦ ÂĄŚć6¦"^ďf|µĺŠşˇďĆóméBíEłdW‘…Üm”@¨ŐšzíBĽÍ;µť~áQŇ«d긾iž‘řhB&x>ä; cĽy“7Y±—Éfd3NěŰF¨2e†ę!şnÚĦ˙»cZ[FÔé”——Žëdźç ä[˝r~ŹóůµŤ»á°é¤ĚÉn•F>¤WčŐę×@MDyđÜtMuŐÄZtöPČeţa¨ůµOĂ’ä Ĺ‹.xSqë·Óě—\DíĚWi—™ “K2Ţ®A›±&žLÎföżN´ĆBÚE _“ętcé5ÜAÉrźgŃXp”*Nn†żézPz†ZĂ=g1fF©rĄ{Vş xí˝ęČéÚyеŞţ©›‰ ď3“IňL!×·üąK˝FËÁč® FřmR9Ë‚Q}żf9‰$מˇU`ÎűźĄŕ l… Đą×CUC6nN˘öו(¶JÖYëűa”‰“^ů›jnؤĎL¨Ä&<¶ż5~’»ü6™üÚŻŻaĹë)ia ~EÔá)u<`ăľnUŢň~fćŠ y(Ş{6[·h)uq"†%©ă\}˘‰Ě¬b~7äw^Ęš[ŇżB5¤"ŕ•Ű„_ÓÄŐˇ™ÔŔ~dmě"ţ‹˝YďÍCZ¦®MŕX[±H1łRÍëě.NMv5Ćŕ*™‡ÜVŮÍŞŢŞ·µŤČ»5K –ó+ý_Vč15Ňň'ÝÜK÷~öfעĘLŚxa´O^Ś37?[Ýžâ•U`űéj»¶PwYěżľ¦ŚÎĎ'(Ď {ÇácĘSčŤ=s¤ “çKź¸_Rx@úďXďäŰLmOK‘Ě1fĽYHŁzŁY=•:Ç»Űc?cťŰČ$›†Ô]_jp„­Ůú#Wáv }FŁÉbj¸oő˘ă´–áăgrv´őMľmë›ÓĺWDˇĆÓE»g0”ßĚ /F«Ź¬wčěŔ!÷$¶OPĚô—Ů•FÁŇ{Ć,<_żďRŃ%Í©9ÄĹÔä«5óGNúĄŘ^3âxš l°úíE—.˝ń"ĺÔîċ׮=;N8°ÄFşFˇ&p-ä<7Söó,+˘±šŃ#őúő]šóĐÓŁŤwžłą jŠţŻl¨m­Rlha·aů˝5GŠUyjÓŕĚq’ľë ڬ?ąÍN߆'j†/Ď0ćźB"bqS\ř3Ľ˘Ů›V­ă)_ÂËřöÚ=ŻŠP1ńůóSŤÎdq7z”>›©RĘťŹďjëŮ>b^čJ»cnhć[6~x!¨MXćŕŁY”m nŃ0FČ»ŽËşë?m*D}şQqmýžîLřC’ĺôPAP逎DńŹŔ­Dʨ9C“z*­?$“A˘¤QĎâoëlĄ‡WÓv!{d “01ś)-M™”ów> qs#‚%X%´×ŚĺXr&L/-Ă˝]«#űţ2 u|’doHmc°śÂ`rBĂ ”>Ŧ ŹSߏ”@¨'D›4…–ăe»?ˇĎ\IČĂĎZÎz¬c8_aO<4ň˛HÄůÁĂH' ˇlNÚ=$›Z–I'Ç_äűÜÔ­¨ oŽ26^ s®Í‰Ě 6“űŤąµUÜŃŽnI%÷|ŠaÂ=‹s¤š:®šVäs¤ä ѡí(Óh/ş8ÇÁRrŐ)Ďhꏄy}%tśÂLuíĆdĚÍĚő}ŇĐłĽĘóc¸¤÷U´%9rýśę#Č?3®(ô‡°<”6Íş4塚Ĺ0YyŽ’>’˙g*ŐHbP÷kĘ(iPVŹEP0A”k˘cŢkĆĚwľţŔ&@Ľ«,/1:¤çđýZ#n×óŁÂ%¬;°yÁcŕJ¦}ʦ->OßI¦Đ§O˙8§HŤ6:ăO',†Č8őňĺPidw?¸nď8…t´čÁ¨ ËnďË\u÷“ËËoÄ<ňóčŮ1¤T2Ô<ąĆcň˛~ô´+­wM›ľ¦ŃcˇĹĄď_ůŠ}žž>ăzi“GĐ4Üî}‹Ş5ë+ŢC#;wÂ|+P–Šz˛‰k~zduÇ@%˙<Ś}#Jë)ŠM˛5 BŠA [Üp˙äĆÄÚýEéÚ[üc"+CŕčsŞ>ĆP :]ś:G€ˇ/Áý¦ć[ôzk9=Nŕ†řg =šÔĹŁUýÓZgçź-Ôk q»Üc®B3ť]ž´˝›j֜Ñ™S&Áę‡6ĄJă/ĂmýĘF'K˝\żć:˙ë±ÔK‹”M^Ľ^›—1ęé7ýĽáh÷›I{Ę’Y—ŇSśčÍÖ‘ŘçGNż©*>)šÉ_±6y)X9qŠqŁ.. ř¬łąě펹ĽOठč6ˇ=¸!š8ĚÚ}A°•) Ł~‰L›)e6QĘvęĚ–W„uŘ$ţ.“._#ŢM–>¤Bąíô.Źs7đŞŞIěÝ~źyNDFAĂS*Ňí3˘ŽIÇ^buŠĽUvdgeŮäÁŹ»ůŤş $Ž^5öЦţů0̦‚ţM)—ˇŃQĹ4›üw:-ň¨*ÍĘŠ°€ˇä›†C]ęČ«µ„ŘĺéĂş#ĹâżCÍwßńsí¶‡#‡”2ĽĚÇxČÜňýĎĆJî$EEr«S¸~QW•_vŻë˝­kĘLpÝ0$ŕr4§j|Ą¨JÜk3«˙9Qs­‡É¬čLŇ)PŢx챜p9VŹhG4Ůq··T ü—÷Iş2?˝z]öţő8(¤űW‚MďGd’Ú˘"­6T’‘SʧAş Ý<ˇŤ™¨XÔČm‹Ş )aű9ÓŁ¦i]űp8™‘Âľ„kYî™DÖLî PᮉrÁ\ś{iÇ&ß6áĐüZ#_éH•`P9üéŕţá0ŤĎ˛EEĚÎYpÇKZ,:ŕÚ˛&ň“ë°ÉÄ ˛uđB›ČN:y5 }i’íÉ~:€áfÓąĎ>iő-ŇZOxÎlŃ»ŘIŢ(˙™dÍgJnd˛žhĐq€RW—Ž2ľöq­Ă͵|¦ŻĽ&ěłîż[Ä« ÖľoW.‰m•^V›ĐźźŘQçš-:Šő„űrąş?- ÓÝkنC1AKtŔFŚďE2Ů<˛…ĚýŠ żR;•¤őëš§řŇ3Ü3»d “?ů;öź¤öĄßČŽĐý”eZ>!¬Poˇ /ŁgÇjÓ“WBŠ/úb&Łt€´čŠTżAjřˇĄJwÂAŠcŰÄĐöű†ţ‚ô0e ČJ—u.<—9Ë{=®P»›rĎg ň˝0Zíá©¶ĹůĆĂ9|ZŢéTş ‰Fnă~aĆzţ™ş–XíČlx Yă’tŮ ˙źdÇ"âü El&ćWŮ‹YyŃsNĂĘ8Ç;řzvS§Ş–a61Ö|†‚_đĺ¬\€ł…Â/î›Ô«Sm´Ř8”2'!ńR*—»5ť:V*N‡ţÍ'•ç;ŻRksăĄö˛ń2 şűYWŽ.ŰdMĆO ź©í–ź.+WVwťđ§Ń ÁĐęćjÜe™+Ó˝ŔA;ú[űý‚SégUoCCYl ™[âÖ×çfzG§§™Ü­™i, ¸>|Ň` ć—Ż),Ź’? ăŇmáúôćx1*ŢÔÓźmęÝwŐůkđ^„öZMˇcĄ %Ś®n˛¶'$"ÍŚńj­kÂŕ‘^ůd^áyÄŢĎĆ‹ÜZ˘"JŽë둺Ýßmî>E8¤ľ±űýR$ľá6;JLŁ€»·ü›v ş·(ń9Hť¨ËďäňţVgÓ?2ĺ8NÎŕU¸m›˛ąź›r§JKčUńŕ}Ř..z¬ ˇüp=‚¨eöbpń9Łë˘üŰŰńď’ý߬(}fÜÖ ]ZöÝ=™Jv—eŽľĎωÝ$zś^1üÎ;V©Đ*k+Ńěét#{nkç3ňÚŘŻ„»¦«Üt6s}/ŚÔłlogÍysăNݤ—Ás˙Ľ?fz‹ď˓ҙ,s ţj+řć÷śîd}†˝OpJöű˝jd˙lŮT‹Búhu3yÂT‘@×}Ů [YʆJ¨Ńü$뮂¦ň6Żăˇô)M}.cdľĂü‡„úŔł‚[u¤Ľç›ŠVze÷ľO¨KKa>J!fýŁVWs>ż @d݇ĺľÂa“$Ö*ă˘O]ͨ ŘJ#¨vqňšă>]«b53@ľÄ€¸®UŃ_ĺ›ě¸î“Eđő•đ¨[šÁ¬ć»+Q 7ş) ÉÎd`´ Švž~d§Â1Ľ-’:†€†ú—ôdĎęŽwŇ.řÜU˛W9ß© +č7Ő1ôz·Q7ń)rBl1tçŞĚÉ~ţôZü8l._Ô'ţâwńôXO^cÜŤüec«L *˙°­]‹µRk_ě-´gçŕú&)źde›—~ćq€_ÓáqńCŹ8‚é‚[‹taÚ+‹˛¶š¤Äéj•÷y—Ż2?ť{â€Y“4)AQ’€WVL›%~fgęZÔG4kłßáX"1eŤ0eţü1Ła€śZn9Č@ľăĘżŇĎÁ6-» ĺça‚Ó×>d6.µurŕů?üţ˙' @ě `„‹=a ř_"ź`endstream endobj 320 0 obj << /Type /Font /Subtype /Type1 /Encoding 482 0 R /FirstChar 11 /LastChar 121 /Widths 483 0 R /BaseFont /RTPAPN+CMTI10 /FontDescriptor 318 0 R >> endobj 318 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /RTPAPN+CMTI10 /ItalicAngle -14.04 /StemV 68 /XHeight 431 /FontBBox [-163 -250 1146 969] /Flags 4 /CharSet (/ff/fi/percent/hyphen/D/E/M/N/P/S/a/c/d/e/f/h/i/k/l/m/n/o/p/r/s/t/u/x/y) /FontFile 319 0 R >> endobj 483 0 obj [613 562 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 818 0 0 0 0 0 0 0 358 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 755 678 0 0 0 0 0 0 0 897 743 0 678 0 0 562 0 0 0 0 0 0 0 0 0 0 0 0 0 511 0 460 511 460 307 0 511 307 0 460 256 818 562 511 511 0 422 409 332 537 0 0 464 486 ] endobj 482 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff/fi 13/.notdef 37/percent 38/.notdef 45/hyphen 46/.notdef 68/D/E 70/.notdef 77/M/N 79/.notdef 80/P 81/.notdef 83/S 84/.notdef 97/a 98/.notdef 99/c/d/e/f 103/.notdef 104/h/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 120/x/y 122/.notdef] >> endobj 304 0 obj << /Length1 751 /Length2 1206 /Length3 532 /Length 1758 /Filter /FlateDecode >> stream xÚíR}ŮÝËÁĹ‚ ' Ó(4ŕčęih*I_߇Ř"C™ldhÖÖ4ŔS* Ńm̬mĚ pÄQ8"Ű·/“,á0‡ŤW¶(â6Ľ0 ‰˘(€ Ŕsů„xBB—@\ ‰F\#AP0Ś’L–ý¸ < X~,sĹ‚O- „ S`ar; ,r1‰\G2qĂ» ÂÉďajµ¸“AÜŘüey"Ł_uŮ|‰úWă Ä"®ÂŃŐT_čŁ5W ‹ů«»."6sh0ęÇ,t‚#!®;,â„B+uĺ®6AĶbÁ„y`ď~·˝†+ŻąŇrgèČ;JđoŃeî ¦ýŮŕp$đŁR¨TA$ľO;˙UWíF9F‰q° 6ŽłŁHÄ\ČÄĐŚrˇHE~M((&"Ž"’8ŔĂpŇňcš[ …–‹+Ř‚ LDŘ ţő?98`‘1Ćft`lJiTK*°´ Ćý‘#Ćq­Ś ‘Ě'̉!(â?Ä8¶‰ˇąµ'Ęăw—ôT(ěuţ!ĂíjëćőŇoe‘˛;űÂwŚTł*ó7nW׍XüBÚëŃĺôňXxF^˙‡qIŕx~tý¬Ů|ר1Ţ[é •ĆÚľů) Ů˝#ťĺهJŰ _ÝzQ쾍éýwĹ'd™ë~’šë‰tK–S>r0éxµŮS5/Ľ<ŮiˇČ=ňɉŢT»qHĄ-ŕ»ĺNç‘çU®‹e-Í´­•­ł>ęáOZ|4”zUĂŚ¦ęµĺł´sßá._míŔśőęŁîŮ©G'?6S™™ĐPş¶îmĺ.«@Sű^ä3[yíäŰ©dBbňTwŮmmĚUßáRçpý«Ń^ÖŹ}'É=ľ‘ĆA´MŇő%§×\mźť–u´UśnŤk~Ňł4í7őŘ9WżbU §ń;Jć<ŐŤN7äěü9 őľNÝ•d’ĆčŤöĂEµ <Ë˙O $onf榺GN¨ČęĄýŚßMÁLú/u|o8ť·oˇŠţ˛ľVč‰eěĺäzč÷â ö’qŐĄwtęç-ž|–’°˝ÔP°đí–Ž:XáµÍ‡/Öß$HŐ“˛ęînűćé“n5÷_|;7ȉ´•ÉśÎV¶<çťEiw[Wź¸XZG)Nhzm`óóJ|ëdĆfĹh…ł‚łTÇÄ΀ Îł ŞňŁű&˘4›$mcXŕÍ=±<Ó–Vąß§iý1”Şepăň¬8Ś.ÔŠ0*›]j[\4‘×Á4¤µ—KŰŢ\uŹVpI•jĎK'š»gä/­’«Ď?ËŞ¸÷¸¬ą#ť=¸Ůa?$wWóřŰ :lj0…Ya ޵PŮŕS_ŞţY+¨Ňč§ó;ŞEĂ^ŇĘKL˝wvY¦q>2jíĐčYĘ”|ŮLCa`@łžíˇ®ožËśżc™1QÓťĽąśU›4÷`’±ů’Š\[ô_ ĄÉköĄ—ťL®IĂ®)ž*šżő“ŁëFż\g깍ެpľâýýd±˛¬—]ěm˝JMöE˝S^±ó‘%Çî„;•5 é=u=4raDYKr)†™¦qB{(EÇ)ŔÖţĄŰÖg11± DüÓ>Y¦“âŘ&/{ßű.z¤z0“uDL8éŚůßÍśÎňa) ü­&†”|Ř?„'5ŚŇmÖđŠNżÔî)rç KářŘ‹÷:­é5űţ±‡Ę’ˇh˙ˇŇ9}r©7 ®OÖ>[Ľµ¸ëmÁM˝ ”p™+-ăšĺŰÖ6ľŹU×KPßÓ—kjż4R_’H;¦ĽvWĎÜ«¸ô¦“Ú§ ßUđvlż<ó3Ň–ż5 3ď>KŘÚ±!żřŁÎ?ô•Öą™k¶’5*Veş[.‚©–JÚ€Ëöţ[çp•ĆťÔ߸H˙řźŕ a|6Fú'¶‰©6endstream endobj 305 0 obj << /Type /Font /Subtype /Type1 /Encoding 484 0 R /FirstChar 49 /LastChar 50 /Widths 485 0 R /BaseFont /DOJLNJ+CMR8 /FontDescriptor 303 0 R >> endobj 303 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /DOJLNJ+CMR8 /ItalicAngle 0 /StemV 76 /XHeight 431 /FontBBox [-36 -250 1070 750] /Flags 4 /CharSet (/one/two) /FontFile 304 0 R >> endobj 485 0 obj [531 531 ] endobj 484 0 obj << /Type /Encoding /Differences [ 0 /.notdef 49/one/two 51/.notdef] >> endobj 234 0 obj << /Length1 1916 /Length2 14234 /Length3 532 /Length 15300 /Filter /FlateDecode >> stream xÚí¶eTÜ϶ Ť»;@ăîÜ»»4Ť;ÁÝÝ  Ü-¸k°ŕÁ]‚űô˙Üą'ąg>ľď§Y¬^ýěŞŢű©]ő+šŠLYŤIÔd ”9¸2±1ł}+¨˛±ŘYYŨ¨Äť&®Ö  Wŕ;@ h ~ţűŔĹů‹‰ rôr¶¶´rĐŠÓý3‰ jt¶63q(¸ZíÁ9ĚLěj 3k «3@ÔΠúĎ'\Ş@ ł;Đś‰Ť `nmć 0ZZ; ±üŁ$ă`đüWŘÜÍńż‡ÜÎ.`)íż4é`IsťŔhĢW‚]ţ˙ĐúĎäRnvvŠ&ö˙¤˙§Q˙ǰ‰˝µť×˙ž˛wts:@ć@g‡˙śŞü/7 ąµ›ýŽĘ¸šŘY›‰:XÚ¬˙˛v‘˛öš+[»šY,Lě\€˙ŠĚ˙SÜą)°«‹)¨Š1üמţkLŮÄÚÁUÝËńßY˙™ü/fűĂŕî8[{ôXÁíeO˙ţ÷;˙¨%é`2·v°°sqLśťMĽŔ§L\6€µ9Đô ł0;€\Á€{â°9#ýłˇŕ=g±řW쿌֌vóźÉ†9x,Ž@g3 ëź€ĹÉ nűżşűßaNVđTg ĐâŻ(Ű˙ŽţÇdpYG;7—?pa3˝˝Éź€ĹĘËŃ čđ'Äý/kůźXĐĹÎÄĹęO„Ŕâ tý €}AŔ3XÔŐăĎ8XŃŐĘř׌zrsţř§KÖîÍ뺀÷ďß –uş˙ĺ Ţ+ŕ˙X3XŐÁúoŢÖlúó!n° ĐÉÍäφp‹ţ!pR±?N(ţ‡ŔŮ$ţxŃ’˙&đ’Ąţxy˙xm2\OîëÉ˙!p=…?®§ř‡Ŕő”ţMĽŕzĘĽ*•?®®ú‡ŔŐŐţ¸­ęě˘ń‡Ŕ.šě˘ő‡Ŕ.Úě˘óoâW7u61łşţŹ“ÉÇńďř˙<›ŕKŚĺĎ1ä§6ýCŕÔfžVđ:Í˙¶ď/üçý…ŕ‚–!x­V!x±=–¬` Űżlń×SĘ Ö°˙ŕ›‡Ĺá/k€ţB°†ă_Öpú ÁÎá?ů/7Ýő/[ąý…`+÷żlĺń×E¶ňü ÁV^!ŘĘű_řެbb O&vđ ~aý§Í|>n>ż˙1ÓĚÍ|­¸ţëř‚ţo¶°_ç@ 'Đ éçČŚ?Ä&˝)ěë'ÉÂérXzH1ËćĹúď?:‘—!íJFĺśč×ë´+˛°Ńö`÷H=ž‰\˘:|U&¤Îť2ć_÷ÜŤ÷˛Ľ[‰´g)xí:’ߣ·7Í]źpA*Í®Ź}MŃ)Č˝<.P¦•P߇_%čŃsočÉáćіʲÓ­Łć SĹČpúÁľć‘’ł6üÉ&ˇ…aĺÔá†őXźüއŹiÖAʡşEŹŁş/|RVŽ^űÖ?\-’ °TsěÁ.#¨ŽĘça‡Uçzż“4šąŔź”ŚPp?glíĐ&{ˇâ6X/Ů1â`0˛*’]*f˝H*UĆŇ< xżŇîůľtČ%űSnśű˘'»ÄjęÓéÂ’ˇ¶ÚPŕëdeOăxłˇ]çhĽý„Dî(śňćă&’e ęWâ‚d˝Ťńh#F÷üIÉ˝P@ů0?Ż‘D^®_ß™…$Näň—Xśső¦ľ®ňŹUL…çYu(ßn*¬5LŚŮşji•Z“č—O;)ž!“\D2¸ÂyHôa(>&aN¬‚{ßŕĘĐ%ŃđáÜÝ÷Účł(+;„jF}Ľů_Ë”NůĆźěŐőę:úó ńŇÍá+rS4ěć.(ϵ˛­ šV?T‡ Ń:sÇń‹ą®ÁŤrWÇ›Iő‰9ŹS˛đ“1Ę-BĆ:”ĘgĄśB$?µ®7Ý0¤«'…-߬0Ń3xŇv/ápdT6ôÜ`Řż°ľ6şéň6î§ÓWôPŔĺżË|ľ'ČujYąNUn;ĘąlőíO“‰OŽ~‡ŹŃäô;¤(ŃY ×ÂńÁAúçB»żýĐçGQ’ )‰˛Ů{v±3aqőĚľôłR΢f­I]ű†d˝Č>Tlo¦ĎúÝöTśĆĹ‘n·M›µő J„˛ŹÝföJIşQšŻ!‚ŞĘ"ón˙H^öDB¤Űľ"sý…Ý”+MßĚÜ‹,(ú·őɰ7qL•ťgÓ®I |zĂĐ({šŰ­ ѡÎĚ-—”“ežŞż’$ČCŽţţőjiź%:óÝĄM˘~ ·[š¤p¨`ÂSP¨Tvrŕ–m#/a±µ„v7f[·»Ă9;˙4r<·”ŔĽäŽß÷­rĚw‚-ÎŁÜľy“ Y%!>ÍÚŁ3&ţĄózZ[BŃĎ/Ń3ö(Ó· V2Ů’PΧpůZýą9 dŰH=;ßČNň+v6żÖP­Łe{òmvŤ±µĆžŤĽ”G\ vŽép° 'ÉöEbcFęřô GŽ8{–ÉĹKŐôőč•m¸”¬wÎ&ĂŠčk:*âĺ‘R¦mÚY¬äŮĺł[âĎ3Áî?ňĐ×¶ź”:Öl|,ŕ˘2ßČ/n›.'ŽŃFŽ–0Ľ‘iŚÇĄ 1r-M ©QÄ1±b$\˝kDg­ôí—l»c籓0'úŕÜk;Q$¦¬mG^ŘöÎz÷ţS„ň;~v¶PZĺ;4Y%Ůf]׹Ú&Ţ•‚#4é %·*"ő ;YWÖĂž‡ňŹIÔJţÄzŚ~-fŘ>ĽkJ»ŢÖaht' ąţGXŘĆó˘›<Ą/ľB^¨Öa ¦ę‹Ű*{Iß(şŤž*;Ż„¨¸˛gköó­, 4ه]ÉŻ(ĂĆ”=ě>•ď_v{ÖŃŽ˛««Ŕ© šYečÝEťăýŞpZśd´ů=%Gë5÷CÎ×ó1űtŕË?˛«· "j<ÇyŃć•Ăλ%' ňC(iEC»–eµČşŢB™˙> KĐ\­Ô{c Óňٶ3O™®i(—j[‘߆Fc”64}fś` óPř :eyĚň «(´ńOv–ö@şżŐô’·KÜnąŹL‡4ëňŰ´hńcvŠqSńÝą„ŚX®hŢú|ČűÎČ‘CĹhÓ“´›ÝÇkNĺ;"AZs*‡1ĺ×ÔË;â^&2މí_Ŕ§Ăp1Ün™Řů./ĚČtĘ›‰¨čü¨?č˘äß°ëći›?݆ŹWEN…Éc¤łÓhKsą*+Ěčtň‘9"źÖ5kç3śí+–w~yĽu g÷„Ą žŹ Á.2¬ŤË(Zú×”ëĹá{Ö• óň4VĎm=€ľębsü-*!zP% mô1›^¦ă'÷öötS‰…‚+-ňÁ‡ş_»±#Đ÷»°{˘Kµ v7ă+•×Ćb<(+¶AńRAËs‹žF‹<[*ζ±ą|!yŠăN,$‘(–vٰî=ďě#j즷!M€ĘGVüďuh*‚Ř´N>wr?ÍäbRÉTÂł ’5v6ěÆ´đűő°ěßśOĂPŇĚ€Ěln»¶ÚŻf‘©7îx IÁ¬l˘óÔR¨}fnä‡Qyd›Ł Ç©KµK§í«{NůĂZč/^Äő¦Kűë ËýűZůÂ8w]ą_ŁA6íżť± ›DjśË¶dc5łŕ·Ú#¬ÇtÇŠĺ74íżl Ô“÷b)‡” é˝ă-äWô/ńVt^LVÔź!@ő‡2é6Ř@łźJľWÚDK6 Őfç°»0>ëúL2÷äqͨ<@HÚĄ]Ńš`/Fo¤Y[!µ 7FO =4ôAo¤`ťÚ~¤ňě‹s5ţÝÓ!&*ÝJh*:,Y+IP€a™âţî§JëŕGŚô’ÇŻ4•ďžU“ýéşŃ'ĺŽU4ô…űťxY/ś$źőyČ;ň$ˇźGřč'ďťÎśŃNgăŇĎëĘ•č8('ߤ!űí.ĘÎ üP Zšž1HŁ%XĽKP;ślYűý]‘ůÚłm Óu)ĽĂA¤őއB6 ďnu‚=čŁ lV>Żö<…ŤlOJĹTG(ţëfÓä‰ÂŇťöą¶ďŠŹ›Ş`˙Ŕ"bböąFěČ?“mş]o>ŘęÎ1ýÜ_™ţ<‹r‰kfBß”Żš&Üľu˘JKţű1áĎ$]y{ ‹Áęx±޵düäKÁ'öĂe… ?_éK.ÓaAżC*ݡĚg”K0¸ÝńI9ýČŃm–BMüwďŽjń1sݬ»3LŚsmĹwz¦“AʞĚŁ{±‰Ů¤8Ô…ˇP#BźŻ]ú!×qć~>!ú™v´ŐŔ n.nf’nÄ jz? &ꪑoE]0püH=“˘(˘<†8˛řc[3źúy&ýG´ľ=ď~ăZSÎérą$jfOÁSߪyćři‰,l§gÜžÄĺśÂ”Ř@ńdČҢnĺôW›Ź·×ŽyśVćAjtZ,"—| ŤiŽ^ŻfX3%’Â;H zŇ25‘¨ßĎa2° ő•k·L^]ĎČ,"űĹ3'QqË –ΦóÉ]ó›„c®'¤Ńu˝ćźă—š>ę–uîŔşŢ3ĺZ«» Ý0ÉF‘Ńp»Ň]Q‹6¸đKNâPHY7 Ël5ýĂ'… ™ ťă…c‚¬µXu^2ŠP7‘áŤŐT…UűśŰ˘bň„˛ľ%ý)§ţäź÷'ÂIP÷51Vä =?qő“Ľ®qEÜU![ůS•¨RlăÖ@ęŔG˙]aą¨˘ ČZÚ'C._/˙ňâ=ŮćąhN żůëHֹʊ®<ٵ{»ô»Ţä MzřŤ¸Šy˛ <µ€´îŕb ÁÁˇŞLŰĘď ,aѸńKBłß‡ßŹH˝ÔĐ 'ĄŠ÷mzş65!Ч“ű\…őÇ“”´/ŚýĘOXx™”10ńs]Ţ­Ť·ďą§¶5ďT Řđeĺě~öÍ ¸qłÉá”´OŇVvsŕj|ěöˇ‚{Ď˙Đń˝ˇ´ĘşýSŰŮűY‹ÖŔCîĂČ ÇrCxčű2}¦€Xm×ĺZúv|÷€<(vŽęCľb/Şń¦Ł:šÍĘ Ą-e#Ý_\ňµ8rî-Xü öj4¸ˇí†Ń_áÖdçí<ţÖ^†î°ú*ŁI#Ĺć¦qÝč=űß)]` Ń=ęyąC‰.ˇYÉőđ…dďM?óxÄŰą đs-łë\«)…Îú| –űY5Î,řâÖ’Wg.çśu°Ęcł‰*´nÁEąď¸şďýşÇ¶JěGŹ+KŽIü»FȶĽěą7ÖĘř»fřoŐ8®C-íéäJäSV±źD®p»ç_f3JŮ;tqâS éj"Iw|ö7cißť‡ŰD^sµ»ÚÎüSiO*+4ĆâgĎ&t6€yęo »Mćî$Ý´mN °fÔ[ťĺŠ›¤é_8‰CŇyIFĚEňpőu˝@ŠuĘ€gŻ-Úłwň7D=nďŢńW„ß&cgGWřß·2äZ,s¬jđŢ0‚şg„ďNßš“í‚ń[4ĆŹß‹ŮrńŇ.ýôS€6‰c–q±řeŃŹtňđŇyčľÂě×vĹěőŃtűŠ'›yۨÉâ'śŐ¬ÂÔŚ>^BĽ™AöŁöi‚†ŕš’ľ"$;.™äđÁ}›`‡3Ű=;{ŐŚ¤Ć_lomĺděÝç2ĚKD_«Ĺ°#ä¶wÔÜO _”X‡ńIféÉAĺĐ©őDĎr´^ Śôr„Ů©”áK>LX®ëĺőłőv>bť~ćT$lô”ç3i†˘wY¶r mŤ.»ř íŞIĘ«řBôůs‹¨Ř §~‡IţЎÉđ¦mxŠŘ„ЉUč.ĚyšÄ’ˇEw; şÝ`15·Äý&¨ÍQ ŤnćÁ*1°â0\g3°bŢuŘ檪8i”Ăň{¶–7MVhʬ7Śři9» %ňţ#ÔgNÝĽŹ¤ “?S۶tk‡ËŽVSôXđ:xńď~…Ćuúøŕ’ ř EąbdšuM~—ľĽ]‚Č%"ni8F3ÂäŔśĄŽ’Wą-ui߀úŁ˝ĺŁí«&O|´žv”Śsô‚Ť¬ÎÔdJ´úĺÚÔ×h"öŔŠŢFËçcE–FžÓö= ´bę‚6’ŕôçČî6Y˛wŻŰ*uUYľŠiöů+7„Ö٦âXŻÄĐpŞ$RÜe‘Ó°6‘ „K'ä×"–^¶t 4tď22ă´T˛’K?Çft߀T†ë0M4ó«sáĄËńâ•˝!ű| yÔlcŘ1lIF»K`ٍ“čLąV+"Ö»ňŇ0ź‰6s¤ÔN~§©7¦űÚşżZ*Ŕ‘A·ľ{ßŕCď>ĐěM1ц†‰A§*7üi«OuÇZň>q×QĐ”ľ,|Ý—â’>IäBĎ|ŹŻ‡Taîe@¨¶®Z`ŮiM–A‹ÍQ¤{cóx¤t€ÚBwŁłŔxŁň#gä:PŁxĎÍEŃWtů‰;Ô™śü]¦Ű<á+,®”Ă ݵ˙.ND%‰ŇŽXŹ~ß{áV#ŠŃBjĎB ¦ R› ż„wž,ŕ”SŇfňÝ‘ 41-P]•çx}RĚâů[üÔ”Ć?Ďŕp¨N>ą}LsPD?ŮTvľ×’Šđ´Mńr{E[&,§ÍŔË÷ˇ%źr)˙óOú“;i4^Gsßů>î¸'ŚGÉ„ĽÜfm…(Íf6DVW`8Tľßylsća\0ŇĚ8 Ʊ:Uť7˘Ö>±|¸Ü‡€x ™ äaeÚOďźlřŽ¤Ýµ±=ÚďZ:.g©şýÜä ¨î„˛ä7ôżH3ů´z*áknČł«BŠşˇqpž÷gÓď^ŁFYëÖ¦21ÁPؿĥŢ-z´ b×X^:ÓbA| núNL[¸ĚŐú…Ó ^ČĐ01 /{8†ŐÍĎÇlŰAZąT\.űłÇcń \ôÄ(‡{Ω ý) rľĄŤŘkôtslĘě‘ŕŤ”—ĹÍmG¸7fhĚDpł"€dě{´ňĚÎqčž íFŔŢ“ýí_}´éĆ}&ó!GΊ-Ú$~€»ŰřčyĂĄ‹Ł*X íŰR-»éąí|m2‰ÖĽ<§„ŁŞKÓ+ěÖiţúq¶"ŚŇ{i_HűĽ>Š5ŃĘ +ŽÎaĺ÷őóâá@U °Ą!-(p8řHůŰogXÓl˙D5Ε€ŞýĄ2vą™7Ľ3•c<č«Č#”j„ď „'I”¸^ˇČąĺ­F°đŽŹŰĚU\L^ŃťOaÁxőëş ©„4dŽ Pô!Ő€D!1čRÚ©Ď`Ď“”Ä”ÝU@íF®őŚxă]Qďç»¨ŻźůC9®Ę;Ć^·ÉsźŔ1™EŢ?uăŃ~»]°›l|Go1@cýAŚŽ´iYHš­#µĘc|áxĂš“O‡Sě:´ú˛ÂŘńu°ČÝÝż¨äFČD”Ž˘UŮV‰ $„ŰBO7’]Ç€±^1VU×Ç m—Ű-&Ń®=Ę•kŰ\ěXMĄŞ\8~.C[úĆ›/ˇŹs;F.„ZÎőá\h=L­éŞ‹—Ďrą‹–Š»Şć"Ó’!Îoş”íçÍw# Á^*‹÷{Á‚ »fÎT!˝…‚ľ—ĂR˝ĹO#ä^®ůçEpQD㬟&á8ác”ű˛!ăylŔéM"Më"»2}q<íÁ {yɵą˘¨1ĎćË`ź»˛Żś|Šcá×Wи©!0‰ aÝó”ä+HTÖ#˝¦Ŕ l®”(á&‡HČ>l°k‚R(*e ňµrˇ8l1†ďđĚhGăfÓ´O’zXp°}FG.ç?KDţxńކ:!,…ăDÄkcQćuűĂ]ßQ!WËĄŹlXeçjP‘Šnó‘%#ÔńĂfUvŮy“b3ŮŹxxëÇNť(*ÉČ‹Ń1OÉL&®ďżîëĘIĽ| 'pŽvşd70Ś-FÄDö=dLj`4ţő€%â"vŐwŠRl•äâµŹŽ˘ňŻĆĄ9RcŠŃwăD…ŕ=á—`íďn÷­‘n+o«¨Vžc­l5őæ ¨j^Ż _Ęla¨“_ŃpŤfŢÝ–¨÷Óđ7&ř‰`¦ŰNĄ2ĚB“#~[ţB®_€ž˘ÁO®?Ô•T[Ze€ţIOÍÍŞSj.—ż„5ŻWůo¶&xřĚěwŠK)·ěÄD ‹CŰľC”éP8BĂ—u›ď‘s0|nčČŽ®˛ý_ߍ'‘ésB2H6Öw8Sf^h’ˇŘ‹2ćhçĂď¦Đ•Ŕşľľˇ4Ş,¨}íí75ÜÓŽqWbŰHßnńÄ>M—Łc‰‘ţţ6ď ąşlĐď‰Îxů3ŁtĚuujܬÇłs–sęÄiŞ,"pR”ęü>{VúŮtŰV€XYyżX‘Hşj„‚Ć[˙Ít Ą=‡é%†ĚÚɵ˝,ś†P…~’༗Ńt©4WŻŞČóŠÖŕh Wąt§ň˛Ř†Ăź&ŇyÖśRŞ›TťµĎÚ1*¤ˇ]fjł)5Sv·. ­ ©Á|9LNńcîAĺkŹ_Ţ!.§˙9g —Ý[ÓĎ™V±7sý N‰ŚůjXRqę€Í]ôůxŮŢóWŚ|€ë©Ď੺ÂřŰű†ŇÇńÂaČÜ„F€ V©€őŤÝXýËýiU_S}Š ±î=ňËu çYDďPü´ýdŘ•Vó Ĺś•ë2 Ş`b—9ď|'-÷4”YuŽ-ÂýĐgj‰)‰0Jś hÉ?¤“-§ÁlĺĽ2ă‹°ć€AńŁbÉ%(ű ŠShB븎–‘Jź\aˡBÁEę«í~›śž„ŁŠÚĘÄŮCGúDŢŁz!pĺŃo^¦ íF;ňS«ěÜzC5lC#Uۢň˛ýŰܱs¨Ť¨u 1”ÄAEMwb­Ę¬şŚŮÔęńó۬=ĂŹpŹ‹ô9;z*Ő÷6쥳†áKAčȢę+‰ÓŰ4?:@Á|µQ‹†ŞZü9OŰ}aľ/|rčkĂ6őÓD§ÉZk":š*ÁŃ;a"ńu?ŚëŘD«¨Őş% ČsúűęÍŹĺ}é(Tţ&zî ěĎá\Şw‹ë,Ň dŞlK9˝±žj&ŇŢý_Ë„Cw3FúßSČÍĎŔž,OmGŁĹŽ‚ěőöŚÄ„$·˝Ö˘çëjo‘ôëŹPěIČ’ź.r–ÓQp.Ö´o¬…ąWľ[UHÖú–»!.=l×ó.u eż3¸Ě‘ ×ëŇžm§®ť\-«yąÝ$cUbB˝µP°Qřę}ńŐ蚤ŮOôÝb«“%ô7şVx[“:3•ąňęŃ3ĚyD±™ ‘őq]U–DžmsÖ& ôhrÜ0Z€ezTXĎĹxq“ąč~k•ĺRd"(z;Ó0Kł’ĺŤ=n ÝlIts‘pŐ‹Paë?Ő×NWSčÄ;ʇúKĽ&ô؆g_}ű˘Ĺ(ňĄ2ŞDirňZŰ‘‰#ĽFpf\'’^\Ů<"űŽh"í'Uäˇ]ë3]ÓňϵŰW‚íž”Gß Ě̦Řhw÷­Ćą„­AjmA+E¸ř_ŞńÜ_LĆvU>Iů76ţzĺlÇŇľ–r‡é’Łý(ú~A cQ !d'ąő„ťś»“ŐżźÜp1™ÇŇđ@îóÜgÁŤz Ă…®ëYšâ˛ÓŻĚkÄ›„čHŁovßS/µĹŁŐćHMqĘćo°Ź5-?1ŰĆ=t&.â Pý˛,üÎ?" ‡{AâŮx3Źýmô„cÔ*¬’©c·H-u`‘[tI¸Kę4ë[ěj 3ć—Ë·Ő.â.4öj bËGĹĂńW¤q·˛§lsxdAľű*¤`ôÚ—0žŢvĘ…E©0í(MŰě¶ďŚ’á—«¤ůíq'h÷ôt¤¤ł‰˘7šĄbŐŢÚľnşőgî,‚ÄŻ<.ř›‚LśwÖ°Sś›m[Čř%eaÔűĚ8wîÇ}EkA»ť…ňXÖľ1Źi‡ĽšY˝Hd<şühĹęâEĄÔ‚A~˝PeDŹđţd°óďU -*ělđł6v9żÝ.n”‚ěËFž/˝,âЬS– ˘}ńrÖ)°fňŇ$Đ”řč˛1üús‘0KÜż¨ŘDŢgâQ!>˝(5§N­Żđ1eÂE¤ŃkwvCÝU”ĎM-5R-*—WaŰZ:&>O0—ľ„Ať±ˇgJ]Ź{ yFD|×H:•Ď™áPţuźŢJ-x¶eĘZtňÓjźą'÷ !p€/äK†ÓŢę"Ăńá~7 G„x-$¦MMP<3t¬şb‰ĄËcĐdGoĐ#©Áp§tą*ڇ•]Ą/(bŹ{űrfęch–¨§ěżŚř(‘Uýá 'uŮ<äŮ›‘fŤÇËQ^ʏ§s+˝—»˝+ąh–Ů ô›8ă* 1;úፑë‡o^ÁgRÎ n#*ĺѡlK™Ký€DŐ/›Ů„7nşŽ0mPÜČHÂá^Ň=s˛ŻJÚç2îÂĆă€_ÁDŐuKúíĽmMzůÍ*]Âo»*™éX±u=˛Ě<4._K AJÂuQ=3ßĹ šŇě©ř)oi<ó-&“Ď©ýpXçRrŠ•łfv&–Ę4ż ŘńIb©q*ŽŃ«`čđ‹¦ýaެÁ>íĂśęŘĺ µÖěn–äEv1%ë^ń¬_Śťś›˝Í%ÜZ”‚lŻĹGĹ$Z÷â°´L冩7V9č±­ß, ¨|T ‹;Š+UZG§–„3Ń]b´‰‘•cěôe‡K>@U0í·m©˛HT–Řf‚†ťîč@¤yWíŰę-ůX]s.]–ÄťŰŇ]žx´4×›LË›ü,'Ś€LóÝ…$kN|í:Oôľľ•+×ŕ[X8!ńłB Ň÷n¨Bä?˘ĎnP 2kLë!¬Ší‘p·Ď5ÖÓ “B%ěć$Üľ¸čşŚă>)đý €5YYvÓřo $ň&hÓ»Đsúŕ6í%‘r=ő»p ,ťk7w<‹^źXvó?yÍ0~+Ľ`§íYŐ¦éöÇ·I â—ĺ˝/ÔÓh‹ßg߯ŤńF G@MĄ‹^ô—jaÚ†W+vŃl¤Z “Ľ1w˘0rŞáRűd)ľÔÖµ{“‹ĐćyaԆН$nŁî)ŘĆjˇ\(ŞďŞ zß.;»ň˘ĄIô•Ô/dßz§e;Aň¦T8­yÄ&bě{âCÔ×als»’oŘÎ,Ů&&аMĐpú4Ą©&d,”ĚćÂŃŃďŻ |ü ôţśHm[GţĂÉLű…ďaňc3~Ͷ~Ţ!~Ý <0-SĄ­…(ČNkˇŕ‘ői¸•×°‹ů „p‡ł‚©ĺ¨Řµ Ąwě®č(ét*9;űŁâ’H†×_|óĹ4Ş2·źRđËy‰Kž¶”ęôŁCĹô{Ueů(füđô†yaĆž[™"ˇy‡ÉhÁaŤ7•ďÝĎ$U…ď±$ŁäşŰŇ7¸ýG*ęPZ)Ýą ~s^9ÂôA÷ |×Ő!wf2Đx °’ÍägH…#ÍK¬r]Ż#ńŞq‚ ÖÝď]łŤĘvV_ŰŤ…}pĘb´˘~ ¦ýL!ŰTłűüĆŁŇ]¶Ľ"Mő„™I@žŢ,EŁÚ1ŹčćĂya]ĄňG§®Ą w˘jz«{S‰XMŤµÖşĐ@<=ÇKViŘ[ÖĆZ=~Ů·DôI-7Oµ¸34Äqüvn†#A°0`ykůˇ4ôş˘I§-A_LÁ5‡V/ű59d»,ˇŇŹW˝_ôYü6˝‘é÷ű\¨Ái˙›Ť#ä˝v˙7Ĺşąý[¤Ţq5ť]„ŻŹd?ifĽaô±‚ éú\Î$l¤Ń U<)źmÄ5Š Ţ«ëK;ßí^a•ćÄŤ“[ÓŤ7[GĚĽűč^ăLčľxë*s?§(QdŐĄv‚ Ť¸)Ú}~O{Ö]:%Ľ®;%”°\:¬–µ‹Iüj4;›†ˇďňą+Á$(jľxś9 Řh8Io\WěiaÓĆÝŘmŇ4ÂxżĹÁ˝ßř4ţ+…´%OšQtôŽq°jÉ)Ś7¶Čü›?%{ąŇžvK?&25úÁoŻć.Čď?ĘÝPžđľ˘˛şČČĺRëó~•¨'T±H;!˙„ź›§/ć6UŢ<3ŘöSçá7ŢzäČkkił¤ ߪh”#ÓýJîYŃS8ËŔŰđ¸Ü!{<ŞJĘ‹ÓVŇŁAű:—ĺÚµvuç&ćaűĐA÷oŽŰ®čúxşíl­ żĺîź Âź#ŤŐ{«\ö‰y=cĹ`çîÁ‘r¬a ˝—ą÷VP‹szĽZöšsFw’¶;&ŽoĽíńňY¸ÎţH ҧMC… [ö­űŕ{ˇ»ć. Ź˘žźxŕoűć–HŰü´3ťÓŰ×OJ€k6™čcŕiM˛„C{Y€÷šŞí’Jł´ ©(J˘\Â6čśdťĹ6˝úüÝŹ~Ú…3äÝ˙Qőń_řęÄ‚łvÍŠżëĹťĄ/ťÝA×+<ÖkÚŠk{§aJę˘P„ńUĚÁÎF™ö/Cě–¸˝agQĆđđ™†>÷śţĐÂô°.I(„W‚©µ˛ě N®=g5®‰~N ;ŹeUÎľK IŇO“üýű¨ş!ÂĄ?¤€©ă•ŠigNÖ\Z7ď/ÇŮ÷»°Jýń´¸4_§}HĐ5óŹŚe¦ĂŐ˛ĺwr0”ňlH[Ęâ•ÄÍ„˘c=g"řG°ăL 6/¬YĹ&ľ]ÝĚXV‡q»ˇťµť­®lŔJriŁ3‹¸R[XICźŮU5}9×bú&ĐĚÝşž(.eĄJü_EgČC =Ř·AńŐî¨$´ui/mČ“-§.3OĐyrśŁX5fĹ.•[`~jŹ =#ÄÖBV>S!že7úNěŔ;¤%îBě°S`&."ĺĐŠQŤMŚ%¶cÇâŐ—)ó{čáőp§׬Ćä˙”[é(s»•J줠×Kţ1d(6[•J1E-ő(aQŃóŃíëUľł.•Ţh<@(îőŠÍ…›#ň”ŚoĘH”űÓÔŁ‘±hárĂ“ŕ3 éśĂÝ,4ÎJĐŰÄĘ۱¸AŠW2ż˘Z‘Dę$Ľś•Ů>V]ÝĘy‘äpť1Ňw+Ô-‹äŐ2xG7˘\Ëóqt!Iă->~®¨ ’đűn(*/7†ý ^µ Ţ#4_ż±úZÇĎń?„ŽzÇ˝%łišd^ŕ g±&‚^µ ť^cRłćh}WÎĎZTeť"ť:t= G>}#xÝF¸7qéjÂSč*•ESşßΦ;†Ţv.ĎTUhU’‰&ÚéĆÔˇHń˛h­ŘÔVZÁ˛…Ú··•# ?©ĹXv2ßŃŃ:â¶ř @·ĽmŁ}]ť^. ä\Ő·Č”Ş…‹I;áš"•fUÁŹĹg5F±+őóÓl®˘$ćí«SpÖ·ŢO2D“‡×Ó5ţ1=n#ë9µMßn˛Ľĺˇ^=‰Í6vĐkIĎăQ˝ey†sů±ę6*>šăÝWšÜĺxÇw(h+TćÇŹ˝x¡ĚĚ­^Ř ‹ń ä1•ŃtăŠ%‘y©”µhBćIV/*ú]V.3ŽÝ–l @ŹQ—¬ĄĆšýÁ?'W˝Ô‘@ńŕEĎ)rI×Z_¬fčŻň†÷ŽP/dâÂâZZä˝"wóv}Ž˙łe©Éµpéh“/,<±*Łşz§'°źé+I=ýüP|Ĺ߀Ę3łOZBĘŤr4Űr‚ńF«Öm…ŽqNŕ÷#Z•ląýôŁô“i ‡WmŐČCJ¦ą5+˛čEÝwř‡bS*–Ţ«+\rďUž)hB[âĂ×O0ßt4ßóCősˇ… Ž,@™ĽÖ­{G@ŔK*ŁJrí BAz =Kżď¸R¶7ĂźÔ«µš_/ČF&áQ3ý^ÇŘFYPy:›IŠĆ!S©–›hjMh]8őń·˛Ń5”1%c¸ŽäägŰ:]ż‹UŢŃ1—˘(ęÎ[ yd3›IŻW’5Ŕ˘¬c{żn\đ#//APÚ˙¸ ‚ą˙Â-ôÜD!D‰ďĽÇZS‹‹Ű”YđGŤ 'ÍsőâľŐţ)–öl}îĽSšŻ”[Ř/ņ(F´s.Ro~ݶÂä\ŐxÝQ[ÓXôqŔµěK0^g1!ňöTú//_&ąÄČHź 2ç÷Ó Ą|ä; ýRo4™š ;Íě1F NPEnVq„şć.髸{ş5÷6nGŇî‘>gýľ• ŘY°°|íÓaF˙ĄkŤcZćoăć瑎k*!ÉĽąŐqĚüë*ŇŘ–`— ŤKąéŃŰ´€Çú“·Űś9Ż‚ŮG‹ ľoÄĹýťJĹ{1ÝńעР.¦—DvËÂ^ •C.Ľ9mţgźGC˙$‡Űę]h+ś x‰HDK:’w&Áe*žc‚Ö¤ś‚5t~O'Ősî±_ŤÖ÷Źkglą•Ă›źkGI·ßőSoř–7í#ŮŤĎÉg_ZŔy6t˝L’j}[×˙0 ÇŰŠ˝q‘Ď‘ÚöTst™Ěy/NGÔ&)$î›&ťlÇz~ë=¶ODđXĄ"śddÄű¬5#ÜPőŚó ´ĄúµŰÇÉ™¨ˇů%š@ŚĎŔŢÎWß)*IäăYzä5;‡K)WpśŮî üv2ân;lţ8,ĹÂ~±éĹç‡6±–’öľtqŁÝé¤čˇŮćúFŕŤ{Íâ‹Ę±Uµ‚c~Ë4+ ŕ›Ŕ‘˘~{Ü[JQ[âä˙„v3~ŃV!ĆŤ%¶Îą~Oťő|B0 s÷¤<_ynŮű%†Ę…ŕy=řđŕ‡Ë äÝj_\l ĺ&ę66†pĺę+äăc‹Şâ—}ľľ†o×ŔxÄÉڦ겮őďt'(PźŁÓk*Žź˘†\Q÷k/“+ËŕľÓc!®ÝŽE¦ľŰç‰IŚ“ ľ˝şBć$°i5Aę”Î΋Ë{®? ˘jJťô'uă&žX ýmx|uÓčÉןú^RÁł>ň0 ­řZ»Cý‚{ö4ç[‘ÜŚ\LŘ­¦NÖÁ*I×N“íúŁ6ÓŽâ7ĽjÜ/šC<^ř}p#źZDZęb¤eŇR%Č3NĚX·>#QĄP†^p'i?ň)Š 7ĹܵćŘPOśyë.2ĆNTĘ|dd sLaóĆ$%í"Jľî^ŞGJÔŰ&°+ń•ô¶âCkŤ&5·ţz®ţŕÓ•Ő}ŕÝŻŐáâNŇě\čąrŠ÷{ήűR,ćo`ăʰXeIQľźH4=ÄÄSRČC÷¶Ý(s˘ÁŮv\cŇ‚_Ą˙P."˘5‹°Ók˝›Z`…°-’ îŔ÷NŐŁĽ´ŁJ%‘Ž÷;ćť9¨Ó˙üĺţâěđ&Üšľˇe—ťeW -§îö+=zŔN%vďoĹÁ+O=]­Żč®RAĄ›XÔKdĽ{ď>îé?ˇ dß=ÍéÍ/őŇ`”[xqLâÎĎecžUíI’ÝřčqfĹĄť˝p ±ĘNÄŞXIä™[ĘŽÖeS PŚLgăâ{Äř¸#Ş»w‡öŃ\‚‰ď~ f[!9Ęj7Y>¬d¤dP¸‰ŐÉŠk&łwĚ%ű"¦ăs6هřWTďGĺuęB¤wţq%­Ď™.“v¬J?iŤ:đŃ“ň(Ńę}v»Ă¶Ç”G4J‰a•łssäk4ź=î^čá-ąĄtY%?Ď-H`Ă) ‡Y4ű~-â¸Ń·M"QM×onxsq¤—;ctłw—7Oňń6¦ćâ±F‹Wš^Wj„ţÂUťšk*ŞŃ|y˘ĺÇŐîN˘/h@ţ>˝/ik“&cś]ßM:|öÇ;е<;×™­Ď\zŰ ‚ŇqPO!éń˝v9ń\5ÝF}kyĽ•W©ŰHë2vQ[B“hŔąÜś'^—l]­ĘĎ‚'"ňÔ°‚ŠÔ¦4ňČ\`‚H$ 0 ú"Äł ^ß5Y »Ä?ykÁSÓ*đ7;k#Šö>F27o“D=¶[SnÔsÍśT–»z\ߎô43®W’5ÜĎΗSxţŁ3–pG]Iřs{—¶ő†‚}Ćôă/sřµg¬íďK¨`ɨSP‘ťرOµ©”îúŞÖĽ?ł~çÁ3¤Ý|ŞQ» rčy7Ýn/ýÓąŮLĹÁţňĂ&ďRéÎÄcť5Ą( —3—ĺÓ:Ögˇ‚ˇaÝ•P<ôŮAr`xaG 55 f`,ú’Ő¤áN[/ޱdTçőbž0Egă¬iެŤÁ3—DX&…€R@uQŮ˝±ťW?«ÔÁOń©‹„ÍĽ:Ž‹înŃć5ń<Ě%ËÉ­€IĄŽđąKŐ´y*őDťsNÁŤŽ×ýź(ĘžÉ:ůÇ„hjÍٸą×N±ë*›ó™n=®Ů/úY·ł()[‹îGńŞĂř'Ă+_†Ł)5Â9b qW˛ šˇ”a“[€„kO«öN´RčoQ™uÝŁÚĄm±…|r5&oľXRxďR΄´{U1›Ňw!.—k VKęĘů:UY˙?ţ ýż˙W$0łš8»‚ěMśm‘ţ… 2wendstream endobj 235 0 obj << /Type /Font /Subtype /Type1 /Encoding 486 0 R /FirstChar 11 /LastChar 122 /Widths 487 0 R /BaseFont /CTBMRB+CMR10 /FontDescriptor 233 0 R >> endobj 233 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /CTBMRB+CMR10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-251 -250 1009 969] /Flags 4 /CharSet (/ff/fi/fl/ffi/percent/quoteright/parenleft/parenright/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/A/B/C/D/E/F/H/I/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/bracketleft/bracketright/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 234 0 R >> endobj 487 0 obj [583 556 556 833 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 833 0 278 389 389 0 778 278 333 278 500 500 500 500 500 500 500 500 500 500 500 278 0 0 778 0 0 0 750 708 722 764 681 653 0 750 361 0 778 625 917 750 778 681 778 736 556 722 750 750 1028 750 750 0 278 0 278 0 0 0 500 556 444 556 444 306 500 556 278 0 528 278 833 556 500 556 528 392 394 389 556 528 722 528 528 444 ] endobj 486 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff/fi/fl/ffi 15/.notdef 37/percent 38/.notdef 39/quoteright/parenleft/parenright 42/.notdef 43/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 61/equal 62/.notdef 65/A/B/C/D/E/F 71/.notdef 72/H/I 74/.notdef 75/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y 90/.notdef 91/bracketleft 92/.notdef 93/bracketright 94/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 123/.notdef] >> endobj 229 0 obj << /Length1 1205 /Length2 6872 /Length3 532 /Length 7639 /Filter /FlateDecode >> stream xÚí“e\”]÷ď ©–fčPşKş»»`ş;¤¤¤Ą¤»;”FBRşáĚ}?˙çÖóg®yq}×ţíµ~{­}ŃS«k±JXC-A˛P+'§PJERź“ČÉĆÁ!  §—‚,ÜŔP´…HČ)(Č”YÂ_ŕ!^!>=P ęě ŰÚą™¤˙ń%ś@0°•¨báfr‚ç°˛pjA­Ŕ 7o6 „Ł#PóŻ®@M+ć˛fpr­ÁVn@K-`˙Ë“Ä ä˙WŘÚÝůßK +Üéo›Ě@¸Ik(ÄŃh ˛°«BáŐ@p/˙7lýgrYwGGU §żŇ˙Ý©˙Z·p;z˙Źęäěî‚U Ö ä?Ąz ™“„:ţW7 G°•ÄÖäřWě* öY«Ý¬ě€6Ž® żă őZ€7îoěúŞjJ*Ň/ţg¦/Ş[€!nÚŢÎ˙¤ýKý7sţfxw``/ Ľ˝śp!üů÷›É“XA­Á[ /ĐłđŔośxľś@0ÄäyÁłłA nđ-@xKü6PŕŻÂgÎnówěoäá˛;ĂGµţ˛ű€`ĐßA ;ú‡y9€ěnžż×yá)Ýě` ?\đ"PwŘď7<öřCÁdw…źř†űř×tţ‰đŮ!ŕ?ĘňÁ%’ż îRúâ‡çWřMđ5ŐHnFó7Á•Z˙ü†˛[ü&ř>Ëß?¶Ő?ÄÉ?µő?4čä˛#|řě?.†ţpGÎ Ľ°?žĘő„Űí„;v˙á&=˙Ć˙ľ’’’P/_Vn¸SV.řĚŕ™x€‚<|ţ˙›ŇĘAÜţţŕá7űßl† Č 0?µł_Q “?Q‚‚(i[˙Vµ¦ă[ëÓĐąDÇÂ!%–ĺjýŰŇt|ě-”-*Ď{2×č?ŤQŮŁ`—·©Ó[ć[é>Ťdú§é*Ţ›Î4Wˇ{Ďšë¦Î÷yŐľ.ż3řŘ›uÜ·—«Î$­˝ŤöťˇÓČŁ¶3#ŚŹ__6ÝQ'2Ľš›Z'ŐĄ8Š'rÉç]ⓥńĐűHô†‹'ĐwĽŰ|ôIf7V¨11®¤QłnO±ČÄBüWjůYy»"Öł·ËręŠżŚ©°Wul®ľ¸—•ňňlĽ4¦]oŞĄĽ]—^,%î°y;'ÚŻ{3Ýö0LĚZąžöţÔz ˝ *Ŕx78–^˝DĎ'*MxÔT,‡YV!kôb7MĽ©ŐůşľüÉ7đŇ€őÇfżŘ˛XţĐWXźźc»TtŁÁÖ˙óanb”dÚCŐ9Y‰ťOąÓâ—‹Şwć­Â\n.Ó[  ]KÄÉ–ę¸VO`śîŢŔŔ–“âTs)Ĺý&<!ž;úő[` µÇ¸M!›Đѧ„ŘČĺJ‘­‘µ:Ť´gŘ“n'Ôž˘vž+á+ŐŕüźB›'$­Ď°ĎzEó8cr#5ŞLM}?YÉĄ6B+‰žoŘ$;®Z‘űćźZfíxrĐĹÇżFn¤QOEËÔÉP5¨`Éć«ăÉÉëȨş8—zĄzÔo*–ʱ‡nmc°)3Śe=eBeĎŇŐ†ú)¦íó‹ĎąŽ±ŃĹHáË&} 1P™żPi§"ęÝ/LěÁ–ţŐvő—¸EKĎ蔑sűĘĹ›§ÜŰ[؄ϻ>lP\vkT0‡=y©ËPĄĘ=ľ©1鑾µÄ°0ęv}$Fi˝R½Ŕr ý!xós‚ÎHVôáä%Ă@Ń!3Ž»GJ÷ §ôÜ®®B°}ąE±B÷'ÚŇ/ái(I§ŢQ‡€gĘĂ5Ć6¨,Uşíeqr«”ąoďžD°qô9’őꂜĐć…c± 8ŮkU%µŢW·ůšŢĺµv…tm ÓŚí«¶ńd1^”_’ÁëÓ*ń·«gk–ŢžöM„<”’[|¤`ç6čjĄ¤ÂÇ0LÜłčĺGŘóWéf,Ő—/%Śľ#b[S–˝µ7=ľiˇFGĄćůt‚ˇKť©/×1ÇŽa…7oµŠ·‚5—–@Ů;‡ ŞÍĚ—V>aVk/Ő[)ś —=kb%'Řçľ~ĄÇ|Ňá6ubŁŤ2Xr»łAy(UB”y‰9.˘Śq*SúKą§Dg÷;Ŕ ’Łź|{öí6ô oMűÉs-ŔöRŃ÷r4'´ććŐŤôüŞ›QŮFXhj[˝Üf(Ns~¦őş±qȰçΔTv§ŃŃ ·Íő1ź†ź”%ý9žéŚĎO-–ę ÇOřżD ”ö´±dźLG‡ň¶QčÄ{ŢňG<Ľâ6ĺ&ăËCąÂe¸ Bó)߯ŔöCńcŐ9 ‰ę U„î¬ÖdŮk2ŘŽqé-Ü–‘‹¤’˝#L TŮźJ,`ĺm}ŚÝx"PSŁă‘űb˝Ľ©Ja*™+çmňL? ¶ÝÁăÔ{_WµqKxsÔĂ˙ÉÚ‰ ö~™ÂXŐOĺí—C‡}ë]ëny7­%&5cüťúf!oAyä>jşÝ #( oĎ.‚O ")ív˝Ĺr\mφ3ßöô‡.ĄňzçĘ»GűÖ1·–_LOödI1ěfĄGC©—ZRčýFóBmđĹ‘EŢm7r¶#Ĺs”¨7/n…_MŇŠ:E11˛dĘHľ;kĄ5›Ľ0§řĚĄAQB”(Žvĺ˘p÷˛íHŮŽ0e>UŘ‘ T }Ş`©”ŇÎßäľE#Aϰ-.ľµťäY´ülÚń]űyy/·Ă°Ç™śžpp»‘ B÷aĘŻ™ňy™Ó‚ů‹@Ţ Ťşť uyfŐžă2?ż;ʻē°Ôc5ÚűKĺeR˛9ÄŁRő.»ääW "ÓëY$ë(,Végĺ.îoˇc…ѦQ—ëS•&!ODo9ěř°HĎ"™ËŤ‹đŽ©Qo˙…‘9˙…7zWĘ-ż(Ňą¬iFĂ,’MP,4°,Ż+˝sLŢČÍÖyPłĐŞĺ‡Çu÷N‡Ú+ßË;¤w8Ő—|R»a—t­ŠŘ§đĄRČŘvŹ<ř*†^|öÓBáü‡~0ér›´¦úóЦY­¬ĺ/Ń$6ĺ•fî ň•ÂćŇ Ś4_ÝG_żZ*TÖ.MŁůP–¤$o7Ăý„ú±r©ěn*"ŮÜ»T/&ʢě‚ęÇ%Ű+=­” !ů8ľöÂG]ź^zZ–é°0F«Ę“x‡8n߸"î@= oúř¬^`]¨˛ĚŻŐö›ÖM~#Uß*«paí—ĽĐŽR_ýCNŠ÷¦$G˛“#€l/Ě\&’4uěI‘GG^őÍ©GĐ`šFm{€Ćí8;˘N"EIú€a‘-Ę8˛S…\ŐRKηąéÔOO|ęë71˘,@–°E§d\éžĎ óĘÂEQ2wyÚŇ!eŤĹ†:ľ)Í«ăUkŻT®×)J%s\«fZвϋ&y . V¶•9tąÚPo;_ŐhY*y‘˝z8,q¸ťŞŁh,ĹiľF®ĺ+.+Š4µVš+™śŽŢtj@:I_¤SĄ¨]Çůťkš “vČť0eIđ#+W>—ÂFÂŃpŠşŞ(„¤Ś´,š˘Z(Ţ {2*šĺ›Ů=\0P îđ4ŞC}óI?ăń%cEYŇ'c⪞*Öh®g›©·ËżČ,1b˛E5ÔçmTŢr©š#ĺČö»@řĐ/wĎĆš?¤Őôą ®(ÇÉÝ ˇČÂxX\Č8ůÝ;/śu!#ç¤Ĺe8MRHkB~ŕyR0n†węIÁ`gzú׊ĚcëĆX°ďăQŐ†™Ë “7$Ę$¶QüwX1(3©¨ÄĽÉ0ýtŽ©Oľ‰:ďpQěôd—ô pţÁ•š·žŰŁđţW­B˘bŹä]lí!)Ş…˝Ź^YśşG‰Á„µŠťj"WQÎXţ2ł‰}¦~±í_9ď‡bąŇ^H*~|ę$ń5ĹXXXł:ëłęĺëç˝ÉxŞö  ÷ĎŃ»š”P«ęŢ3Yŕ·ÚqYö-®‘í â¸×źHÖhJ~–Xŕ:÷m’ÚďôĺŻW(~Gľó…Îä÷+« ÜVůÜa=+.a†ó/Y ·ë~Çöµ—TJŰW¶äŢŕ”ů¨ďóvüĎ9XIÎ'c( ŕ‰JŚó–ě+A_÷—3 Éu-Şśiϡ 5L#Ú#¤Jzň(Ł8ÁŮNô°”ĄęŐPż6‰˛yŰÂNqÇ·"uŻy'9bqc…´ăĽž4&p‘Řřj!hĎURťl>GŽjOrá’JËk|ÎŇ—óÚÖ(śqÉČÔ8ÇôÍg”ÎK=wŁČťťí(ĎžŘ\»śđq‚?Ňav8Ó·˘mł?úJčÝSd@Ë FÂűB”×-ǵ\Á_ĘŔiŹ'ŽÄ†Í<Ąš¬S}ěD^#>M1ä+č2m÷E2wü÷ćÓeÍßs’ĆŹŮ®”ŤÇ‘¤84giswG~SżČÚîti™¶ů\jͧSćm¤¸ĹŽ_7ĂČńLź®Ë+AŞBg9?ň’žţ rsäŐűŻ-Šđ"çKivŰő7_­äĚ8Źgďă g7°»Ő±ÄĹyD#Î\ ÇťĚ%ćŞIÍ5¶}vqőq‘¶Xi$ÔUŐ+ôGÚ(őeÔr'ŚÓ¤jBÉËź(żPͲŤ†>IĚľ\,ď§ëĆMĽ¬ąlmŚk<42\|Ŕo#Ř}îŃiß=§ÄnĚŇVâh<5 jÖ+L$đĹŤŮ8ÍEňfŹ3[yĎge[f×€o8,Č#ĎĚü1Š­p[ŢŚ)9H8NoZl&¶PA0Íš X&*Ó3SÍîŰBlŞXŠ­ťú†¦‰-,µ÷T0,9_ĄĆNJg˛ŔýbżňĽÚS=ĺĂ` füĹ ˇqK/; /ř#dşův)|§ˇ ?†î­jË”•Š&~Ű„ŹÖ˝|V`ŁäŹ@Š´4 ‰vc?u†'±ŔăŤĘĺ®4ĄĄŮ ‘Ż_•˘.§ÜůŘéčŃ˝uą/ô 6/{‡ÎBşx7(ëÄ|J«> ¸+Ę8#[ŁňLÓîŢŽ~JD÷ÚĚĂ.„wE®*ŻŠőĘ^3=>Ô%a9ćz˙4Ä>!+2DzDÂp~{ă~¬mqÂY€,™%§•OË˝ů¶FšJîĐ%őą¶Ž~caŞ'NÜxŢ˙dBX—\fĆĺ~ň7SŐĽn©Ë’(hń~|Óâ ,ČMVTń«v‹ ó Xł\ţ•¬ő ř µJŹ+]T´ăęűBíą? #=Ý@áR%tă“É„;Yq ]­U¦S‘_‹űĆđ7 GÖł‰ô(.FqĆm6Ao§ĂëÄďz Z“Î~¬ěĄÂn>©řăťßđn÷]·ń7(KÖ&âŇď$ ©3ĚXÔm›&>ëĆă kHŐ©•~¦ŤŤě`{•€[®¸ę±A‚”ý˝­ŰkG[óCB†gžATkQĚc¨â6Ţt0b†Xô'Ĺ’ˇ/ŠŐŃúrTKŞ•ČňO•˘¬×íDî®™¶×Ďőí ¨ÍBľě§psHM2Ü‘ćFđßč“-{ U¤śu¶ć>őŐeÜ*˝ 2Häü.-„HyĐäóÖ iňŹ ©'Ť©K éu2ęSIaÉĆŹWriÜtÇÇ<eß=ŻW+1“Â9Ă\˝ŚĚŐĂ@ˇŐ’6Ů«ótąnuéÜř`}q‹ ™(ĎCC­§śý#)9űöŐ*M6ű@2OŹýî¤tňWŞ–ľW ůńŐ‡&©ďr4„çkŹŻäĐ›%żľÓX«ůök5~F†č"©ů3›yąÝ\cę'’îsÇ€Ą‘}L_®‹Ćüqkőët˘m%‘“ÔťŞaŁ5ă’ô5J}9ě%yěô˛vă÷ŁVWU^6Ůlžáp,‘ć y żUÓÁ;$ĹÁý•ŢÖCݧ†ž+ŮÎ6¨Ť[E ţ•Ž‚ŹşłlíNݧxµîB­E‹äßhÜ©śŮFŃżĚŰßC÷f›PĽőď²PđşĄVź’pµĂťĐÓ0+ő7bżöië¤ýHY)SG»|®ˇ‚éŞţą}ÁĄŰDüĐ,9kc%gd˛#Rç’UáM(ľ’şKĽÖŕ‘÷ ľŰć[¬DMÎ?=#ţ…lÖµĘËÖřĹúD'áĽO¤¤-V±#(~¬©=[XG.šk¸G8dĎs?ńô‘Ű›Ö6VXěŕň°Ë‡Ň[Q5Xö”ăDeĽ«eng\÷|…VZÖľE-!H–±”Ü´ĘcCţŠKKâgGúŁÓ Ąl_ňkś¨_şL4 y)a…aDMV~n‰44D˙b˝‰Ëť«î9˙ĺö~ó`ŚçKÇś˝#oÍĺá)ŹxÂŃŁçć/?.ÜćÁéčż5«îÔ­޻Πqiâ*')Kďŕ°|BűTlcěť°@/…ô˘;KŢ/e q€ŇC›×¸[7Zť˝]Şş}6ŽunŹf蓟’¶wţĹ^Ż;金˙ŽÝĽýͶzżf€ě6Ń9j·§]wă±sl‘D†rakř:ń8‰ŢČR™z¦ś–“‰G˝s7}töjůç”9 $‡Z´kěDôöĹbš€©¤¤•nwîaÉ {ĚĚÖM…QbçµŃÚ`¶wíßUrßdß?‰Ž…z‡×öařÜě˘˙TBŰňxéu‰nŕp°kxśiN€â^f[ŔoŮąĎI{ăâ>ëá'”lá77eńéWµýÇ›tçťO›&ۇóYřDźŘrb®EůtŢ/yőôôsy{`úM͆q FëlřÄ”,g§•©[UËŐ›3öiÇMls …/ĺ:gč"l´On‡*sئĘ}ŁűoźKÎĎd,}–ăD^Ę/ríŁ®Ŕś®(‘Dľ›qďMY¬¨ në“đZ;Ü^WyŇ‘©GĄÍbÖ;‹=ĺ[Ě?Čą†“ÝôPÚŇß$§Cڎ*µŘbV}éÉ`)B>Ę|d«›l Ą”:ůe0µh{Ś}źŃC Íś Č÷đËoWÖs^¸ŚW˙;E%đJ®śÖ”ż";řţĄČĐ÷Ç‹ţqB*j̨W^¨LFăAË®ąLÁ;MdµĆŘßĺćź6 düňh·ý¸);řţ®Ín@[¶ć)ľţ-ˇéŠ^ťŔqM×Čy@Ő§Á§xcŤJŐ˘&ć’lcÜW9hÉ»š,ĽÉYpBßîÚŞ1»˙şôĚ15r,}Ķ~§LFşOůBag[áĐrPr‰Ţ~r=#_D…‰W˝ g®Ý် éş…Ö™})-řKmTďÇ]ö5L*2‘ oŽŐ¶ ™]ž×6Î3ĘŘJ0™×_”Ť>ż3 V E%ŠćĆďtFŤG1µ—m‰püĄl+K]ă?ŘG ĹŰĂeů•4ňEGi¬“4łĺťÝĐH蛋sęQ±'ŮúËÖtXý ˝ş3!°%ĂĎw®¶jë§u‹xDőHďřHR>’¶›>˙+D—Ń»jËÇZř´;ęÄóśőˇáąIĂşăf•Ń–_čm‚´ŠU6“,X–KŃ…y 2;óEFJbë'ˇ2%+§x\AÓ„ěuM‰Ĺ~ű’kŃÓžäR÷¦ŕ_K¸Ű&×(Ü,á˙2łž¨I‹ę(¦ŻaO‹X‡gGćk´Ů$˝©8^ĹÎ6 oq5ł"U‰±îŢČ–u ŢqoîlYá3‰ęŃŁ~ËĐ/›?ŁÇ-8_*Ľ™ŐsŃźą9xúógąŚŽß9‹ĆV\<ŚtgL‡¦šŕŮ.4ŤK>BÚKiHO"™"ÝUř^»;:Ö75—P]Đ,ľYHŹ•\ů5¬âW„ÓhkÎ0j€JŚO Ć­W÷ý1ŽÇ–´ä4•ůD“÷ÎjűI™Ż™ˇ&]Ě…`Ćsú˘yO^¦ÇM©V.ăŰ™ĐzJäc¨Y,g# ¦JúÁ¬ę}G7)˛ŐKŚW\%”MěáNZhFCóń¸öđ+Űś«ţG“‚ŠV.¶˝ů±Ł'Ů|Ą$MĎüăč62Ç}ś¤ĹW¸ˇ™0QĂ˝GçćŹÓO–čŰľşŕ!'y<ăÎvĺŃ®ŘÁ[őĎ?á ‚ß îbö–Yjz¸FeÓśĎ÷QEQ+ŐxÜŤLůüż—O3<“ń–‹ź<¸=ŐG·ťpVFšÁ0)Ż _iűńü@ś~ą†5É=kWFÎLOĽŮęÖĚĎcĽÄ'ę={©÷‘ă˙đř˙ ţźH`岀ąAť,`€˙±dúendstream endobj 230 0 obj << /Type /Font /Subtype /Type1 /Encoding 488 0 R /FirstChar 11 /LastChar 119 /Widths 489 0 R /BaseFont /XNOKMD+CMBX10 /FontDescriptor 228 0 R >> endobj 228 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /XNOKMD+CMBX10 /ItalicAngle 0 /StemV 114 /XHeight 444 /FontBBox [-301 -250 1164 946] /Flags 4 /CharSet (/ff/period/zero/one/two/three/four/five/six/eight/nine/B/D/I/N/R/S/a/b/c/d/e/i/n/o/p/r/s/t/u/w) /FontFile 229 0 R >> endobj 489 0 obj [671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 319 0 575 575 575 575 575 575 575 0 575 575 0 0 0 0 0 0 0 0 818 0 882 0 0 0 0 436 0 0 0 0 900 0 0 0 862 639 0 0 0 0 0 0 0 0 0 0 0 0 0 559 639 511 639 527 0 0 0 319 0 0 0 0 639 575 639 0 474 454 447 639 0 831 ] endobj 488 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 46/period 47/.notdef 48/zero/one/two/three/four/five/six 55/.notdef 56/eight/nine 58/.notdef 66/B 67/.notdef 68/D 69/.notdef 73/I 74/.notdef 78/N 79/.notdef 82/R/S 84/.notdef 97/a/b/c/d/e 102/.notdef 105/i 106/.notdef 110/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 119/w 120/.notdef] >> endobj 213 0 obj << /Length1 1167 /Length2 5165 /Length3 532 /Length 5923 /Filter /FlateDecode >> stream xÚísg<śí·µč5"z%JÔщ˝Eď˘d‘ÁĆč=z'.D Ń#z” %˘Ka-ę™'Ďű’÷9ß÷Óůťűţrݵ׵÷Ú{_÷-C!e0ҢD …€Â@9€Şž±(,Jzë–* B;#j 4D”•”=ÄD@)9qY9Q1Ň[U¤›/Ęů! ŕSĺ˙K$ P†CPÎŽ @„†BŕŘŽ Ŕéč Aű ”a0€ń_'<ĆĘ &`gG4ŔňĐA*ň—m„ ý7 ötűOČ ‚ňŔšđaMň°ÁH̆8‘Šč#±µ X'˙?Lý;ą†' ¦‚˙•;Ł˙Áťaľ˙'Ž„»y˘!(€ A!ţ-µ€ümMvö„˙;ŞŤÁś•a€čß”ł‡†łlčŚv„ś@0Č/‚˙Űvlż,¨š[ŞX üÚćŻ!Č6őuű'é_Ú_řcgröÜb…Ř÷?_¶˙*ĄŽpD‚ťŘë )ˇP _Rě˝Ŕ"I€?ŕŚC|¬_aŤ=ŔŽ$ŕ„D‘ţµLěľEś~qż „$@ęë… ~SR7ěÎŕß” @Ä‚Bţ&d"Hä,) A{˙ŽKb« ˇ(Č 1l]¤'ę7!Ž%ś˝ţPHD<°Cřc­y@Ľţp†mXäďţĂHDÎÁ:uDÂżIcëh˙d±F­#lŽ˙  (6ţb›€ü±~śC VŚřbĹČ? ¶ÔđŻ^ţ€ŘFĐ@lž@¬+ďßűŰ‹ü=•˙~çTT>ţBX…vŘ“âiIŃŔ˙Kčč‰BAč_ż3öćţ;9cď9âq$ť™B:Ţ wÉhŚ,R/­ ¸}MĺaS˛ţË®‰×daźR®ÁJßéşß^¨·<}‘M}ý+ÁWvďsfŹŘöŁ L¨{rćäĺWŻ_łýZ-÷łő|ż¸q‡mQ¶5~<ř.yÍ`|a¨<ÍŞ¸/o÷íVˇ!źšé:Ńgśîű^ Ý9áRŇ–Ů0ł¨zqă™îĺŃQóŢ7ŇăĎ r‰"nŰC¶{Ţ<-".H˝´9Řż{ź.wRĘń~r:‡AAqńZěńE‰9-­ç§Uą"JŁâŤ<É™Ź ą© )őf®Ç“ď–™ň‚„}ţ1TČtőÓ^…űCĐű5›Î¦ţÎ Cźńšü‘7—†·N)†ű0]˝'ACŰÔó‹Ikřîoç…UĹY=ľĺ´»ŻwF?uHőUÂXÎK?Ţ[ő“şç–˘Ąz\TŁĺ¬“ń S! Ę#?]10¤1ú9ň}™ôxŮ`ĎĆŕćŹóâŔ™yżÍZŁk\Ô,$Ű7îLŤqˇĹ§ňŽ2­°˝{ «­ű›’üŐOSÚŢˬWĽ.ÁĎ{”ź–ˇ59•N•‡Şä*d¸¦.6eĐßőŔű)C<_~dtÄ<|śnF­6T^FĎ$–ÇXrQViÁĐ˝Ď,ÎÝä>¤ćřrůçš ŰE7nÄŐ"*=m]ŠżFcV *ę‚—8#dWĚąŤŻ Nĺř‹¨<˘ˇN…†ďÁ¶*”ÁŻjg [§d"r÷¬*=nač[Žő‰0žË¤Ŕţk,”§YMďMslÔąFOç]łĆĹ+ťů„vg؞͍Ć/Ëâ—Î@'«ďŚYŤ2/ŃQ1w•ĐżuUÍ„ĚĚÜÉ^?ŁŞ•|ďns“ˇ~Ú׋5!(okĹŰ„y2 ¨řšwő&ŻĎ°˙S\űť§‹1yAdiÚw2j6űđ¶ě¦Ë^8 „pŕ>wv…4“ÁG` Ĺ>¸‰B‹ä;Mw~˛á÷}ČP ±Ô žŕgűťÓµ2oE\|goóőý‡Ű3őÄE‘űqÁ”Ţ+ęJČ<Şő™Cz:4’ܬ¤ďSAutsä M’í„ËŃ/ăźQ©Ç0îv\„*­8]U‘·w#\dcÖCEăřK?QąúČÓ,ÂřżĽ,KžÔĽr®ÚŕĘUéF\šu|ëŘN%R{ZkŹC€¨&µ#A Aą§ éÚ 'ÍĆâćĚv"rx.Đ›äÎAď¨uXźĄúŢ,lRq&Ťř4Pş|‰‹Śď 䥚ž=Â;ŽkÇ9ÝnÖ†ľ8Ţć Nxj©Ůőé®öăQä äˇăcY|'Ť“®ËÎÚ—U{Ö˛.Of9'©Žpôě8…ňH™‡dGItAĘ5Ήm_…~Ęçzm-•đ黹!’ω˙|‹÷ËAÇ ŰËîůN E­’ŠNW źůS6bsăŃ·!VÓŽ˘ç/jcó?ďE7Ëcš\Ž%[\ŤkuV¶™*bÓiÍü<¬źÇeŹé÷6ŞT°7͇(-ł+;<ô×…űáí˘¨C__“gÔäBéŃ|I jJ[{۸‡ZCbĎ:vľŇYŚ ‘1Z-éż×űˇ}š‰ç~ő1FP3aî ¶1.ŮďdíÝßNUöUô§boŔq˘ě]ůŰŹ#öM ©wz‡á<Ü„áŐL¸„®7JęËYQ0™űâŹ?áH4 ľX ă- Ąb”»&Ţu—ë;đÉ”ţFţš°2użi'ËÎ%VF˘ßßf…łUĺPÚĎÚżą¤Ę-őYz>Ę•Ň9I,Ëśâý|vJ”¬Îđ3yS›¨ŤS^ş†,¶…>’…¶§î”Šé7ÎHtiŁŘ\áoÉNÝÔ`I„äí’^šŻ¤´Đú¶Őć8? }[aňÓ `|É™TpĎř Q¤ö-O;Ě@NĄb†¨<ĹŃq îuOľęşÚ¦¦WúGĆ/ŕ™”kśs×"ß,ňZuÚPIž)v‘u9 ¸ ěÔ_Ďd±˘šxĺ‡×É"nWpŐ˘­Y‘ öĎÜŐ92Ŕ»zú°=§ĹĆw©ů®»jŮšů‰ěáwKËMůŕĽV ·z [IÁö¨yŁôʼnkŐĆz?Y©äŐżµ<ňí˘…OŠś4™’•>Ů0 ŞU‡›8¨ÂˇlS÷Ç«Ř($áĘŕmh'LťŕńAç©ű ®4ČËôşřOůl[WoC7­ĄĘĆTZ 9­siš}^tź-Ĺ“ěHżŔŃ|eW‘»ŠľŹhä­¸ľ&în9 X›Âđ§ ”oąžň…<Ţ÷Łú٤‰Ęńr¶G–Ô«9/Î'Ľ@ ńĄ—'ŞÓ81ôÁuô› ¤ËŮXq¦óUlőľľ™\kü-2JMŃÇÉ$Dx?řąfÍšŽkËHĹŤţc­P#ůĐS÷°~+‹ăŚÂ˘ě#÷˝÷iŕŐĂ/dWö×űÓ:1—„ŚŁĄfľ÷"uéÇËâ,Ý«bŘ~<‹&3čĂĺ3 0`i’{ěÍ%G¨]jySp3k…ď>ůúaÇ}äŮM¨9cC1­‹x;ˇOC_ާMŰťî´NŐ-iĂUęĘ[1¤K?ĽB×›ť!» ]Ŕ©9ćWﮩˇ2ĘLtâóçiůK5 qng-Š•2}¦ÄśŃŢË«{˝ůŰ2!9ęŠE—äĎßkůŕ®mGD‡lG`ň5NŰů›d:p3•ăp@´Őu®YfJôŹEy|iËűĂŚOšź©|BI[7‡ź“ˤě$Î=©ëZ=×/üBb|¨×yÓΛ÷¶mxůěZÔJ!I}˘”B¦mjžČďĂĚj‹Čő…=oďýž;6[Ď ÷xD;î"9Č BDhýëŹ5rx9¬;T´|@ć™y ú&†o_” ĎśäË…'…(Ť´ż‘WueÁY«Kö¨îö=I.t×»&´ŃB˝G†Ö>Á}ţYăC“•ó4 'ł&›’Ž‹žĺµ/Ś’ü2Ŕ@¶}›Dŕ{’ëł[±‹bUDô*8?ŰwŤî‹É˝Îi“–ă»7†+üŁĺ5Ů^fú¤z®DM(ő°çađň®«(ŤÍłč• \)ţžMńwş‚ŞĐĘş¬9¤8a©Ö$Rm|UĽB˛Ü¬L3BŃ8Č>í ÄçGŔ›úóě[v“ôÄeňfďö8{“íŁ?íݢµ§Ě]Jă¦ÍőQ3ÇcŚ·2izÍs9(-§í<Ľ ä~ô ˝h ĎĎÜlîËKL|±S&GáÂýňŽÁ̰×üÎG˘ŕ¨ÜNŇúŢŐ´/Ĺ“×oě-X­ľ/]„i‘!“:bL˝Âm÷­WŢŢBĂĽ›z—â'ž¶YeźöwŤoęp{i(ß‚6é-¨‘2…ŘU°Îŕ2ł[¦ź|rI«< ł,0ŤÄ—u2wE™ę Śy1[q3€ěőµJ"‘QwD„'¦¬M®W,&űňaÎcl›_â„nçCŽ6)™rß±nß#V˝p4e{™—\/‹ČvQŃâđ®'çĐZŻ'x—2íř±»â>±KŤQ¸•źXKŁzݧC7űŠwçĚ=‡ý,¬Ú>󑢔ÖljĹřç§‰Ń ÝQ®đA÷ŕĐ ´śÓo[ş‹î+±0>1ń}~QCN#…–!rËŞÄ'*TĺŚ1/cĐ+(~šýŠÓ¦ŽĂń鉄§°)3ľÚöžÝ2ˇ}4íÖŰąÚE‰ŮCf—9Ţ,şÖŔgˇ2)A±ĄőŽŽ?┣-Hě˛nBkx/\;dŰ7ÓşoÎŘ*7ěYÜÉdŠŻ)[♺h-úBTÄ‹!IĂ€I L˘XŐÄś°łôUÝ('Údž˛X.YZ{C«Ëtęţ(y™xôöŕęqćX w8Îđ~ÍăŤKd nŚr·!׬kJ}ď…3ŚUęjPť[‘¸ ô ďm°ćÖC‹g„«ĚÖ?ú¤_`ŞŽ3äńx\e퉗úö‚H ć_zľŚ­-VdUüÁĂZżÔ<~—ýNÝÎ.ž¤˛B(‹“öy˛‹’B,-4X{ŢP/üú`ăŘgZ»ďŕ¨@ďÔÉdVŽv¸ß°!Ë%‡¨]ČfrMČF©yNĐúĚY´p]˝FOź§í7zúÎŔÔŹ›!ęqýřšKŻx0G äN1 QLäýÖ'íeošbZs^:¤Důń*ŐH ’ZHÝ \çđ´ŘŹ&őnŹžÉ Ů!}ó™˝ć"`«PÁŔđdŇĽš nfîíÝREKÂem<öľK–GütSOúľôqŹO}Ŕë[Ż"mĂă—{¤mPÔDRRR‚qH¦dW˛f› Ż<žŢ,ÄÉ>M2.é¶´Ý&ěząZŃQg°ëŠ—›v}ťł N“1ŠzăFáϸQ•2j_üC:)×ÚͧYé|“ě˝ŇýpoŘĂşŞ*&ĂŞ&|'áĚ…ĺq9µŞŘkRĺq°ZWkîćEަ˝FjŇsßVYŹŚČ8Q÷”Loß»xIÇ?Ô؆ÓXp–dŻeć Af÷"«ĄQ+‘-±…m+$&M»Qű Ó*;îZ5«Rý‹2NŹ—îŰ8D÷CŔ¤x’K¶ę@ńĎ>ĎVPËÔÚÜ珻ϓ»ş,ľÔĽŠÝ7sš˘ăň- „ÍŰÔ”ä˛rĂöýÍvhĂć2ąęÎ/˘ą^OęÖ(ľs+ڱV\TÖŽcňżće¶ő<ť‰$`é”âç˘MV›O“ ´gZˇ_e|Ť=şôŘ/?` K9áű”ˇ©×ŹľhbÚ@3T"Äĺî†ĂD>]%˙mе•$ Äc—˛î3–TMî`ő›„viWřö-±‚ĽÁ«~Ĺ[Ús•©“×W;!çžH~›ËM3*LUĘsq´†Ű®k…˙™±J+ ČVbŮvvřnÇ­ź ĎBN6T:Ţľł\`DĂZIfzl4˘“ŹÂ-]ŢÉpÝá¤éí>ć× ˘PpףąĘťHu`¦Ę Ý[ĺF4řŰÍ>Ă0”+{‚Źô˘Ž”5e<é ]Q\_ÓXg):®Ä#Ą&ěZTŻK Kčôp¶‡ż3^{djV$Ú?@ëČËßęëU›^sĺT¬·DK˙ÍĂË´[ݰ‡óľÍ"&‚wśŁŻiąŃ«XY [$J÷-ŽőŘxp?f±eýśq÷Cî`T4¬ě¶ţBmř´ą[Ţ Šţž§Ľ‰)ây’ş«FKz×g÷-ć_ô1ŻŤńÚÜ^‡Â[XÚ DÜ•ń5×x›řZ®µ@Üôč}Ŕ'—ľűU©G_’s‰WhH4Ąeá‹ĐÍB5÷¤ĺÁd/¸é¸°r%|˝4E·ŕ˘'’»»p«`‘‡źÎ.ůýuťf޸7ňú_źŰ®ł•^Ł7ŰQGw|CmVß÷IČao™ˇ0[Ąq¦H!~“ňJÝd:ňiĂM×Ó 'żWĄ2\Žé{îűr‰]ÁîYv||gÁ馟b4vŮĂfFß1c˛«ËĄÁa§o¨źc.8xĆ'žÔéő4ŹVŐO©¨ă†GĆąU»€şľáR2¶±Žw·yT ŚŘ7 :÷ń-ĺţ8Wó8ŚMҺު$I=ImÔ¨3j[›[!$’ŘÜq!žłÖ,ó\ĽQn«¦ÜH"‚«Ň‡u0wźÜ°éSŐJl°›;ź·÷Ńŕź{× ×č„•ăé â«li°tó]čtßŇ‚ő:%qV|ţŕ'ŘÜŢŠ’A=® Ňbé_׺M2ĽľK€G­IĹăô˛ŕJŽŞMiŇ łmwĺë*]Lľ%ÉO?±k±ó ľvüţ ŕH»oBÔ›ßŇ#¦ĎOŠł]łć\@JNż‰ŇÉHťHľgÉbKăâSîÉ/GŢĺ{řsę¸d­ENŹaž0иťëČŤ  Z î1—Šřˇ ·—Őp­˝ďq¤źúƊ•s-0Ű]ž×/¤Zł†ÉG‚ß’f:V¨wç×Ó¨Ţ?¬˝ÎĘ8lO«r&ÔpyĘá˝řÁ"­Rł+Ű<άÇŘ䲰iv÷ŮäŤŰńśç»ř­,.Öf–%R\Pş¦'őf>Ž·9dç VGĆô)f"mą Ý·%XŻI«ö€'ř'â4řćíφA•"Ą©¸» Őj#,/Ksj+l×ŕ·’Ąćoą°|)!sEv¸ łŘ±xě(»Ł$ő®řćŚŘ—”bçÄ +ď-'b0ç.ťˇP+µé ¦ĹÓBü†ŮÇ›î•Ö2řM^4¸ętŐ$őO|öĹ{ŢřŞo;V'}ŇżŐĄDU‚×ęá"NżÂ—'AâHAfPŢi¬Ń–#Ľ)‚ĽůqÎV{Âg~??—9„îv¤z®, ˨żh°ŻŚf{č^ .‘§łŢ‚Żő’aQ»7ŰÚÇI%Ľ+­Ř|ŕś!vĎä×ÓK2Ą‰]®=Ń˙LJôüŹHŕ€Ph$„r%ý/AsĎendstream endobj 214 0 obj << /Type /Font /Subtype /Type1 /Encoding 490 0 R /FirstChar 11 /LastChar 120 /Widths 491 0 R /BaseFont /CSVXBY+CMR6 /FontDescriptor 212 0 R >> endobj 212 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /CSVXBY+CMR6 /ItalicAngle 0 /StemV 83 /XHeight 431 /FontBBox [-20 -250 1193 750] /Flags 4 /CharSet (/ff/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/I/Z/c/d/e/i/n/o/r/s/t/u/w/x) /FontFile 213 0 R >> endobj 491 0 obj [736 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 417 352 0 611 611 611 611 611 611 611 611 611 611 352 0 0 0 0 0 0 0 0 0 0 0 0 0 0 443 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 741 0 0 0 0 0 0 0 0 546 676 546 0 0 0 352 0 0 0 0 676 611 0 0 481 488 481 676 0 870 644 ] endobj 490 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 45/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 73/I 74/.notdef 90/Z 91/.notdef 99/c/d/e 102/.notdef 105/i 106/.notdef 110/n/o 112/.notdef 114/r/s/t/u 118/.notdef 119/w/x 121/.notdef] >> endobj 210 0 obj << /Length1 903 /Length2 2050 /Length3 532 /Length 2668 /Filter /FlateDecode >> stream xÚí’y<”űÇĄ©‘%»ňDöeflcIŚ­ĐŘ’%TŹ™g1fëŕÄ)-#J–ścOD–$DŠ(*k"E]¤˛oąC÷śăvţĽ÷ŻűşĎóĎóţ~żżĎ÷ó|ż?ą}vGŐ0xŞ'dAĄ0ÔPę(}Ŕ{ô¨.€RGÂääLiČ R)f ŇPzz(ŕh Z_SKĄ“L©~!4˘—7P4UZ/B_FÄ 2Ľ!_¶$G©8"ÄQ0d2ŕ°~‚8@táŐa(€'â€'äE¤Ŕë†,)*€ţĆřý‘ „ht¶)@‘mR `[ÄS)ä`*»Ävňß0őł¸E™lú®ËŻéoiĐ—HůWŐ×/€Ń,Ń(?—:C?Ľa!<1Ŕ÷ç¬%$qŠ?BDş1ÂŰ8o€’éĐF˘ŕ6ÁžŰ†Äq'çcv*?öą‘ł‰†cßźŞëĹŚú‹ŮÓˇ7¤:‰b˛ß?ľ<~ęeNÁQńD űBhë Ť†ŔŘ7MÚ)x(€‚نę*}`Ď$ Pi°őujë•ĚŢ$;ĽA#„ĹźÄŢü“PlhjÂ&ÔÄMČÖ&oB=áű˘Ř}(›­LÝ„Z‚¶ uc˙>ij0SMGPÓĐf˙:RG@ë Â˙­@ŁAĆĆ-fďë&ŮŰ… `ë}MĹś!±*ÎćEg?ĎçQć4ńşwѦěaWíŽčž$NňoO­ý•K]– R…řFyFĄV$éçî‡Ů?ł:í1ĺŐ÷ŃŔSŁ©ˇU’.ßR±!üdćŁÇwŐTĽś™Đć´ílÍ»ěz«éĆ—ćńL;E3DZmű8ęÝďÖ§ťŃA»X¤’ŹĹĆ”ĘkîsŕOńϋӊ}Ä9™űMGt)–·RĄ˙+ő~€ŕR6oĆĄďî3ź:ŤÝD-Ł/y2.PXáa}FÎ~űŹâ"^Ɇčhľ t†$é`Ëęëýń VEzÍ©ň‡…–BNÄ^y,QÍŐ[YIt¸+äĚ)ޡę rĸĆ1ÄŻËpŢSůţ_±5[ÁÓ §TôŁVs¶°Ĺľ[–O1ĺo…– l5o{DÂ-|°N.ß¶kş‡—łŠďJö~`h´˘C0<°%Ů®.7h“ˇ· qHbHĐŠW“f´yB˝Üę¤šj Éăł ŐÇOv»®*¦Ąú<ąĆďáFžÖŻ%Ý=± ¶JP9ŐlB?g`«ĄĚsŞ&Ś·Čd1P[:Gć8źŻÓăĺ!RäőGŢËę[lsČž­Ěş–˝¶î>?ż0ÓĽ•íÔůÂŁ…©Ur-“Ăq,[ŤîĺŚGÜd‰Ż¦kgšÂh Ž µ1‡šÇ‘±˛ň>”÷á¸ĺxúžśó VŁőܡW{#żX}5•ĺőžěXrY™ ?mßă°j¸ăKýîV\:U*ă#E-.µgN%ČěÔé`˘Žô |6v›¤b®"÷u ü$“ćîOÁÚaá•”í©Ţv>-žÉZüŃg3řtQóúČóčŘ öć«ĆčĘ…‰C7ô—&xŤü—tďÄj¸ę\Ű[‹TşĹ‚Đ3•¸ľË+ąK»»żF %n&{傲†wĐYb¸–ă2Üuń٬BÔ˛NîCúifyµÝáů Üř¦KÝ˙4—ĘŘŘő.ˇ3Ťť¬gEąü®őďî|1ŮŰö;iĘâĐPž€ŮačhlJ˘,P Ąô;Eü/KýVy3Ź“ç–T|řR—ÓĽ5É)W/ţ†IÄűú5®a=ŃüJ©ľËŚsśqł-‘ű^J‘ ŢDó4DŚKOô^¨EqLH&ŰŰiśě\}w.ý ęü4dtÖ.'&ŠPב%¨ĎęJ›i«Ö±\.ĺi0ćĐŕS~y+kô}Ůóáś»ű ‹‘w~°Ďö5(4ÖH1•lĆ"m¬‚Ľo‹ňF;%¦éŽ řűYýCIîĹဒąŕ¤GgN•‹âzNçÎ h•ZGSYŐo»^C?Ş„©~€Í{|¤tZHőŮż»Śń ®ôżIi7úţŐ^&Ě~B4÷ ĄářęžęĚĆŇĐ9.•2¦’î–7l Á©bÄŢ‹żÖ<ŹîÎ9ärŻÓ_ĆŢuÓ3ÉP-ŕÎ~/ń5™©­şđDčs’­e\ćW Ä!ĂšŠ¶Â™)Ţţ„tÄ'x±Xđžť°9ôÝ(˝xůVÝ„ľąíµbŰTJü?Í ×(U ëđ¶65ěŞlWM¤,eq¦űčW™<“_3•SxŞn,XO °Zo㯭5ůK¦>·7ݶćâf ô8ktj˝Ř÷­ ^śšÄŤ›Ł´ŔŞj㊖ýrľŠŁ]|lW:ucxnzÍ{ÚľŔŰ|x:ÔˇxZäqnR‘ŮËťj$K° «L»>kAGWĚ5ďqęĺĐd?3'eÍĂ1Đëř%=KąÄÁLŰľńü®‘n˛+ţĽäGć9űÁ˝Ę^ý­âż¬i9żQ!čÜżEiî¶yDéŢŻ6ăJŇŰ{gĘ®7›’TóĚC›2GXŕ›Ŕ4@’k§ż[1oÎěű‡­§-!8wË$Bńú›D~jüy—udLĹŻ'—CžłîvÔüťI—Ś“nźWé+eÉ ,z˝’_äU;ojO„jâütŘ}»Ę'÷Ąäš9¦ß”ݍ:Y?ÉzÂÝ5—­{ˇ?EźdÖk¦Šf¶ŹĂ9}áÂŹů dy~sá @7Âvęěą;ĺ¸lú1ŁŐŰľ3H÷ߞƛ…°üť\]zž·ý.ý”(XkiŘqŘ\-(»ŤîJýGéĹPäřŔţ/đ?!€#C ŤAői>°+Âlcendstream endobj 211 0 obj << /Type /Font /Subtype /Type1 /Encoding 492 0 R /FirstChar 58 /LastChar 116 /Widths 493 0 R /BaseFont /ZVXWUP+CMSS8 /FontDescriptor 209 0 R >> endobj 209 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /ZVXWUP+CMSS8 /ItalicAngle 0 /StemV 87 /XHeight 444 /FontBBox [-65 -250 1062 761] /Flags 4 /CharSet (/colon/F/a/e/f/i/l/m/n/o/r/t) /FontFile 210 0 R >> endobj 493 0 obj [295 0 0 0 0 0 0 0 0 0 0 0 608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 510 0 0 0 472 325 0 0 253 0 0 253 844 549 531 0 0 363 0 384 ] endobj 492 0 obj << /Type /Encoding /Differences [ 0 /.notdef 58/colon 59/.notdef 70/F 71/.notdef 97/a 98/.notdef 101/e/f 103/.notdef 105/i 106/.notdef 108/l/m/n/o 112/.notdef 114/r 115/.notdef 116/t 117/.notdef] >> endobj 206 0 obj << /Length1 1419 /Length2 8046 /Length3 532 /Length 8907 /Filter /FlateDecode >> stream xÚí–U\Ű۶¨q(VÜ%¸»+.Ĺť˘B@`Š/.Ĺ˝xq-îPŠK)Jq—"=Ykź˝ÚłĎă˝O÷w“—|cŽ9Ç7ÇüĎ$LtZş\26P+"ÔĆĹÇÍ÷ §®#ŕăćĹdb’saöPgy ô Ŕ'&Ćńřy|ÂĎÄž ‰a2ä .>nö`;€UŽíŻ$€ŚČÍŢč PÂě@Nđ5¬€.ÔÚóáČ@ ťżf¸t@î 7O 7&ŔĆްíť1yţňQq¶…Dţ¶ńpů÷'ČÍ.`…K˛ŕŠ6PgŔd‹ÉŁ…×ÁMţoHýçâŠĐéŻĺá=ú_Ł@'{ĎŹCť\<` 7€:Ôäćüꩆ ©©lě=śţsT„Ř[Ë8! ďżBöîŠöŢ -{µŔqý9Űü§Ľm+đh+ji)pü}šiíťaz>.˙,úWîßĚ÷›á˝qł÷đróňňÁáď2űŹR ÎÖP{gřă $ şą}0áĎś„ľ|{g7ä ÷ĺáv†ÂŕSđ–řlˇn&?€ÇÖţŻŘß(Č ŕqşś! [Řď(ßG˙u–˙„<ÖP''ŕď0<~ľP›ß!Ź;čn÷;" ŕyrţx Î X.óú=./łsý‘ń—5ÔĂíw@ŕŻmxţ‘ws‡·đ‚3Čäü;wýŹýÁUťí˙ýkčďIÂđeżgĂgČýC"poĹHî¨ó›ŕ‚şż nŁ˙ÁoĎďŠÁ‹Zý&xo¬˙!>^x ›?ŢĐ/ţá˛v Ľ¨ý߿×püá?®áôůŕÎ \úÂwîňÂ5ÜţŔżNâ„kŔţ@¸†ÇŻëőůá…|ţĆ˙}ßdeˇŢľ\b.~řď…0@D×˙$Z{¸ÁźbŘß_eđ[űo¶µ‡ßqČdŤůuj-ţĆá]SXŮk…ÂÉrTvDYpsĽF}÷LVČB"¤řÓ WöŐ:Łź„¸;¨;´^÷”îQí~ÚcŠÇA®ńisŹ;ž–;ŻZ)ŤÎ2Ô}¶]čŻCöź¶5Í^!jNŻŽ–% dź îçk±Ęë}G_¦Cč1ńlčÉ|#,b¤Ń­c ÓÁKs-‹ _ńÂKNDY™yíŽŃ±t m÷ řY‘—ôhzM‡oÝN+ łÉN¤ó]ú ´(ďiíŻţáęç™°®`uCç“JHaXuö+ ‹©Ňq…uĎcÎÖv#ş&ałŐâ-  »"Ő…÷Ľ'‰…ĐM>Ff¶©fZ),ő‰ż°ú™P40„$˛…Mş‘ŰťftNčŁŢ’Đ’r1iŹQǰ(éVçř‘Q Ő·µ ŕDęNc›Ű•µői;;Źt‹a2ľ2™3ܱxĚ'ÜúąNÔ⸙ͤĆ/×÷,“nĂD^Ą˘ať˛ç72Ťĺ–Č<˘RĎ©ňwŽé—Ú­XăgČąÜđsŽDdö–0Ś>'ľW-ĂÜuß#Z%ĺ,›Ŕ‰ąťT>dŘ´I«»ÓpSeFŇÇ]Č0`şô‰ŤĄz"±×SšfeüxňâI@ű˘HŹ+NŇî ľŻ†ŻŇ›¤Všb^č’tńŃňZ•»: „Jöô,:yło¤t Mĺő˘öĂÁ@©âĆ%GA2šŃńÇ%Ăź˝qqM¨č‹µl—ŞcÎŘ :‘h˝ŇĆĄëŃÄŕ ‡÷¤ĘrńIbŤßLŁĎŰT¤Ĺ#T©z-râZ F7ůŇ?dsJа¸P"ę@lű€ľ)Dó§´řIXÔďzĽI†M(2ß=#§ř,.FF\©Č–0$S7«\úü” &“'ëÄýÉŁŹ#C©°Śďuc-řZ^wÇ‚éşqţjöbŮJ›eľřî`Ź]bę ˙˝^(•„cłŮ^”Mt€ŕĄ+uÍ®ÜѦő™Iźď’GROŻ1ÝÂĘ4NÇ3·Źu±vt0äÇ\˝p_Fa˘Ň×6Ţę,©G2>w·@†©ÎoÇ‘óÁ ,5 ňů˘ OŁ·WâE‰™‰%»W%Ý4vźř"ŰŠČ^ĽTçL×EŔT*‘ĚżkX0Éú×ú¶ÉŢíÉK†Y#ďšő& « íšěN™×Ś@V\IÓöř â_í„Ă9ßS,Úě P;çą]ĺąP’!ŽőÚ…i”ŕ]tѕȶIÚâ§şŠ‹¤°®‹~Čá}´=ůu[äĺ{}w•t9+Šnl%Ľ°{S®#–FňɆZńŢQsWkTÂ÷7䫲â‹L‡‹’Ł/Ř"$ÚÄzÎT#ýĐ4î×\ź^xŮ#nNzů¶KŮ´Ę3`Ëî:M‡ÔÔ«o5Ů06_ö4fGK&ć®HYE¨&‡Kv@Šž'·dc®Ľřú(‡ bT9Og¶­ş•T6ć×ŕ‰ R>‚ŢÇBçqFŮ_±x;Ç łP^ň6ŰNâT»™ÝQú}¬]ű“C”đ/”üŻÂBćÉťügĆV)\V@PÝĚD×ŔKďÚ׊`ŰAĆĐﱓ_xĚË“¦ÍÎ4_Çç^ŮzČz}şs‘zw†>Ţb ĎAŻ5Kęśö đl­îĚ4$˛#M9MaUěkA‡ĆÁÉgďąoJŤÜk?ŤF'FŢI"ŔW×bąĐ°¦’ăîtŻ5ş"˛)—ׄbfĘ#m‰éőTf$Z¨§ÝĹc&\K_ŚpÍX¸…54<ĄY<ß[yH9ńÜˡaLXúŢŁ±ˇc89 #uř‡pxf§µkŻĐÓ}čÇHcv6+c™Ů8(Ěë %•ťÂ…ĆŘYdRLČämHďÖŢÔf0˝ăčµ?düů¶d:Â0úÇc/dYę¨!ŇŚ8˙¶^Ô\cz|ď 8Íą•‰ĐßęÔtĽ~,ĺá]řĄú5bË•x2tžę‚§Ĺ*2m®6ü0źűVCRÚĎ[’=ŇďH4”˝Ęé şŕ¶OAƩФ`9ťß‡łŔm“ ő3¦ófĘ3O:ŕŰçFg”ýő§@M¦CżRżŹŐU÷lw *Ńź9ç3 ťi´DĎé+dŠĂúő;Ë^¬§&Üc¨SVľkĹjVÎ-S‹ĽH}ŻÁdcKZtm5¬UÁČp•˝Ţő™O4…D8ťj!KO3©žCÓČÎ1ÇÖĆł&Ż:^=v˛>=–aŮ|ŁÚÔň©Ô‘D†_]Ľź÷hUÜŹb%›b ;ĂбşRč‚HWČXqĚŤµK˝Ą˝iW¢ř´ę‡L]L˙łţŐÎňűŁ,â‘ţ9!Ű\•çß“n;è© _%‡xó†t+EžGŔŽŽĺÇI@kĂ × 4;Óä!·µs…Ëfd:@s }ÎĚnv2ćáÍK&Ť]jim T×Ęëeˇ'1i´ěŚE{ěsK–˘Q5ôćßD§ZŹ Ża—ęuÁ&čbźŽH^ §„’hăâĘăúď/m#´ßł„KőŽżô­QŠA ąxoI%ޤ˝“«e‹«ů#_Ęΰ.Ţ$y÷Ą‡W•?ăî› }žK¬¶M´ÖBĹěÇj)ĎÇŇGn´x,¬9$‚Ř7>y·ĂÓ–>PMFg!k,7M)"¨€.×·˝<<Á#j:#'Éť§4É¦É `_Ę÷lGÇ‘ćRçćÖĽ:6tdüÖěxVËńń^r !!›4zžĚ -Ů!ĚÂjV_' Íň]žŢšáÜňKčÄDsâOÖ1ázÔ (ötfIŹşDëđÔ¬)Ús\°ůj0ÔÂ8tz_˝ś2XN˙ěU<ÓCĚ&ECµ˙˙B˛TMňŃ‹uł ź!ą›Ś&ÚŤŐB2[˛ň”Ä(¬ň˛řJ$79˛»‘‹Ý]űbuצ†WńşńmCä‰&ď‰ zĽecś35›˙~7‚Ó—r©/8ˇ€n¦Źă4µ’ö80m~ő§=D ŞőEŘ|7Iä­şŕÂCČCe™…T28gyͧsÖą(Ë1Rµ!ošˇ}^ź1o IČ^¸uĐaÝúš×$ÎóŰZż+TaÝt}Ĺ/ĂS‚)ąű«Ą{íÎÄ úťőĘŘ a†×ˉT»“ĺuĽťu-óµŁ1ţ°Ćg´xźĂĺ¸b‚ő†Żç†źŐ-SnĆű;'ć1u0`•č” xSúýę˛mpM:ş(ÎĄţŚáŢi)ň}K…ŚŠsâCđťŻ_&ś†ä_ŚH˘?˘×í·µ%29ě_ăPl˛®TvŮK'mˇpšLiŃEo ćGmwU'‘P<…@HŤmĎÚ[Ő˘fŹSÖs}žŢƉ|$ş^ř?ě™ę힂Ͳä˝"†¨ĂázXµĆëĺo íŰÜ^1:ćüćX0{OŽôHIXŮ÷pńT­<^0Uĺ¦'L›ç×ű®†ł|ŮŽ“”dj? ’Zě ďçzż2,ĚR‹4Đögî¬mő\é‚Ö±Uf OßŃܱY‘ÜŘ f›p„g)í1¨}ÎĐŃ˝ý2‰„WTžTžyÓd96[pő±óeC—ÝEłÖZrRlĚ; ëXĂOśąqť/§Pąc„É[ĺú’#Â%2žYÍgPIQł=^ä–©ŕż.áę[ŻĘŇzŻ·Í~eóµÖ]H6ćą*:«u–=Ă”ßtăÁĂ|řÓ˝zxIű"ę+†ö¤DdşO®ř¤ď¤E\ęNěXŮIŇ×ëz‚ˇ-őIOČž†<÷~Q›Ix|NĂ+ľůz.c=w|˛żyLe#ôY§‹,`39ž<&aĐZl~ś`Hyu{hf˛ŔQuHmsľH/FÂţ«Ă­I a-ŰÖęSÉĤ–RYfwHďĆæň‚u)šÉ%?iNµµČ*|çŚĺĆŞ×ÂÝŚpwĂ?Ae~×JBł|qź˛p~4ćcaĽX'Ż˝ľ[#?Óđô±yęŕ3ÉľłŢĹÖš‹=şrjŐđÓůÁ»xX/W›’]ćk=5Če;nĆ•ą÷17ĆQŞŕ2gµÎĽôĆ4EĺásOŽéUÍ}r6É›+µLŐü{™Ý5°{2ZqĘ$?U±xVÍŻě©'‹ĽţĄęfcÁG@‚ަϦ-|íÇă䋀Џën\Äo‰'‹QèźŹ:ií‚7b„fĎ jeL^ľJŃiBě˛M„‘54;,Ią+%ššźěLsę8?’Ń„!Éłß Ź‚ĎîÖĐr^l§4.É ň#Šô,wöěśĎ[ĽoKéKOé">ľ·z~@› aŹÍüÔÎ8ĂÜíŚOć°ŁôB ö>ůgpĘ"˘{láńq©öHĄř9Ë·‘!W·° ŇÚD ĽŰ¸XäŢ ‚,)ä"Ě=‘ë˝@Á1{Ş/zcčBĚD•ĘîJîDü] Ö¤#ě •6ÍÇ’3e7vćW8޲qx”š¸Ťd«DÝŻasŰ3 oü\ĺ'–˝iŹ@GZźS˛öčQ¬ŃMęŮZ{őZĄ±‡HS®ą€÷i|©ç…,ťÚ7jÍ^Eq’TŻO”ĽtÜ / YŚí5m,2•Ź:oFQ®•aT§"çš´@ĆItŞďl_Mצűž’+,ÖŮň+k?ŽyipQ ŁUˇi6ŢŽ ĄĎĺÓ–ÖŚ2ůF˛A€€ń]hč™›·}ň§ŚWIŕ  Ż%=w ţ`pÓ´5 eŮŁÉ,ŕ\b"“ôÖňeTNY{)°Îđ<˝߇ľ;ż'7\x5ĺë*Ö}ĺ5PPt¶ÇđŞb\¬Ľ4^ě]XŇNWă 2cůĐ®ŽQé‡fK@ÔąÓŞ*·bK··Ë[Ě<§«€˛T®C 3ěÇN’˘×şśTB§ÔLÄO˝—ÖóLř*~Č.ŮŘ?NŮ#¸äÁx‘qç¦ü㓞N-°33m ‘ýăÂz¸ s:#śĽD$Ŕˇ…í…ú$xË1¸g©VŃcěč$ݎЮĐŃݤ#Ć—A““±ÉňQ¨…Ţ |±ĹšĄ8`¬¨Ye`±Ö)çK@ŃdztĽŤ×h‰Že"„6â-ĘYużmů6Џ*‰( Ă¸Ž azčžm"kBˇ@BŹűŘpÔ0`äu%Q+OR«ĎedOČ^JŹçUByĄ`•ŕNlţ¸Çěŕˬ)âĘK Ȇź?ŮŹŠ‘°UŠ×ňpľ"ľµş=Í“úµöG—žzóZb ăU4őĆÇ-Š5ΩreaőY1„'¤†ăşh łí—ÓŮúj',=ďižÓĐ.xN¤EÉh7xčOsN÷ţp¸~nÓŮN2·š^—ʼn%pV.ÇúZúu$‘ĺ˘ĎŽÔOËŐ<ó…9ñ0—bëé–“âd]6o&›.ńBNqnÎ_a“g†@R W’ú"‘7A¤‚Ô^ýç ŕń>Ĺ›k×T5Äúź ŹŰtsQŢ1 +\:máĘ)>r÷ƤťÖĚ[AN†“dŘÄ+;ƧŽMC&ÜŁŞŐ4F´î”AbJ cď—”EZ§ÄŁőqĐ Y,N‰"ÔČ7‘†Bş!'é˘ʍ]§ăljôčR"ŕ) zĺĺYyń8[GßSpR,G3Đ Ćř9˘T3ä¶Í¦Š­˙•ďc˝<ń¸Dv~x&ÔSČ_€-Oać­Ş– _˘~}t?g­í€Ł†,$™`ąŚ e‰E1TŃ˝ŹÁLĺ;‡±ÉS†ŇXzË‹Ö NĄĄűöůĂĚĺ4ĹǡˇÉ©ęâ Á”!­ŕV–ąUTF@#…}MáČOl‹°™¬e{Šyşµ|rq)ČIĎţ©@¸?÷Üaô:¸hbfçóřI+$úľC™U»Kî„ç‹ĂÁDűMŢ‘4Ö羪 ßf65§Ő”‚Uófúź%Y™ĂSŤ?G~đËęĆîÔ˛ Po[ˇĎŐítŮ/‰˛ĎY• ČV´ę7ęĆ!ä”dG)8”ô ŘeÓ3«çZˇ ˘C“Ł[>ďĐ®9Ú@ąŤŐ˙!;/íĄ/ &ŹďŔR“­š&–_~Ő:TŚżâ2OŇ 2Łl~b1ă?§ë)G‘łz„VU{sľŮLôă"ax9s§EHă}TJĺ; ţ(ŐYm‡Ň×…y•…ŕ&#s›ýÁ"ô) CÂťTMQLoËĘá˘ĺŰÚyd±"°ˇF§=îsž% ĺ~ŠBÄHIڶęHě2 ZaDľ%ç`× ŕ2tĂÇ8˝Žâu][ 'ÝÚsÍ»×—ć)&NF"e~6Ů#=S¸5 6rĽ’=FMŚŢ@ľ€Zݤ…xfCŘţĚÚť¨ýöäDUŮňăŤ3©G´3ˇăäĚ+\ßX`ĎűÚ§Ą1ę¤řň‹L-©r#ąYÓ.” ăź‹Śţ¬Žtc™%ŽÚ:l{-Xϲs8*d>ű}áÁ ^í&ËG=ç&rŰĹL'ćŮ™(ě\˝YÂěŃE—J,™Š!ő(ÄůúNcÚ+nnÄ)ô‡JpFc—0J¦?VŁ0_ĎRŁ’óťüúôĆ5j暪WŽ RĎ7Łe) ,| ¶ Ş:çąh,bćó¦SEN–:=i­-uVÍcOpجčť]7긏Ť RoÝŽ&zîL‹Őő•ĽńşĽ6q V|V·ÖŮoM!9F a»ŕÍţú–ťöťvq«ŃýŹţ{Ó(íŔŐ/+§‡ĄÄ;2ץietÍ^+™ICyPdµLwŘ šAYěpeV†äŰwçňşÁs2C™lâň!«yIam ¤^:ÎŽČOöŞĹÂ}+ Éäţ-ŤÄĺInÂHqűĄuŤä– ŤÎńM›÷P–×W"öU¤./ŞĂ˘ŤS· ×·Fh~6ÉyšqRůň¶ĆÖÎ`|ńFŢŻď2Ś ťIŇsČHĘÚÔîrS‚^Jţĺé>˘ .‹ߪoîˇW“KDb ľ·Kü˛Ą˝ŇóG“ dPbDmÝPűRĄ3¦2Ű\ĆS.Đ!nMÜR‰j“¬¶ţ˘yÎÝFD0eGÖ{.j±r¦ýy™\¶ńľäűĚWĘU°´Ń§Gßîm’ ü¦ťśÓ™(r IÝÂű)ůę.ą3Ů· Nzż«˘÷éŃ~ŔĎ:ÁrKŻžN±/4É»$uŽż¦ršůP;@ÄŞ˝oćŽÉ$˘4¬ĐO©‚Ť÷oH[ß…gǧ‚XŢó)ěQ^‡±,»c{ćrkÔ$qLz=gěmö¶cSçnóŽkgôÝlSFvŮŃĘŇńzBµźJŧľđů"팟šąW#q¬4 âVHo‹ÉKŔĂśýKY_w‡†ŞŮŻś°Ú·śhV嵎YbŘŐ’D?b(ÂjČF±Tm2ŹÂâ@T.wz»É7­i^Ŕ84׸OwĘ ‰Üó<*k;šd:®Y«®‡Ď™R7ŰůŁ-ńkž^צ¤ŐË/Ů8bf°Ĺ´†F(“Jld|ÉáUĐkç.JîŢ)IE Żî>&i*äK˝öđÄŐŞH_16rţĄ”|˘oÓ7ţyoĺŢY/yGŮókŕbčĄwŞŞÝzüřQziÁN¸L™Ňbč’“îÎí Y‚!ýdv5ËÖhgqć~2Ě$U<ŤF‘ĆacÎŤ@´0¶­ÁÖ9u[GN‘tW&+“Ö ˙”ǡ5ĹYvÁ7HĂ(Pú®4Y^ŚÝž6pŻąąx{ťů„şu‚8Zv—iDU‰k0ćxkCZµ­đ`ż¤ „îÁ/éČć:đšbBµ%Óa^Â}ť(7ţńÂň>JiĺĚsőŚĆß;. ±ď‚Ę yÄD¤‘ő€\r ů2ť «ÜĹßµ«§µ:µKMáÇ<0Ý<˝…-ĘĆĘĺRŻč­7KŁ‘đ5Ńđ"LĘ  1¬‰9{ŮZ»hX`jVD±ľbAű’â'ą+Y’ńŕGË,¬GčOŠ»Ĺ¸P8đ©ré¶1ă}Ź,(ŐÍ—…§RKT¬5űpi»7,¦řt' $‹őásys•]Ň÷±L\AëĚ4ľ}ZĄ÷ąĂÍ­,¬MÇÎHK'zż]—óµ­˙îK„U:E\ś]Îű÷„;ż¬ĘVř˝«ĺŕi7Ó&2‡§ĺ?-׫„J"7ÝX&MDřH“…ŁŻ˘±&›R¸˘¤WkKvSť®P¸–ŹĽ(X~ôۤ)~bÓɰ U9˙uś˘ďşuťä$ăë”Ç˙ŕ čXUĂuťk7 !#¤ ›ŽÜŻ×±w; ˘Ůü´Ňú ˇŐ(Áů•‡ĐCv§±dŘ”«»ł`ú›ő7G_€o˝V×(*ńE#ĆBź.Ý(Sr iŽLdmRČਣbćáy\Řö>™†ĺ•}sPZ9ĺ» ţśc‰ îă6“Űo0$6ăľÚqh||–¶n4ĽQ·őµDSpéöv†łęámĽĆ kއÓS TB,;Źäl±ĺ-šŞzR»šŹ­Ő˝Ž5oc]‹Ń\S%Îý×E§ŤĘÁqýF·6‘ßÖC»hAČífĚv LM¸ß˝ő?qú0§”­]cáX=“‘íÎň*)Ľ»źXOaőmIßö–!ŐW˘Xę]ËÉĎ\Ëůŕ"˝Á$Ăf‡h­"—ŻŘ&~®QŢŐW”NßËÚ­ÍĄČ‚±[zŢľ9”qR»ˇ˝ ¶cĚÄx™Ň$m:´ŹđBëíűĚ’'Ă·螲7fTơ«ńá\‘{őĂtɇsi-Ď™#Ż„v©ÍĽ"ť”Śf‘ú”C»ôĂŤŘŠď͉đŰé}Ä ÚŘ„^çäŠöŁ­ą;ű KQ»§ˇEŘőöµţłĄ]üćĎ?Ű2jĘqÂŃĽĐm‰ň`zĐäˇÂś›r,´W¬čĄď.H†čÎR /> endobj 205 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /QFNXPE+CMR9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-39 -250 1036 750] /Flags 4 /CharSet (/fi/parenleft/parenright/comma/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/at/C/F/R/S/U/a/b/c/d/e/g/h/i/j/k/l/m/n/o/p/r/s/t/u/w/y) /FontFile 206 0 R >> endobj 495 0 obj [571 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 400 400 0 0 285 0 285 514 514 514 514 514 514 514 514 514 514 514 285 0 0 0 0 0 799 0 0 742 0 0 671 0 0 0 0 0 0 0 0 0 0 0 756 571 0 771 0 0 0 0 0 0 0 0 0 0 0 514 571 457 571 457 0 514 571 285 314 542 285 856 571 514 571 0 402 405 400 571 0 742 0 542 ] endobj 494 0 obj << /Type /Encoding /Differences [ 0 /.notdef 12/fi 13/.notdef 40/parenleft/parenright 42/.notdef 44/comma 45/.notdef 46/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 64/at 65/.notdef 67/C 68/.notdef 70/F 71/.notdef 82/R/S 84/.notdef 85/U 86/.notdef 97/a/b/c/d/e 102/.notdef 103/g/h/i/j/k/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 119/w 120/.notdef 121/y 122/.notdef] >> endobj 202 0 obj << /Length1 771 /Length2 963 /Length3 532 /Length 1528 /Filter /FlateDecode >> stream xÚíR{8TiŽ’mŞMWާúĆe‘53grYíQFĚT”˘cÎgfÎáĚ™\KT”’.žHşz¶ÄSK‰.»’JR)ş¨µZtŮCŰÓłús÷Ż}ö|˙śßď}ż÷{ż÷÷±=%ćBŚ €.$A›#Ä8‰$«¬Âá±ŚŚś(Ň8I,Bih U2€ĎÚ–ŹŘZX˛Ś€ަpY LśL‡HÖ@¨€.E Bé ¨`4¤¨HH)i5ĺr Úˇb¨„T8Ä8,.ĄA”á‹;dČŤ$ő§6¦ ý …CJÉ&ŚISŔXÄHB® dq=Hć,Č8ů7LŤwQÉĺ¨bH~(¤Ż`TËŐHE¨Š†‘¤‘TořÉ›b¸J1uŁQ9.29ć%‡g!řŕJ<bž8- ¨\ ‡űŔFZaŇ6ÂuŠ-s4ű4ŐaĚĹ zą:ŢňpŤ|©™Ś(<řň8<™őůoíłś )‰á„ đVĄ(TÍâ1R|D"'0`cË!HšŮd˘A I±††j¸¨’I W†03 ‡ű\ •ɇz__ĐŃ‘Ś4·ć6– bÁ·Ö ¬˘˙Ć“Ş( ôđ bRú\âL˛F@)«é6)µŰĽ˙lbaŚóảZÜqý×N±˘íͲŹ[s–Ôö•h+źh4­ÓŚJ¸ę˝źŇpvŢŽč†Ă„o ‡Ťý{)L´3\lµÜ7Eş˛+r†ßn{µ–ÎË7Ż6u‹7?->ýűÉi,ß¶[3o«ËÂój‹’ ‹+ąZÄ€©ËÁćT˝Ł—s*Ş6®YUQ8X«×v&j…‡^ËVłvçܨ\ŹŇq[VVĎ|Üw•_ş-ě…®úëMîmöw©ť˛wµH±-«ś˙)~\v–·"†šću2fN•2ŤÔí*Üńłč¦?¬ěw +ýjkŠĘżí˘âÍB˝yH¸0ŁůYcgÉŤäśö1¬ČĺÇO´śŹťŰaĘ[R+$jžíJe'h*]ž(őÝŻű«ŽvË Ju¨cě$Ó©ľq=׎ěMbR9şűmctziđü­ w[ž‚ُ/Ž·ÇWŢť\>9zíáh<ŻYW™Öąwí9É5×:źoq~Đ˝ţ…ë_ľ›X`­Ľá›[’U9‘Ć+ ęJ¶$Ź!Zćp$íîěDüDXŘŁçćn<¶´ńú },Öf”Í­r}HĘ“;D-gh ö: Ҳ.®2{qçň+ő®šŹé=eSrşŤĎźôUT®é7l¨ę Đqß”Ř5©Ľ˙Ř|ŐÝś¨|—ĄÂŘž–éŹĆ+čă3§ůÓŮ6ĹqšvE‘aű˘ÇŚrwoő*µĺ†nW{óţáÇú_ŕ?! •C”˘IJ…°ţ¤;endstream endobj 203 0 obj << /Type /Font /Subtype /Type1 /Encoding 496 0 R /FirstChar 3 /LastChar 121 /Widths 497 0 R /BaseFont /BAMDOB+CMSY6 /FontDescriptor 201 0 R >> endobj 201 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /BAMDOB+CMSY6 /ItalicAngle -14.035 /StemV 93 /XHeight 431 /FontBBox [-4 -948 1329 786] /Flags 4 /CharSet (/asteriskmath/dagger) /FontFile 202 0 R >> endobj 497 0 obj [639 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 574 ] endobj 496 0 obj << /Type /Encoding /Differences [ 0 /.notdef 3/asteriskmath 4/.notdef 121/dagger 122/.notdef] >> endobj 199 0 obj << /Length1 1516 /Length2 6486 /Length3 532 /Length 7369 /Filter /FlateDecode >> stream xÚí”e\”}·ďAşKş†n:éîn††!†PéA¤AR”%¤KJéNiÉ3÷ýěç†óě—çĽÚź=×›ů®µţkýÖZ˙ëbaĐŇ呱…Ů€`P8?/ż@V]W—ŕçbł°Čş­áTΖđ‹‹ód<íż¨„  „ 6 @ćęë±w€Ře9ţ ȸ€Ý! k(@ÝîvAäY;ta îË qvčüu ö»{my±ůů¶`¶‡@±ůţR¤ µD˙e¶őtý·Ë ěî`Gä $Ú ξ[°6ź Q ŚPň˙CÔ&WđtvÖ°vů+ýßSúo~kłďEŔ\\=á`w€:ĚěýĎPCđżÄ©m!ž.˙éU†[;C@2P{g0ř/ÄCâ¶Ő‚ŔA;kgđßv0Ôö?E ÷·>ąçŞŞ&Z\˙µŃżťZÖ(\Ď×őź´E˙Íü÷ŚŹ;Ä` äůçß˙Ě˙Ł<ł…@WBX`íîn틍¸řń P[°ěPĚÇ …ÁGˇě`îŘ-±s>»żmŁ€sq±ľ·ř|]ŔĐ{“€Ď±Ií˝I Ŕ÷ě»7ř`Pđ?, đÁ˝ďýÂşpwđ„§ű˝Aa€x=@ó@ŚĺFHó{=P†ßżÖúŹEŔ…<"‚8$sOĎď ,{Ožäî Ńü?$ŠhGážJ•ď ‘SížY4î ‘EóCdŃş'Ätî ‘S÷ž­ëݢý{B¨6ü‡ŻßýöÄŐmî Qôńĺm b%ŕř×> BĂDH€<@Dç(ärŹ»Ď}€B°(äúŤ»=@D]÷ř×Î bÖđhŢó"Ty=@„*ď{@Čđ}€/ţĆ˙ţ6?óńăáđ .˛8bŽ˘Ââ˙WČÓÝ …˙ýĄD|ţÍvÄ ö°g~Ŕ@OBSľ„}|)ź?ň Ťůą}]‚FMŰx3Nđôdç˘~U7ÎĹjŁË’tüM´Mzďkjʍ&íď ‡n ©“·›^V›é/¨ŤŽÓŐ}7\Ďw ľ~™8ÝFÖ[řřÖ¸ ;ë¨g7W‹]No cž©ÝÔ«¶=#DDÔH!ÝY?<´šUA‡0Őíc„Př‚7áŰDÔ…áŕ—Žáő\sż`MžÄ—ůď“nÍÎIă‰@ÍC;±µâs۵}Ł©mbđĎ›W§‰đG®ÎM´EÝšŞçň„ۉrěF?2WΡęśĂż ŞoEčôŞbŢč×ď¬CMHÉ™ĂĘóGž×OgĆŕ§ n,=Q€ůŐwôě«ÍŢé_»Hmbµ¶—J@í/ľ^đ„5nk‘•Ů\WęŮcróšŚ+ÉŤĘfrźé'lřż_T˘z!´•Ć_ĄýT Hjí*ť®ZŻ0A<:{5ŽÁř‹§)w°§¶©#˝rěŤňžn|#‰SĐęŠ/R5;ß/ĆC<Ĺ:ljmő%Tá}¦ÇÍż]ňd‰^µś‹Ç§ě&{cěz|_6R+ěP–TÍ6çşŐ}×"0·¸Z˙3Đąé(ô<ŕ©:®,!{RŕźÖjÍS:‰Hg©>~´Šđg\'/Q«Ku$t šň¬Ż}vÇě‘Ń>…ů˘Ľ"×,‘+EôA›Uˇáq•"Ň®Xv÷÷á'X ˝¶Ť'“íäÄBös249<0ŁA×ö5ť.o7`еšćD÷÷54Ë´8wů„¸ýÍe";ŢÍ1 L ß»‘:UIö#e"Kv™á¨¶Ě?°é´(Ké+É[‰÷ß .ë+ٱm?¶Ußň{^‹Ýuqfâ~%ů™“Úş˘ˇD аX}Ă6€Y)_ňčnĐÚo7—ikţĐc˙U÷ŚnSqƆŐč:*`i8HŢşš‡¤ëň›¸KžÂčÄ$V;›†­Á]¦;·ó%52ş¨Ŕ¤Q»“@ľESKü®‹_L˘Ţ’"‚Ü"’řĚ™ŕÇĺ|U×qő AźIYHŞ•ÚUżäÝG=7ż ™`Áwč ü‰™Ćů“[´¶îČš{—fN>«oŠIÜa™–%×t săÇJŁ/ĽFŔ”ô\[®Ć´éUSőČv~M@žaVĂ™tŻRŢĚ7 ň…őDÎ)çJx?™Î9…ěÚ çŹĄď‘ŮľΆOő”j…íOŚ b ő`ł ŐOČ{ă›2ďl3†Ą§"Ź=B%ašV¬‘d×čČ—çĆb.řˇ€TeÖşk˙ţťż s,NĹ\"}`VË,Ýőd?O@ăDkî¦ü[ůľIťO›Ą;ŤÚÝ©ú-k)ĎaţIÔĄ6R8QăBŞOĐÍ©Fzž…Ĺ꤉a@\ŻI%Hý2í­Ţ´˙Żä^ç( RW*?c뛼¬Ę­Ľ|bößB7FÖ†i ==—üsLŢ]ĄÓ‘SS±ąĺĺ‘5wšf`z«€nlo»‡Ôµ»°zu…‡čÄÖ-ÄŐŃ TgdńŢ„V ø‰ŰOÖ&»>đ!t®:xhĂĽeďÄ‚Ą€·j‹Ąs„×Ö!hMÚ“ŰŚy\kFăÓĚJ¸á˝Ĺ‰™qäe|·ÁşNűâŘ,·ěżŁNĄë68î0e:p2ÖWą[o0P‡Ä? ú.ë4ç n˘Vó¸˝ý†šKѨř&4őÇSdѱ˘ĂëląŇW0A/QmĘŽ~ů5©uÇŇżü¶b_ QÁSe^‹Ăçŕ2źL–Jçťĺ0¬ťśmA^óĘé§JřÖľ,ÍTÇAdf1ĐáN~&Ĺ‹ŔôĐ]}ëąěĺŹbfÂ=ăc_¶NäŰŮ{^<,ç´xkŽi˘ŤŮrwgďróŤ'ń±GIŇ,ˇ|¬Y¦ĘŘ҉•N='jÖXNątbĄ6–{/~ťč‚@’ěX—Y•¦K÷«¶XZČďŢśô`ĐĎÖlťaËRËţ /":_!4ËçSôó¦$Mr›žĂ‹Ő•ţ§˘gňO–ŢfŇA~5iÁiekŽáϢŁU7e€{\ 2ˇ[Ň'ýęÔÁň ç»((ÄĆVż_;MIAňČÖ~%ôŚůýZUžč›ďµ®>kÄA’ČôĂĚ$ôČ[0=+V}®“łÍś&»ůýóŞ˘č*•6–H™–…ú«TĺÇݗpNl§‹ë_‘xČĚĚŹ«co®°'ú ¬—ĚÓ ^8g}Öž2Łó68%›[±m¸ŇFţ9˙ü”÷˘ŕŞÝ5ç`pŘw9:ü>n?úĺđ$/ÔÇ­x"r­[YĹľ•~Ľ8Ş)¬Šśíęh?ľ(cFr|ůs0şó˛LůđëŁÓŢąťw Š9.TŇ3ÔUŤQ«W˛$·Ë;Ęş,[ÔťąJv~mIź®zÇi>řŃ—ě®RëąŔV‚P%iÖůCŁÂ_.lZ„¨â\ÄNOhĐf"+tÓrr&ŞôźFĎ÷5ďźgC>ěˇ<ÝRR#k¸ 3˘>ž"—ýß·-&•đ´¤72‰ˇVý%©ůÝűŚşhë9©hôQ dĺçJ°@Á× :ŽvÁýŃ#ŽGçşĂó‘ž'.…Ź‚í9x]|Ńç'ęŽRň  ×]řťtňSĆ‹ˇéŻĐ.í{D•8NÖuý´ynÜĆúţËCĆHŁ#ZٸccfĺmŁ˙śI::çúlń͋rXC•ÖÝăîC}¤Fâ]NÁ§° 'ąWĐČĄ-s´_DrËţ±É|ÄyżüĹĘcú/!ß ¬PĐŚWGß,Ă—Dv„č[śOcüŔ˛uNé/üß{[,żşď$*ÚŃ5‡›ÍU×)ź5xFĆÖW1—f )YŔ_{5÷däá€;íÄo˘ľ ŚŢŮgX5ŐšČ|âÍ­ŻE˘´ľPý±]ä3fçešŇ v±B.w€±ó'-wIË/Ô)WvUŘĚLú‡‹­–BÜ|t«Źä<éBßBďň”˛á!Ďp;Y‰°.Q’]źh4ňÍ×ô÷ý.üb˙Ćť ÝXŐâźuŐ%ţlLšüF;!ů»đú…EÖč}‰Ňłößßď^{Wę?V¬g>§xÂłĄHť›n^ĹŻ6L`‹}«*ë‰ŃÚŞ5ů~ľŠImćCi §ó•fáĎ\óáłBŃ€…0Šď‘Ě{Jâ©1›öjA‡äŇAnĽéś…zQď„đń˝"ç´ň"ŘĽPB7’Ň2¬©†¦e-äoO‰l$űěşdhšëúŰSŤ†±Í™2đĘXŐ1Ö“7S\€:_–:D>Ół°ńť [m{ČP‹€ žÖTćץękj¦I7ŘJ7’TÁŇq­Aî%‡¤¦Ź&5h'ÖłľďłoyRÜÉ$߬UŹ« ÇÝŠÎFŘ<D¨B‡¬ŔU¨q’Xt•gąÂÂN BŐžŚö±Ô‘s%÷I<ß‹c3e—°RpÇťĘĎîwâ'xţß&-ěwđ(­>Č3ÔŞ2ßÇü$\ÁËő/ÖŔ«'q>L6ěO&çŁ×‹h솯ű?=>‘Đ$‡Zbű§Šç%sž1ęUé’±E)Űť*Z t GŇŰVVŽ)*ŮaÇJřłvb_sĺÍŻk†ľź;ťŐő.˙ć AÖ 4ś°şˇl#˘ĎgŤö[wš%šEęł#tPőÍ«Ň4S1ŠîNŰJy]î‰0zĐ`Oî6Ä0˙kä2ľ…­!NäĘž·Đżü3ăs'źŞí)JhVCŠhV-łPÇc˛÷Ë&ˇÚÖÂŹŃE÷‰z¸mŕ´c?ÁkÁ ‰V3&«gBÉôbĚ@$î^ÎĎŔýË‚ŢO$ĹP™,˘€=2_ˇo‰rÉ—„Z˛dóŹ0ź€Ž?ß1ęÚEţŘkH<©î,EÚ]÷žÖńűÂÍZTlŮlNTx(sCzŮ«č&·—˘t ĎN†Ź]p«ÄNË0YŘÚ<˛°–VŹ'6nvbyöj?4=ů#Íŕ€ľ]Î,ďć|˝MălŔ]-čçGű€˝™w‚_©nćBL\źµ Ą`6ęxq»~ą>Î(Äíh0}žÔϧĚŢÁ8”*ÄľŐ2˛ľ:%ýöV鸝"ÉLÍĂÜtşe—X#–¸r,Ěq¦áĘńîÄäĽQŃ׏ëž~‚§ŘîÎ21yăX~;7ď‘:TűúlѨŃ×+ü„9ěFg5GĄUâóó#µë“e“GđW‡?ę·ŠňÚ€©:\¨;9 8ëDÇ/ţăĹ]Řőľ©7Üö6öýÓY|h_@Ĺ ™„vyć"[ÖľÖ­ˇc9eőM•÷™ ´—Î'†ß Í“`#Ne¦6Żśqwł"áÍĐúĄ%ŰăŔŠâ”ÓyM‘ÚMŐÎ~—řâçŁ*Ę e—č2EOrΤ)b'ě?éUy{T…@4ONË˙đ6mxöeˇűż«ĽęŤżDŐ“02ó[w9â «Č·¸ăRa)_{ýL4šŃ]b@oÎ÷׹Ug^Ń Â7 Ţ•‰hDiš ťĄ;ěľí6QAĘAiřćXZnăi˛8†‚4M§n?8{·-"ŻĄNúíË-¦JĽeKß´ü–iŐeĆ‚żçřçcuJ2T´™ď"§ň˝ŠîöŰ{4CW|ˇx¸XŞ î‘`ĘăÝ>Śö2Óą&ŰßBÁ´öפ‹*MPrXĎ äśl“řłbȬGßFHV÷Čäýč­ĚÎlňń–ç$§x~ĘŢölĂâ@żŰ@:24ǰĺJˇ=BF\OŇŘć܇ń¶ýŔć™–ţŕtRŐ’!Ŕ@`ňŹ®›ŚBLIÔ%#űyÝ0ŰךÉ主ÖěŃ.ž…‰/™Foi^m¶@#śŘ`‚éř)/OňŞX2%2Ëę“R+ćĽéRťW¸ÇMľPť­ i‹ j©ě÷•ŠÇ2ëĆ\röžÝoĆła=ECwZV§íĺ@ţéqéŁjc…łzÁ2äśmÁ•“yź_ît”ÉS!&´Ô÷°$†—‹\Ýml´G¦7±hÜ‘Hź#ŰŐš˛=rťäŚA’Ăę’ľËP8ź˙›Ç×{lţúXő|Xľj'ĄĐOB·>š{[$ŞAÂôŽ&‚îAŁÓůkUžĐšŻŇ®D˛KFUía¤Nďľz­ˇ éËbËlÉü~•÷Űă¸=đ0×|…Y©ęÂëĎçź,ŇĂëOj˛ şC ݨ‹ůE#ʆ/ŢR±…çᛊÇ0W±8ÇÎËłwí“‹—Ç:ĚčŢq_ (8ÜV`J±w~Ż\9"hhă“]„[,šŕ”xyŠ:U€Đ7¸© Źc°«>}jŽĐ›U¶đ®;˙>§KHih@î&Ő_?=×ňĂ'­5N Ł÷âĦp"dsź{\ňŢuĄóV™˝(v=˙Er»ç»×ŠD¬ĐÜ/™:ľ´ÉĚ›9˘rď.-™”BGďeÍnŢę[>â­Ą±xb1nÇüŻŽ•¶MÎ>ŮjlgŐY®BĘ]U:çU—c«Ëő(§_f±©ľeSE«ÓŮZ¶T­˝0h" vdxŞW§Ź"pýŹź­˘*áfř B&š“˝ g•Ať˛DʢĂϔ۷ď“ÜăŚ^Ë?{OóD6!ł QW®rĚMCŮr888 Yr,Ń" ő1“MĂĂí§*Ţ~śeD܇Ľť†2«`â(S˝%NŰŃŞ0ÁF­şżU†ÚýH´•Ő)«ĂŁăMžc¦ÓEq˙މŽÂŕX[(0M͹ߏݫ€¦ŕsśČWÍ”K/Ů`2TpˇŹž†’»üZ é"r­mkX(é ĺÚb“ugÉňj*_žZ÷ď1~ŇĹŔBŹ^Nż´\µ á8KŘąŠ`@qFugßFĘ‚&ĽnˇÓ:\:o)ĄŢćďÝ›Ľ4®^ů»6­6oAéŹtOśÍÎ1öđŮ'ň[ä§,T©z­ůń, 8:Š \V`sĆJ:CňŠ˙۔Աâ?Ö—Eµ{•íĂTîôZŽü^ÚÉó‚—ârŤ«»…d8l™ë’Ą$ĽC/SĄ*>””ůŢÚŐ ¨ń·zäł”Üu†Şa¨ł0ÂvÝë/ý슺XţěѦ|«¨gŕ«j©Q†z L˘škŰ@4ň°cM!ŠŹMBL×}5€,˙Đ·( ~ĐÜdď~||ň»OoĎßö¨>nĺ}o%wĚăs}ÂǨx¶•źłzŢW¸aiM9Q)BŻşű1@/Y Nhčíß8(ŹľGňŚ|Ę)!‹g˝ţćîŁńçźúfŰZ„6ěK#DŠě,¨‚ńµh‘Ľ%ç"1󛳉o”ů+µóď }4yhm!VmĐAžJ‹¤˝ ř$öŐ-ë]JÇŔ< %ý¸‘›ľăp ĚÖźz|ó3^íęÖ!ĄĹIĹŁ ĂGţ[2ążq/WžłRŻ#ć{ÝěEHÇôK˛_mŢâ?Ň ±xÉ0$ëZ …[âÔ‚ťü¨uÜĘĚ˙ôĚe'|ßçy)›NC|¤w&™V”*’ÇŁr[’|—îeëŐ}GłAťŁXÁŘŰňR‚t„ú…Ź~ŠőńiçőĄ!ťČq;0=x¬ěvŹqîcîŁ#d?’s÷]&e¬Ą,›?ěíiŽC ŽYq±9FĂŠ–Ĺn}Đ,v›Ţ†p*Űď3ś‘úŁÄź}ćđYpCŐ5rÝx|ş‚?ěí»ąż®}u÷3TÍŢUŇh‰őr4Eo,˛€ÄZGë,!łńi4Ś™R¨/cÝďţăO1­šÖFFł„Îł |r®řáž*Ďćµ%p@\™=més•°Ĺ Nͧ„ŰäoČ_t‰t#[Ţ zzmáý,~Lcˇ˝U9ŢůYňŁ´ńmޞë+\ÔŢőł˝t°®řRľÍůĎ« ľ­PQZ®Ň‡ÚĘ·J†Gż\÷~ü¸AŐIŃŞľ6Ľ…śĆAE{3“|»ú¨Hľ]ť&UVťŃýÎf1kÍmYżbyu7Îăf OA9°“ x÷HŤýŕÝ$ąŐp!A^Gˇ{…SßîGç›JÎ\‰« Čm\ůceQĹĆ Ý\ůĽH>ošşpÎ÷‚¦µÁř˙řĂţß˙#€śÁÖîp‹µ»ö˙řăśendstream endobj 200 0 obj << /Type /Font /Subtype /Type1 /Encoding 498 0 R /FirstChar 11 /LastChar 122 /Widths 499 0 R /BaseFont /DBKKZP+CMSS10 /FontDescriptor 198 0 R >> endobj 198 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /DBKKZP+CMSS10 /ItalicAngle 0 /StemV 78 /XHeight 444 /FontBBox [-61 -250 999 759] /Flags 4 /CharSet (/ff/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/A/B/C/D/E/F/I/L/N/O/P/R/S/T/U/W/a/b/c/d/e/f/h/i/l/m/n/o/p/q/r/s/t/u/v/w/y/z) /FontFile 199 0 R >> endobj 499 0 obj [583 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 333 278 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 667 667 639 722 597 569 0 0 278 0 0 542 0 708 736 639 0 646 556 681 688 0 944 0 0 0 0 0 0 0 0 0 481 517 444 517 444 306 0 517 239 0 0 239 794 517 500 517 517 342 383 361 517 461 683 0 461 435 ] endobj 498 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 44/comma/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine 58/.notdef 65/A/B/C/D/E/F 71/.notdef 73/I 74/.notdef 76/L 77/.notdef 78/N/O/P 81/.notdef 82/R/S/T/U 86/.notdef 87/W 88/.notdef 97/a/b/c/d/e/f 103/.notdef 104/h/i 106/.notdef 108/l/m/n/o/p/q/r/s/t/u/v/w 120/.notdef 121/y/z 123/.notdef] >> endobj 195 0 obj << /Length1 846 /Length2 1891 /Length3 532 /Length 2487 /Filter /FlateDecode >> stream xÚíR{<”ů6n1¨HI‡Ľ’]—̨ёÁ`DalĘe5fŢa3ĚĄfr™˛Í •(Ő©uŻăZ™˘E®ÝÖ­\FäEą¤bvq&ť¶=íźçüu>çýýó>ßďó{ľĎçůţ ő=đf=t˘ÓXfsppÇăq a‡:0@‹B§9X @ěŘ0ě`Ŕ ¬Ń–Vh$j8Đ#¸ Jp 0r0ţD˛0á B$Đw+ —j TO'R@×ŔP©€×§LŔ d‚ŚC ÉŠ@$ ‘ÁöÉŽF¦ÖźË$vÄ—Ö!Á”šڤ&Ť©EťFĺ$ …íˇKgR'˙ Sߊ;±©Ô=„đOňźcú Nˇr˙Eˇ‡G°Y p§“@í[ŞřŮť;H˘°ĂżíâX*…ˇSAŔLşŽ•"…éDá€$ ‹ T&¸Ri¤omHł[1ór±wń8`úe«+]…ĆňćF€ü+}#ľbiF đ›Ăá)Qzľü|3 K#ŇIšôY QÁ pˇŇ÷!EH Ph$€©e9ŤÎ’^¤ąÄd:úi©Ö(ćö©ôm`{ţ@Ň­Á_‘´ôBHÝŔŔŻ`´?A$cţ J§°Vŕ_ٞ·§s˘Ě¤ęfH„TiX#·Çü‘Čf0@kĺ)J˙‚Éé‚@ˇâN:Ńćxč…rAA,6«őş‚1SGwüI˙–ĐĆ|â…ŤĆ3†¨ĹÜ<«ÎWĄÜX{ţÍîB‰ŚĐ.ÇD7Eáaünő&5Măk—đ«¦ţ?Ę>Čl¬]ž‘8&Ö‰™NőĽď?TĄPěö aýłö›ň]ť‹ďbĂxżU.’ FĎC2+ÝŇŔ}ăýgK&ťéYtqÎ-˙Kď×-‰µkűÚĂzŐ„;’2Ýĺ:ó§ýś‹†ŃO.Í®ße‰yą×É÷ÍnI1•íZăn]Y] ‰Ţzz:Ž÷NAW>ąĄË>Űó$Z\“Ô»Ö¨éO»ĄŘÝű®ßÍۇ;¸µÁ÷n~¸ä9ľ ËŮ'ůëE±bŚ9ĄMç¶'χě·4ŮĽúă}f~»–cúrĽŃWaZĄ•Łľ*Şç »ĘE_0'rŞ;µ»˘Ö0F-Äń¦.F.ű~6sóKÚ…™ŰiNUOýa"™}ˇtťť—QjZućH ÜU˝8ÔłrąˇxHN±öhW÷†ĂŁ’¤ťG×Ó_í6H‚9YM¸’0™‡..ň*‰“GloHr{˝2ÝÇ"[¦JşA9!=bź÷ĂŢţî˛}v©Gó:QŤé)ĂťV7J~=’ń,?.ýulVţŐ×Ř˝k22&~.ńX[ďöáşP2ÇĎMüä6(!š—*Ö.46…¤XŤ–Ł®Ť¤]:Y•műÎÇ óv&Uňč2…ÓśR‚„Ąµ¸cĚfŃ"'e:·hD1×ŮÓM˘S——ˇXX(U{ uČM<—±?‘ř1sńu¶ěî+$qoŇIý1T©ăĎ‹ě[W†ÚŚ ĹkÂÍŢ‚čŘžŠů§ń[0’—CY2ˇ>ËÔă6a:˛ý®âŃéľjV OU?đ;ú‡NŇo>ÂvpµíđĹŤŞť·éó÷˝ői“čëMx뚏–—Z:Ţł >G»ú^ü6 Ă‰ż.ąŁgg×ďă©÷#L·Ă˝|Ëěřzůľř”ůáS{ę’ýťČúĄü [ď=§BdгŧĽ±U1ŞŞ:%3¤ŕ9®y3tÄSüqÓ;­ĺfFvhv«f™UIŮMłôů3Ů-Ěmo5&ĆĂ*_ŮčŰ:ůT¨ˇĆüł8węĺúíÚ#`5+ŹŔ ~ëŃřűxŞ?¦ülńÓčÓE2ÇÍ8I|^ňu>澉“üąWCwÂí,WżS^UŹ­'ج©č2…x ŻŻS×>ľŹŐ…}óîŐśá˛Ç Ł‘_#ĽZ‡wŠ÷ 9 ŃŰŽ×i/Ć Ĺu¨Ĺő,ˇFş1=śśůóřĂUOµ6ź´ ň”bäŘŮ»űâ]l ŹîŇíwbÇuuqvLůAÂ>ŢB‡Ń‘·ęWçÉ)ˇˇjŢ/r~Ë­äˇaľ˙XsÂż) ;?Ś ß»Ó-RɶljÍC6Pë6ěJŚ´»[2÷ÉkżwŚĚXB´2YČÖž®emÎěŚ|¦‡Ş¬ŃLŘ>§rËč{Śţ¦™TČŞ 9€ î­˘ězżB{^č1Ő;9µm¸čůäŤHÜśöřPúý@Müâ¶K/÷ËfĄ*-˘¨a‘Ŕ¤BX2¸¤čéĄő XŽÚ6r,±ÖŢ`ż•¨®%kr?·łóáYÍĆÓNd‡źçôŞMů“÷d]°čˇĆăĹĚäľ %ž2ě¦@Çv׺˘őÍň:ČG <—©i4 Ë­\F‰ěů/-ˇşđ˙đţ_ŕB€H =śŔţ Ů3endstream endobj 196 0 obj << /Type /Font /Subtype /Type1 /Encoding 500 0 R /FirstChar 76 /LastChar 116 /Widths 501 0 R /BaseFont /RHBHPY+CMSSI12 /FontDescriptor 194 0 R >> endobj 194 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /RHBHPY+CMSSI12 /ItalicAngle -12 /StemV 78 /XHeight 444 /FontBBox [-98 -251 1052 758] /Flags 4 /CharSet (/L/N/a/b/e/n/s/t) /FontFile 195 0 R >> endobj 501 0 obj [529 0 686 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 469 502 0 0 435 0 0 0 0 0 0 0 0 502 0 0 0 0 375 354 ] endobj 500 0 obj << /Type /Encoding /Differences [ 0 /.notdef 76/L 77/.notdef 78/N 79/.notdef 97/a/b 99/.notdef 101/e 102/.notdef 110/n 111/.notdef 115/s/t 117/.notdef] >> endobj 192 0 obj << /Length1 772 /Length2 944 /Length3 532 /Length 1505 /Filter /FlateDecode >> stream xÚíR{8Ti®<‹Fé˘č©‘Kfć`L¨„’É3)B»Ç9ź™Ł™3ś9.ó´¬Ý [ŠHn]h»Ş©´]´1mYĘş š¨‡R¶T{h{zVîţµĎžďźóű˝ď÷ţŢóţŽą‰źČÖ —‡AO9IŰ"lÄxř‚ć„Íe™›{PĄ 9ąĄˇ3@śśŕ-půÎvvÎCňH%E%4°ô°"ń› R†’ŔĄ%PĆh`¨äi%¸IĄ@8tC„P©łYpŁA$‹3dH@†Ë˙cŹŽüĹ@JÁ–ŚI+ŔXÄĺ¤T pÎâřĘ™Yqňo)î-•ú˘˛!ůˇľ€Q!UţEË"ŁiH9)r$u5üčÍâD´l$* Q)ą‘b)¶›kĎű O"â~ŤI@8*UŔá>$ń‘Vô†Ťp– üüWŰ|Üę0ć‡$˝R ÷3y¸F>×LF‚ąl.aĚůô:bÖR“ă)vŢ徦čüëÖŰzÖÂLkS#ľú€NËči†Ę–ÎĆAc“±ň…÷ĎZgš‘Z¬Żń¸} =lÖ°4˝Î+‹Ň6qhZ^­?:ąT5;±żE]oZ~ě{‹ý0 Y>g¦Ę®öÝ€Łťö™CŽu¦Äö ĐIjúcŽôQídť§;G+ńf–ĄWäsł·w §Ő­`Ď»ŢŘ«#c™¬a_SX›€?!ÍA»ýťÖMÂŻËÖާ›[nĹÚ|RRµ>d’q±şA5/WwĺŚ:ĺTŐ‰ďŇÍ) \’.čZ–aébŃńá­¨öŐ×ń»CĎęÇt;ĄD%íOŐćuÝ=TĄ7®šńĽ$YŠa7»•ŢďŠWp,‚¦ĂuĆ­Ó¶Ö׸t>•Şš6N{Ţ!)»Ř¶÷2r%Ą[o··÷-ÎůąSźŚĘÚ{4?¦*ŕ䨲óV™…gׇňž:‹“{ľťýµż(¬†[n-‘ÖŚÍÉ3Ý9:C÷ňx-óŇCˇ¸őćÎi©Ď\Čč'†µ|ffź{ˇťşř‡ËwĽďöŘć±]R´O“”˘ńo®çţÇőżŔB“B”˘ĺ2”ZÇúUP9{endstream endobj 193 0 obj << /Type /Font /Subtype /Type1 /Encoding 502 0 R /FirstChar 3 /LastChar 121 /Widths 503 0 R /BaseFont /GRYPQW+CMSY8 /FontDescriptor 191 0 R >> endobj 191 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /GRYPQW+CMSY8 /ItalicAngle -14.035 /StemV 89 /XHeight 431 /FontBBox [-30 -955 1185 779] /Flags 4 /CharSet (/asteriskmath/dagger) /FontFile 192 0 R >> endobj 503 0 obj [531 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 472 ] endobj 502 0 obj << /Type /Encoding /Differences [ 0 /.notdef 3/asteriskmath 4/.notdef 121/dagger 122/.notdef] >> endobj 188 0 obj << /Length1 1071 /Length2 3546 /Length3 532 /Length 4246 /Filter /FlateDecode >> stream xÚí“y<”mŰÇ­a,Iöő"ű63–l‘%D ˛EĆLfa[ö-R–ČĘ’$’5Ś%*…ě{YОFďÔýÜ÷í˝ź?ß÷Żçó\×?×÷8ŹóřýÎă<.)qK+%7ś+҇%*A•ˇÚ€Ń9++¨ U†€¤¤ŚđH8…Ăž‚‘ÚTK <ŐĐVUŐVÓIF8ď<ĘĂ“ČÉýJŇ 0H< ÇçŕDO$†ZGV8 I P Đhök€! HĽ/ŇM…n(pEz ° đ/GfXw ńGŘŤäýç’/O šd©&ĺŞE7¸!ÝAŕó8Ş’ęä˙ĂÔ?‹›ĐčópĚŻňż»ôoëp đŻ Ć›DDâs87$űĎT[äćÎ!ÝP$Ě?WÍp4 a€ő@#Č!ÁĺŹtłDž€;M@ţŽ#±n˙4AmÜo `#+±éi…ÝčďEK8 K´đţ«ěŻěß ý›©ýÁŁüG2Ą&Rß?żśţ!fŚEŕÜPXęH¨ŕx<<Dť *©Wˇ ë†ôţTÇ`e,ŽHÝP› ¸ăđ _ަ€8 ţ+üGD"ń¸żęLô;ŔÔ-Ş»?YĘćuűůżHSŰţEÔ˙-¤EÍtý‹ ŞŚŰ„`äTŔPŁŕq|ĺR+Ł ĆüŤPŞöR…pzü¤  Ux©"@Ş®ďoü÷04Äů_U:®(©¨C©ťĐ4Ô5˙W‚„Ç#±Äß?uŞţdwu‘H$4ü‡Đ‰ş’^C1.č-f”§5ô¨I:_ŮÜ×Č9”L‹.ę<ă#?ńÄn§$ë(Çăśß®ázCĐ…n“Żá>I{sľ.sYuBvkYç>zKlE~>ü¬şcIťÖâÝD9Őľ°=gĄăsžĄě)ëy¦1qšGß§-w˘ŽkŘ™dˇm®E?‘V‡qfřcŐ®Ťűq¦Ţbď‰ ąrŤąVat×@âÚ)`ľ—˛wicńťľ#źY„ď÷Wb"6]%8hä¤-aJěWŤjŽ9KJ?(bǰ¸BŔî®H°ËĂŇŔ4Ę ćÇsý2E?'ň÷VjKÚ‚0ŐŠńúÄn´¦µŔk÷Ź…OŰżÓ%Ń$}nÜ*2vç ŐuÁČxú•…ťo‘,$VtDL‰šX¶$[łâÖú´U›Y"/O†k7±ąZMDז߼Ž[źúTĄ·łMBüb.âŽyëW¦Oă+.Č /—˘…ž8i×§ę„'T ·ş( ęhŢ™c|1f_ĘQiţbLáűGŰíĺÉS>łIjSDĺ0óInCy‚ßĘN!ŻN:·Ŕz»”T#kľŹ‚%{|´—ČgúڶÉMj)Ln{*¸­fśdcj8ox/ &»%R\WŻĐ¶rx íi„Ř—±x$A’…üÜýd˙ó† s>ߊú¬mń’”ň c˛öe4Çuô6㞎ÔÝTçŮ ÷eT•żh:’XçGʡĄg2†’©ă‚ëäüĂB3ô37%'Füi O¦%aç’y®)FŚóé "·”xČlĄiá őRŚç2çÇ Ěć,3¶S3ĎoÝ+[x»ŞśWżÝ cw[8â í':’ÝÎO€R ÔIĚSł}©­ZMGnc ľQ¦ŇVÁ»NN%9jémuľb˝(uU$Ű ÷ć€+­oČŮ·×OsM“9V›ę˝Áaî0ů7ý¬¦Ś…x‡¶ëńÁŢŘ(ŚÄĐ‘ÇŰ/7Ń~ “~Ő4ßśUeÍ–ćpĺ_8ă!ś'—çËqhăMÄ#9‡%®O5šq±Ż«9˘ÄéWĄŞOĚ›8„®ýěX¨m…e-IŹÎNDĆ2+?×e.ű»oŐgÇfě¨hâX!hĎi7Ć&VŽG[¦šäôy˛ötQđyao;éΖ5ÎĐwĄ˘ľŤ,ÝŻt¬»ś~úU´<ŕÂ1ĎŞ¶2O B‡‚±ą& żuĂí$‚HŽa­řĎÇ‚›©l§Ďćȱۊ÷m9{öc‚s‰ÝüŢDé3é™đ» V&ĺY/ŃסQŇa‘ĆEŃJ}~ Ýk3»9´RŔ˝^x…đě×vúv)ĆŤ40CŞ Ü®AŠ!0˙A‹źÖń”k·ś˝ÓUŔ·ĽłëL•Št]nh ëP&˛iňš3+fY»6€P:ń8Ç‚ŻĽâĽ×(éM™Ż2zʬ`Î6YÎľv6ůź"d6“ą:_~ľůUD©qW°Žěç+EŞçđąž®ô!äŐKoŻî¶×đ~2‘pűŘýô«DŮŕ‚ y˘6OÔç1Í8Ů“7Í^'V X·ÝC¸Ű ÖX=ŚYD醢Ź[^ľ`S˛ÂÚĹ?·j±®Ň02ŰGP‹Ů”uđyčm»/éY$lÚ>íFţT<©Í…f‰ŮŰĂ)7~~—çqFJŘlŘ ¤hě÷¤°ůKŢ–dÚăLŰböú‹eC}śČ ŻŢXËCrč)Ţ6Őbht&~sĺ,% ą~MĎŤČ/Eś‘3•C~Εíüy©Ď;íékĄVzü~ Ž1ş:Äg.đ‡]”ĺ$̨@ř.—ťź:3ŤMž_Ü‘ÝęDt‰{¤ŔaTc[ ŰŻ.ŇĎ™şi-eŮţŐ!’éîĆ7tpç¸ĺ|—ŕÉOÖ&ébM‘č`Öu3¶3ĺ\Î`Ú!o,OtďŽ,ýRŹďdtnGÍłŞšŕ55ňłq) -‚á%®Ý†ÂܛϽ«–˝·äÖévGx±¶·_żoŔ‡ýü˘'­ę÷ĺmě côY5éŽ|H»žÝ™yŹ!(çEŤBú ˝8í÷ĽĽ›Ž(3ć+Ą°$FUąÎmzůĺ1»}-ÁmµHâęš“ÚĺÓ‰"”,ŻŔue‰{$wgr§€.7taxĐőhÖMŐíšR=Hb â!¬¸8FKµĚ=C¤Đ:rŽĺe<ű.]ZŃnvÝ~,, 0jóÄĚ›WEŞę[ľ\]ł˛ďbÄ1Č‘;{ă«29­$O™8[¦óĺçů 0†]_~éwY§?űńVcôúüa©MŻţÔ·DQŻÚKĽ—8uMz=kŹÖËŢZŐ3éN ĘÍ~`ôÂ(>hK[u#-ó§Ge¨“úĹÚ¤ől]:ßw âx‚“K}psÖw¸x¸tťž9Tó»Ě[™/“ű*ýmďÎKÍŹq+u+ ]=]°TŮX.č(·cVUtG¨ÉQďXfÂ(ü{Ż&™żÔl\šÜyw7ÇŽ±î.”+;cÄť()/ă¨Ý˙ x$joʆ•śéžóšX$_ĺÄä6Т7%ÇŁKK@%“|Ýďďxöšź’ #ÖNe9ôeWőnÓ(˝]cŞE†ß®lŁyś“o¬!)gźđ€ÇűČŐ-;őŤ«‹´Ź42űž2ńnâv/ްÂ÷Š”“i»nR8yŻçĽZh.{ ăü…·‚U÷¬üśŠô€±Ć5ú罉hŹÁ™#Â9–X„ ¶ŢĂ ‰Múj=KŃ«µIňkŤvM' žćĎ[’0ˇ`ÍFŢ…˘÷ ĂŮtÚ~ŰÓ±a uÖŠ1‚ď˝Ô;Oť<Ą7ľ§#ĽÖr=?íjŰb›„Ô«_ŚŇrifS´?ăi h—dŘşq%ŢdVÄ772îŘ÷ëŮ3Ű®Z•·“Řľ]Z‘°ďCđob9űWĘ›6f˝u°pśAó›ţ*­búŻ\RÚ/ş·Ô3ч¤}č/•f~Ď·©Ľ°píR÷ UµĎűdëµ›gDżŐ÷±0^ŢY°L@ŃX˙Ľ]eĐj”RßL›’śÔA{RęŰ3×ŐíDvU·;_Ä0÷•Çí»!‹^˘Ž'ß1qŁdČ«<”u´ü ˝I.ŹIuĄ¸±XĚ…ęcÝŹł~j©čP Y3•uýĆ ?±-F±[ţ1“ná˛˙'Ŕ{sż«ě5ˇ€Óć ďp”’VÜ„„˝ĚVٰŔń'\­G+çşüä xJ®ô”0Ň˝›K˘‰Ąř„R]sľ^ňką…ÝçX{ôÉ},:ŁÝ.˛^DnëAau Î|>ß3vfćă-qűËKÓóKc—n •1Y:ď Ýó7żyA˙ś(ÚI<^X>97ćŠńľm¬8Ä1 jîÖ˛ÉćŔTá%ź–U9řVđPŞ+đ.ť-éšĚ…ČâöĎ1>ę „~îéÄ'JJËŁF_)·vqŔ)ö·eŽËn‡ŽÔ‘řoŹYĎ?5*řż@«tG˝ôwVŹöNgf>şĹĆçÉŠ‰ňę^p˝ü1 (~îSM¨5Ô‰ťńŁ/Pů]7ň*›Í»ťđ¦~íšĘař E!¦äćOë-%¸@叛sť ěq^.HńŽÂťŻĚ–fV©Bźžx«áĂ#A¬Űy­™ĺţg÷T˛3$kdřé^á¤8¸ßć•él –Č~XS2vC°‰ľ>Ĺń¬˛2^ňݱÜިĆr.ž.mhŰ‹ĎEUX:QÄëžËn?>–\rtwŰ%ÖH[F {Ő{˛ŚůPÂCÂëËö§ô8Šíý00XéŕĐkµ>IÁŢ.ŃAűdŚľÉą«ío¬óF?DJ§żŽćŤŽ‹8tŹLëF KZľâô~}1B>¦±k :őé&Nćľ¶ »DťŤNٱ ˙ň¸ü-)Őć”–i+ą}ŮŐ%Žłů 8›łˇ^2lá1zM˝cSJ&Ő÷űtŽŽQ`áĹŮoh·ßo6=É12ţz}@ÜEň Ľ˙ňĺž1ŠAŹE^[‰5]źÔ”ä˙ř€ţ[ŕ?˘Ť„ă‰8 ďúЉXendstream endobj 189 0 obj << /Type /Font /Subtype /Type1 /Encoding 504 0 R /FirstChar 44 /LastChar 118 /Widths 505 0 R /BaseFont /CSREGH+CMSS12 /FontDescriptor 187 0 R >> endobj 187 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /CSREGH+CMSS12 /ItalicAngle 0 /StemV 76 /XHeight 444 /FontBBox [-62 -251 978 758] /Flags 4 /CharSet (/comma/zero/two/six/J/N/W/a/b/d/e/g/i/j/l/m/n/o/r/s/t/u/v) /FontFile 188 0 R >> endobj 505 0 obj [272 0 0 0 490 0 490 0 0 0 490 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 459 0 0 0 686 0 0 0 0 0 0 0 0 919 0 0 0 0 0 0 0 0 0 469 502 0 502 435 0 490 0 230 258 0 230 774 502 490 0 0 333 375 354 502 448 ] endobj 504 0 obj << /Type /Encoding /Differences [ 0 /.notdef 44/comma 45/.notdef 48/zero 49/.notdef 50/two 51/.notdef 54/six 55/.notdef 74/J 75/.notdef 78/N 79/.notdef 87/W 88/.notdef 97/a/b 99/.notdef 100/d/e 102/.notdef 103/g 104/.notdef 105/i/j 107/.notdef 108/l/m/n/o 112/.notdef 114/r/s/t/u/v 119/.notdef] >> endobj 185 0 obj << /Length1 1608 /Length2 9081 /Length3 532 /Length 9996 /Filter /FlateDecode >> stream xÚíU\›ëö ˇ)V¬x!(VÜÝ))NIˇ 8 ¬¸w‡âĹ‹»w/¸Űdďó?›Î9—3Wó›ä&ĎúÖ»ÖóĘ÷^„–JYŤYÜj–B`Ěě,ěIE55‰ělv6tZZI[0f…H``;??;@ÜŢŔÎ#ŔĹ)ŔĆN „Z;Űš™Âô’ %ńÄ­Ŕ¶f† @3[Ák‚,jPC30Ě™ ni Pýk„@l¶u± łłŚĚ a°‰ťő/'91Ŕűݰ‘˝őż9€míŕRz¸$®h…X:ŚŔĆč¬JPx/0Üä˙†Ô—±·´TYýUţÖéż2@Vf–Î˙“µ˛¶‡mŠP#°-ä?SµŔ˙Ň“€ZţW#9ČŇĚPbb °ý+df'cć6R6šŚA–vŕżă`Ń*ŔîoVůwďŢŞĘ2ýł§?V™A`ęÎÖ˙ţ+˙ofdř Ůš9>˛±°±±Ăáß˙ŇýŹvŇC¨‘~(¸y [[3:ütŔ‰ŕÂ0ť`'¸3+  ŔĹ ` µE˙kKá»Îjüwě_Č GË‹Ŕjęlm †<†x¬ÖđŤ„=†ř¬źÁ¶ĐÇ?€ ˙ĂÜlVăăsnxS©-řŹ x_¨˝ícŕ/3‡?2¸¬vđ5ů‡ájv`‡?Ěŕógýמţá°BĚţ›B-ˇŹxŕeÄ ^Bâ‘ŕĂ% >Vę‘ŕS”ţ‡xá”y$¸»Ü#Ák*<Ľ¦â#Ák*=Ľćű^Sů‘ŕ ¤úHđjŹ_őG‚ĎHă‘ŕÝ5 ŢďĂ#Áűi˙Cđ7”ôHđLG‚g>6¸šŃßNđř×^ţpW“?.kúÂmÍţ@¸„Ĺ·°üáVŹĄX! \úÂ5¬˙@¸†Í×°ý˙:M |Ő` ÜĘţ„[9üp+ÇG„_άN ÜĘůoüďkBBęäÂĚË`怿"đéńĂO›Ű˙–hhok †Ŕţľá—ÍżŮŘ ~5ÁN`Cô™I¨ˇ Ży|ő—|w鬑d;ňÄ\ßfżĘDA–˝EAĽqŰšau0Ĺ1®®ąY!NÜľ|«‘1÷2Iµ¸k·‹«ß4n7CF’ęážÎ§'=i]mĎ­R·f(×­kf©Ď–š‘KvŘy3IöžćOMŢť¸[x .Ď`$Qoġë¦5(Ä‚5·—"úŻ˝…fAg˛{t’ÎđďgHÚĆ,ć±ůÓ‘&…oź±Ď›ćăąč*a`·Đ¸¬íHkV¦*•@ňÓb*1§Ó“RÇá+‡Űgݱ~­Ĺ2#´9®Ů©ý‹Ś%ţ´ůľÜśá~]D«B¬^g>‘9ŢřůżÁř—USZĺÜĹţ~‡Ě qÇŹ,§®ß^ĐBrR=+2~˛é×ҢĹĐ°źŞˇŇő7ôębvÉÄ›ho°”¦‚kp1s3 Őźž§4˝FbnŠČ‰S$¶nCByVg;űâ ÷Ú$#Ó"ą×†1 xI-9j1 Î=‚‘A‚3šw} FąŚî“aťÍ‡0Úöäg>Ű*.]' ,Łi!î"RרFI¸Đ3Ąšçuyă|ľ€Őd*ö3—Óŕô ©c>OÁń1čííˇÓţ‘Ą=EźÖÇďTi9ä/u7q„’Ťk±T€¨˘äۤFptŠńýfĎÚIÔ+őF­ż}>t. ¦÷‰ˇ/˘2=VŻÖůe>7WE3nŔűNÖau|GĘÖ]M»ĎńăĆEEIJľ í¤™č\r¬á¶<Ć#ß?€ˇšą49ŤćËÚőé{ľť+R1u4YĘ"Á`}>ŇNÖMŘuŰęy@›ÔžQľťS<¶Űnőť?°>#ĺççCŐXń–x¦c«Y™ó ěőÁ7{˙y7}? žŻmž%W|ۨlÄN±źÔ‘÷`íÁ˛ąyRĽ‘čŕn”Ż#1Xę ·Ç» %ű„^G벝Âű‹ R\_¶† F„V–ľüWITtŁŁ±ÜůÄ”ú9 ŇqëOk“/±ăŠů0çR@„|aČvz!eŻŮ'=:“ŚöĐň;ő÷8‚{´^çl{~'1ď=>«ĹB¤ö~±$o{ăęU12ý^EČ›ĆCÍbµqm?ÂoţÜďJşżěĆ.-Çîž*JYşéŹ|ˇxIV*ťtyBŚ5KJt ›ú}M1šÂ^Łý%GÍ›Ąj‰Íł Úiú‘8¤ť`ąŢ7źZŢ–jk{hp ”ĘqüÇVDôÍş×ţŰY\.ÉÍŽ4;ýĹ ”1ŔčnŮŹ˘cÂŻ^‰L+ ú6DŃÝ Ţ”§şç«ŚTjSb´r[+ó~^ąŁYSnź‘x·Í©lF%¨¤Nâ,.±¸\ťbŮ…«ć˘OŤ®€0š졭ł>=}ś$ h9!môd2d°Č©9ýfrâ„ĚţIńžä¤|nµľ—§ ÝĽY\ȶtmBs:ßò^ű“®ů †eeě˘cVaHŠđöĆ$˘ő{²oÚ×;‹’űO¬:ôďÎÚ>´Ąĺ€7NaÉĆs™7«Űk·X‘˛‹MˇÝsź˝âŃN 5¬.EŠ._X-” ‘ÚĂŘpYř#ë…~wáÄíV‡&sě†&ă 'śô«Ź­˛Ş'ďŹĐőR†ę^A/f’¶x7uÉÓÉRŮ ň:8ZĄ“w®M©ľ=Ś·čG»÷ĺl$qwRsŇłşMČpî•ŐŰOc­Sťn͉•±6óż¤dv~Ě+žđŰ&j5âFůŢ(hő¨eُíő¸3‡P1Ţ-Š2č,ˇĽ+ßřmdrN›^ď?a*+­ëRđ˛ąs”„a  ŮîGHúË˝Žl×$>ЎŤÚÚ±1ĚSě¨ÍzW€ĐTŤ=«,›\Sé “ë^Â"ŮYAŢÔ‘ ă7B (Ör^EjW”®ýé.4‹'‚iKa}"™nyýĐĺŐSňěXĽc^€çőŮĽ Ťf°ě· P$vĆČ(ÁFŐ+­Çžëâýę•lÄG)Ę}\U“\í­’ěŻ_ş řŞ‘ĺdžń7h 4ł™_a{A†Óáű;»SëRúÖ•n…E´…$ÎĂM‚ZŐ\™í=úÁż‡P|٤…ť$fĹ,+’AëDȦ%UĹᾨSVŬ켪—‘*hÚ[]éwjEŠ‚ Ž®¨mĎsÉ{ÝV8Sń¬ś“C{\dó…2b¶=R”ńt€Đެíő@,˛ź&•čÄ=Tť|˝lk ż“e/ݱfn1w–<‘pjűŹĆńďńEů(K>/·gUĆx`|µkş.ŻĆßĐ´Źšů*"ő“vÇŃôgCă[Ĺ~¸0ŹR‰BťÂŻ«x•_ˇäÄ;ďęE+iw‘\,şÚ#eŚÚÝď ?Ë0#$ä×ů~1˝&Ú/%E` oŰ?ä z"ň1»ä…ľq¦ĽĐÖiTž:K;\©ü,ŹödK˙ŢÍÇăÓ0őŻSéN\±YnB‘ł˛—AM︒9Iuś” Ţ…·rZŠ*)n9yZ­l=;ôfČsuĚă-Qý[ý—¨ ›äŻŇ7!/<Ĺm)AÓo5ET¦:†<¬ Á‡bÂŇaiŐýHVß~ŔÖť[’ëřňś˝M$%Ř[Éôo¤ĺËŰOM©ËŹąeň{{‚ťf öF ¶ůY­óŻÄ’9XĂÔ]vA=S~'c’·C“ă÷xaéíX[í&/·™Ŕ®§r;őZŰŐ^Ëô;›jáťE—°üöě'ęq!I6Đňć¶lˇ×É,íHčĐęW­GÖwoťĺPKY›osu&4ěŽE Żż§^VĐ|ĂËzř¶mšĹ(ő4ĽŢT&ä‹@»,ZXíć0w,MôËĹVLşćĆěÍó"’Šéś@Č>!Ux'Że9ęD [-Ž>G2Kč|Żé˘3ĆŻŠŤ¬řŐf0|gŢ÷bOB븭žŮmâpv\Űv}3Ňć^«81ř)Ś·óä=Ą\‹ŽcO%Ě-(C)ßÉ»l]De6wčÖ*˘ĺŘřĐc» ˘Żăe×ö¶vÉ)ç4Š|ó@Đ„‚ĎĚÚ—B]›á¤(í[·Ý.§_Đ08‹[ Óh…4†ű « e-ĎĄgťFąćč;©7_^ŰYżŚqD¶Q¸b˘se•…î‰ĎĎÍyż‘°%żü´—o$ćń`©BߊËSxvýô‡ÁSâÝťőňĆ/ˇ1Ň·G6Âo|őőQĚGĄ J˝j ^MŻLzxÎ{•‡Ôă¶ž«Î &Ń1xřs„ ęĘç¨eővi«(ě—űB‚P®޲@yuj+)Ô ŃgOńÇ%H8e7|rŮőä“Ě©=6ęMč(HHÜĄđ_©äÜm~AP—Ţ<»¬!śáĘ@B|‡,Ęú%3žíÓĽąVČ”IkzbAČÔ›q«¸ÎA”ý—<^*K»€'iÁĹZW†ęČ*Ś}Đ•]yűă©=ü,ń%_{ Źć'´+$Ůşj»í†‘pym7¬b^…YKRTRü}çŤS łÁíŃ^rń+–™Âi&¦ÍĽśę|HCâü˘Ő8fËůůJUÁ*Ew*>¦ň8?ŠŚÉ˛Ě ‚đ'ľ˛޵¤R·„#fâŰÁŢC{Aăţ HO»Şîëňz.uRµžřVávs¬×Äc7ă< s>GĆ)»1W Xó1ÄĎ:÷çO8ÁbŽ˝—ô¤rrđ¶i]ýaÝžJ¨I{±Ixlěľřš€&âéÓüĹ4îNN’š!®WŔ#ń3˙h,{üęůŃúýoÖĐ NĎÝc‚F™qŘtaS'®±ˇŤ~âąsKIMä {ź5×áçžŮ‚âĺp›ozęk{—´ňV®tĺa=Býö ˝˝ő&¤.ŻM~1o©şž;…56+$NgľxZšjFĄŁo™şsžő‰">ŕŘn©‚şěsl¬uŚ30îąîK4ŞZśfú”•dM–×R"~¶\oŠtŹ&•„aUfČČ›§Y kŞfĐĽş©čý@©ş\Ůçóő´Í@†ö—Ę~˛ěń§ďŔŢPŤÉQ3K|ÉĄ…°}ě:h/qžlřኩ }ŽxéhÔđńemŻuµw¶śBt ţŚé×ě×®Á5žăÜZ7îńänLě ~Ö˙‘ `Ű$´N­ËÜ9Ń@]*ŔĐ)\EÖŃňR»±ŐfµDźnT2q_»5vEa*Sx†11y@9‰ TH?ŃĽíÄ•˙yřIóűIP%ńîbHľć`1KÖűžâEK„řM‰úwýűç3Ę‚:CĎŠ´Ü'ÜŻG:¦.†3óÍ™Ďü‘¸wż ×˙ĐŐU–ĺ¶KÁ/ëF'Ćc#(ŁÇA*Ź‚Ö߀hýF4OD.Ţľ‘UEq2úmüRWy)ł‡őÚ†§µár5é㽹ŇŃ«·7Öb8myz˘4Ë9ęßL«“4$ř(˛vŹéž|ű8€!jé?ŞŹź źb!s^[?śsU řR3ËÂńŇx e‚/9d§$U§ě~Ů,ëšĘ0Çčő¶ÖXáĚuĂDž§áÖy@ş0†ľr8đĘ1ŞŘ§VQÖPeŁ–Ri©1Ő‰ĺá˙Ă`Y)#ó&j7ö Ž{ČňÄ9Ş ˇ‘Nw^^w2i^ݧ”HŇÓ1]¬’°3)[‡ŤćłŤ$KmQ@ľú­‡Ř»S4*6jńY ěk†“. "/ĹgúĆ|ŕ6ŮmŢ›)ĺlĆ8öŐ…ëë"™“•­šŰ“ 1óŠ[[É·D}°Ď_†GĚ2÷žyĄî„ŕTÝϤÄ:¬VGÝĐU.k1šű|5H•ůÝäl…¦Îőah…Ż6Qc qjź–»‚ű6Śë]÷žóŃ®ďCjšŢĂ«–?ťč8ĄPq)_“pF„ĚaÜ«?) e˘LSšú®5›[`ŽźĚA,ÄCú±†ůěŇüĹ1)·9ˇŇÄşĎ=ŹŠýąĺg”™Ç6÷C¬`é3(ĆÔýyń÷°Ć‘[ Ë [+żŮ!Áů7Ý3ŐnúóźQĐďk^şqXKQmy€§NĘxcwźŻC†~Íw˝Ŕ/ÇB“I´ŁŤěĺĺ uÍľúDt¨meŮ)ű° RóŔW;,0ŚŤĂ°~™9E˛·__úĄHź°[×HI  Seń,dťôoëjź|jš4&Ł)jď"WCj Ę÷¤óŰ>¬ńZ-ů¨ď-y(Ą{w<ůiúčĺĽđ ·@ż8PÉ6Óp>hPą6śqíg ©xź'ďdĄ–SCݰCpáJ€Gó†IŇO’A‘^žú>f»ĹŻeÁýŮO0Ů+E^‡nkgX‡ň«ÇŻuXÔŰ„ ]€ČÇqjśŐ…m ¸"úŐ÷Ĺ,*~~’[Öv 9 ÖržŽ7ćŘoŇ+xÇ$Î6‘zlAá¤Hłj@F}k‘3®Y%AÔ·K'ô '¸Oęď?Â2ŘĆ_«°z›ÚQrÖü„–¦Ü=´x%)Răˇ8’Ż?ŇŐ& gĎ··–d”‹ŹK4¶ˇÍç†â‹""ˇ{°˘¶Ĺů˝:bżídî#ۧnőĎ/­ńR‰Ľžúláj 8_hL'.|·Š;ŠÜNśmµŞg8ß'ĂîAéz1]'ĆÖŠoTҠ㪲:Ů@a^qtŕýŃéggôşŰB\‹âŻů.Iůۉg™ŐŞZĘjW¬€‰Ä2<ŰÓęŠÍĐô×@·‘oßÇçĺ/§6޳ؕ¤VDx·»Ą..ďéErĹ)`vźüv+6ĆĐř¶=ĎŤ Ňß$#9Mua§ü/'ÁË=™Ř(§Â“ÉWl]´¶KdJŹüŞćíŻu˝Żm6BSďOś›Ďô™~·ď&7ľŐŇKĽ,fw> ”BÖěLµĆJM§şXž{(Ű™ :ýbŕ'(?_;{cLč÷ëĆOíÎşKFĄ@ţůËO(ĽćŮęŤH"3óöÂ…Źç»ËâčdRHĂÝ „łčăçޱ7ź¤űäĘjĘ‚r%Ę]žIMicß‹hębŰ ĚbI3Ę“d– T*9tŇ]ć\+ţÁQľˇöD·°ýgĽQõ˘äŤÇöp}øĆx‰>GëI´¬ó˝Y˛ŘĆTpeÖO(†?ň$®ůí™¶ ÚŻö\ Ź«˘V,ă&誚:ćPßµäÄ{îZ®FdVdżűőNţ§ĺľ_×ÖaˇçÚ·m°Ó`he÷Î$fýĚxíÍ­â| ś0ôą-RHAŔäŚĆ9o*DKłĹÄ—@C™I*;âŢ/®ŤďEě°Ă+ăys`ä‚cÄ)Ľđ‹¶yë˛ŐzvšőÉj¶B\úµíC{3†ľćĂďäOËŘw:ů"v!”Ţô…eĐł­ń%öCŤŘ +I?Jʦ˛v‚– ąää"q~—ąCďŕýŻ}ÚŹ+  Z1Z—Öoł-B’T4p.8ŞŹkW˝ϩӉ/:|šÄćM»w¶î'ĂrYCŔČ·ehČY‚.ÄSąb㔲t;?îníÁň´°Ú„&D‹`»BËCË3†éffω¤y~őŘ9˛ˇôŮe>ýKd¤°…iç´±#s•_wĆ[…uÉ9Řú ôóć±ÎĄ/(„UĎh,RSmxQ/ęGű‹JCV’‡«pŞň؇ĺÍV8ët&ńg0)_čąr:1«ťh„řłÖ®0ÍOäSy?ů4ß4j“Ĺ–î öť×áç Őî5ů Űh˛·ŠĘ·Ť»ţ°`E_ń§8çâ@ÁVdL}¦,ň>Ť|ňĚFşWťQ?:C´QšO)f?y±ö1n%h—aO1ŘЬ%[!tx·×ćf%< Ł&Wúô4ˇT0Üţ ±Â>˙xŮm›Ó@Ť bč$ë'ú]Xmç^agŤŁ3±á@ÍÔ‚č-ąŁě8ýŞ0Ź ĘR‰ËË~J9&yăO&/n¶2U9ěâÇ€ţ鬭_ť 6bF^|ęÜ'‹¤TüUy5ĐöiṊ*&Z‹±+ű|P)NT-*d×7Ż|÷Ö?Ą,ą[ÝgŘkŚcţ®,ö”…ç–RtéabĄ}‰zź ÖQŁcv€˛ 4>ë^nCŢ”xŃ’ [jÍŁ’ĽU/ȰĄžÚŽPMá ň=ŃŃâY–CíŤcPĺ 9 6á´Šéܫ쒷ą4yK®á´ˇ9Á AZoCnŽB úPß—EDŘP¶‡Hę+ĆűşRŮ–ŐŤS9Ö¸¤42iµĎüěŽRýpş2Ti¸ĎmëÔg#xÖ2T×ńݱ¤„V†'l°Ţüîš»~$ó<­’ŻĽúĎ/'źl8ĆóŇ0ęľ0Ľç,”0Ę(Uď6«ř´$µKę^˙öNĹyŻëB^ČľĘ †)­CnÓKéwl„*ް$,¤gý¸]ÖmÖ’`ź˝IŘą ţ 9´»ŁúĂD/%NBéö±‘‚űţ‚Ę)Â÷6"lď jHľaíÜíć˛ě{mĚx—fyŘTÖ°«­§,}üU{–IŐDś”íęŰ=_v%]Ť8ł(§ż¶ôŲqf•RměU‹ü»F©»{Ęë×óX˘RFÇ•f… Ń%í“…w®”­%[$JťNo[îej룽p7µ0‘…Şĺő~â˘Iăěýˇ…bŔŰúéđdRň—›zy”YÓÄë-á?Ń­Q+’d'IóĄ©+šÂzBźbĽě\ŁSJ˛Ę§hŰbçvňŃŇf.Wͨź¤ÖŹ>_祛Śě)ťđ^Oˇa$€ďp,ëyuT*˘ISNëT١.Î…éR /‘ýM_”µ­K®7x•¨YTotO‰”ďWˇ}»2ŚŚAđ™ —?™ŞvcčmbqHáWÓß4׊©¸:UkDŽ V9Ku6óÎľZkĄ*¨7‘÷í·…ÓôRdŘA˛ď§-ĘuěHEżGĘćuíá›U¶Ed±}óaŕŹŘă®°ĎÚTFáŹ&±}rg,'h!Hnce}˙őő5˝ąŞ§sýťqůGŮ‘‚颣b¨ŞGâU[îăNň’†éďi§í˝Yüú_’´A…e• Ë|äm×VĎ­˛gÚ±RôL¦Éo·=\ŰĽŤnÔąĽaę“"-]q;0m‘‚®+v¦‡ôÁĹ]ę•2“şęÖ">™‚c2™§Ŕ¤eť@ĐËXĎđČĹgş¶W\OS®ĎżMŁô7|ŤfŰŚ’3űľI"$ć×ęďKk|L‡Q50aű=Ýw‚Hµź1ssoćďÓ}iwŤŐH6ߪ§ű +%e +îYôţćęČłw!Ą6čć™č۬Y¶` ˇ‰><ݢ!>Yĺűęn2~ ě/‡ÎB•ZťV&ŻR™Ň5ËcpuôęŐŰžw%qfÔ©ĺšŇ‹cu ű†îč®sgĚ%vŢ7Ňäű%\Ś[g)GAĺ%*m‹~–M&8Ôň5÷9żB{ˇÜôĄ^sčÎ!u€Ľµl0ëc¶!—ę÷d"ČAŐy;É06“ń­ˇ•J­ţĺ]^={s3LŮxg—dĚ“×2ĎgŃqŁĹvYλÝH—Ă9ąWmó;lű­ËĹ®5®|¬?M˙4p€ĺĺë–‘‡ëup—ËëŚŔßj!ZŰg6Ú ŐŘĹÂwKÝá o×ŘhäŤŮ˝ĹQ ·ŕ€¸ĺşó^(]ĺ±Aľ 4Wš¶?»Q˙A4ýúSËáu‚ đhAţ„ö 8b’F~Ěd?h4y‚ő$ćĆ÷‰»+3o˙-óiKzjďzČ÷41ćË0˘ŁögRłńQdâÉAŔ¦řSfÝ&#Z—Ť†5_@Ă‹mĺUC}rM[ŔţלQ#gęg–<ÜM˘zôQ§N±&Ďi,ü?‘ ŻŰăť(YôěÝ{…•ĺtßdŚ*Ţ \¬ŐęćÂ-1Ň;LßďW ©`RŮN4˛ˇźöA˝˘¶ł×ĹŚN“K´¬ˇ1(ŽčE4ĎńÄ*‘Tú%ĂŕŁÍ@łâ}ůýży >]Ľâ-\3cŞF7.ô<úE>!áÍ´ćÉh‘ß$?úpi]Śö;Źę˛k‚.ĘcCR°ŁrËťřTyZ„Ü_ŕ‹çĺ2"H7‹w ĺK𕆹Ym}NFńOĄ®Ë\jfQ‡D˘ µĆÜôŔ—ř´ Ö'SÝy RQ łŠq.ŹWCÁ‹Čf—µł?RJ^ĐŰóľ `4"Ż3 k0çg{sÂĚ“|[˝—A1i'űd‡¸Š{Ťéř "˝ČĚ.´¸7YO«ő¬>ÚNĐëŚ7–äPďFĹ™=ZX$(Ş‹z­±í°př m•sŚśé¨Lú˝ "ď(+4‡<ńš!Aé»LféËńmËđ…LŹŇ>ůéC Ŕh¬íwZNńĚrg{"vż 4”Á+%kŚâ­ůkď®gÔ'Ť‹[ ¶K>TíD~[3hľoĎrÁšĂÜWü«U÷_IMBć•%é”^訅/ îŐíőż >µ1’B”6äSEcdždú-ŕŞčü‚Ęéľ%N¦ř6_cÁTóg Ż8çVŮm;Ć^‹ť§ëtµćż/Xť ĎĐż(±ý~Đ˙˙' Z‚A¶0¨ČÖý¬ˇ:Ďendstream endobj 186 0 obj << /Type /Font /Subtype /Type1 /Encoding 506 0 R /FirstChar 11 /LastChar 121 /Widths 507 0 R /BaseFont /KJJGRH+CMSSBX10 /FontDescriptor 184 0 R >> endobj 184 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /KJJGRH+CMSSBX10 /ItalicAngle 0 /StemV 136 /XHeight 458 /FontBBox [-71 -250 1099 780] /Flags 4 /CharSet (/ff/fl/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/A/B/C/D/E/F/I/L/M/N/O/P/R/S/T/U/V/X/Y/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y) /FontFile 185 0 R >> endobj 507 0 obj [642 0 586 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 367 306 0 550 550 550 550 550 550 550 550 550 550 306 0 0 0 0 0 0 733 733 703 794 642 611 0 0 331 0 0 581 978 794 794 703 0 703 611 733 764 733 0 733 733 0 0 0 0 0 0 0 525 561 489 561 511 336 550 561 256 0 531 256 867 561 550 561 561 372 422 404 561 500 744 500 500 ] endobj 506 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 13/fl 14/.notdef 45/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 65/A/B/C/D/E/F 71/.notdef 73/I 74/.notdef 76/L/M/N/O/P 81/.notdef 82/R/S/T/U/V 87/.notdef 88/X/Y 90/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y 122/.notdef] >> endobj 215 0 obj << /Type /Pages /Count 6 /Parent 508 0 R /Kids [178 0 R 223 0 R 277 0 R 297 0 R 311 0 R 337 0 R] >> endobj 367 0 obj << /Type /Pages /Count 6 /Parent 508 0 R /Kids [359 0 R 369 0 R 374 0 R 380 0 R 389 0 R 401 0 R] >> endobj 424 0 obj << /Type /Pages /Count 4 /Parent 508 0 R /Kids [412 0 R 426 0 R 446 0 R 463 0 R] >> endobj 508 0 obj << /Type /Pages /Count 16 /Kids [215 0 R 367 0 R 424 0 R] >> endobj 509 0 obj << /Type /Outlines /First 7 0 R /Last 147 0 R /Count 4 >> endobj 175 0 obj << /Title 176 0 R /A 173 0 R /Parent 147 0 R /Prev 171 0 R >> endobj 171 0 obj << /Title 172 0 R /A 169 0 R /Parent 147 0 R /Prev 167 0 R /Next 175 0 R >> endobj 167 0 obj << /Title 168 0 R /A 165 0 R /Parent 147 0 R /Prev 163 0 R /Next 171 0 R >> endobj 163 0 obj << /Title 164 0 R /A 161 0 R /Parent 147 0 R /Prev 159 0 R /Next 167 0 R >> endobj 159 0 obj << /Title 160 0 R /A 157 0 R /Parent 147 0 R /Prev 155 0 R /Next 163 0 R >> endobj 155 0 obj << /Title 156 0 R /A 153 0 R /Parent 147 0 R /Prev 151 0 R /Next 159 0 R >> endobj 151 0 obj << /Title 152 0 R /A 149 0 R /Parent 147 0 R /Next 155 0 R >> endobj 147 0 obj << /Title 148 0 R /A 145 0 R /Parent 509 0 R /Prev 123 0 R /First 151 0 R /Last 175 0 R /Count -7 >> endobj 143 0 obj << /Title 144 0 R /A 141 0 R /Parent 123 0 R /Prev 139 0 R >> endobj 139 0 obj << /Title 140 0 R /A 137 0 R /Parent 123 0 R /Prev 135 0 R /Next 143 0 R >> endobj 135 0 obj << /Title 136 0 R /A 133 0 R /Parent 123 0 R /Prev 131 0 R /Next 139 0 R >> endobj 131 0 obj << /Title 132 0 R /A 129 0 R /Parent 123 0 R /Prev 127 0 R /Next 135 0 R >> endobj 127 0 obj << /Title 128 0 R /A 125 0 R /Parent 123 0 R /Next 131 0 R >> endobj 123 0 obj << /Title 124 0 R /A 121 0 R /Parent 509 0 R /Prev 11 0 R /Next 147 0 R /First 127 0 R /Last 143 0 R /Count -5 >> endobj 119 0 obj << /Title 120 0 R /A 117 0 R /Parent 55 0 R /Prev 115 0 R >> endobj 115 0 obj << /Title 116 0 R /A 113 0 R /Parent 55 0 R /Prev 111 0 R /Next 119 0 R >> endobj 111 0 obj << /Title 112 0 R /A 109 0 R /Parent 55 0 R /Prev 107 0 R /Next 115 0 R >> endobj 107 0 obj << /Title 108 0 R /A 105 0 R /Parent 55 0 R /Prev 103 0 R /Next 111 0 R >> endobj 103 0 obj << /Title 104 0 R /A 101 0 R /Parent 55 0 R /Prev 99 0 R /Next 107 0 R >> endobj 99 0 obj << /Title 100 0 R /A 97 0 R /Parent 55 0 R /Prev 95 0 R /Next 103 0 R >> endobj 95 0 obj << /Title 96 0 R /A 93 0 R /Parent 55 0 R /Prev 91 0 R /Next 99 0 R >> endobj 91 0 obj << /Title 92 0 R /A 89 0 R /Parent 55 0 R /Prev 87 0 R /Next 95 0 R >> endobj 87 0 obj << /Title 88 0 R /A 85 0 R /Parent 55 0 R /Prev 83 0 R /Next 91 0 R >> endobj 83 0 obj << /Title 84 0 R /A 81 0 R /Parent 55 0 R /Prev 79 0 R /Next 87 0 R >> endobj 79 0 obj << /Title 80 0 R /A 77 0 R /Parent 55 0 R /Prev 75 0 R /Next 83 0 R >> endobj 75 0 obj << /Title 76 0 R /A 73 0 R /Parent 55 0 R /Prev 71 0 R /Next 79 0 R >> endobj 71 0 obj << /Title 72 0 R /A 69 0 R /Parent 55 0 R /Prev 67 0 R /Next 75 0 R >> endobj 67 0 obj << /Title 68 0 R /A 65 0 R /Parent 55 0 R /Prev 63 0 R /Next 71 0 R >> endobj 63 0 obj << /Title 64 0 R /A 61 0 R /Parent 55 0 R /Prev 59 0 R /Next 67 0 R >> endobj 59 0 obj << /Title 60 0 R /A 57 0 R /Parent 55 0 R /Next 63 0 R >> endobj 55 0 obj << /Title 56 0 R /A 53 0 R /Parent 11 0 R /Prev 23 0 R /First 59 0 R /Last 119 0 R /Count -16 >> endobj 51 0 obj << /Title 52 0 R /A 49 0 R /Parent 23 0 R /Prev 47 0 R >> endobj 47 0 obj << /Title 48 0 R /A 45 0 R /Parent 23 0 R /Prev 43 0 R /Next 51 0 R >> endobj 43 0 obj << /Title 44 0 R /A 41 0 R /Parent 23 0 R /Prev 39 0 R /Next 47 0 R >> endobj 39 0 obj << /Title 40 0 R /A 37 0 R /Parent 23 0 R /Prev 35 0 R /Next 43 0 R >> endobj 35 0 obj << /Title 36 0 R /A 33 0 R /Parent 23 0 R /Prev 31 0 R /Next 39 0 R >> endobj 31 0 obj << /Title 32 0 R /A 29 0 R /Parent 23 0 R /Prev 27 0 R /Next 35 0 R >> endobj 27 0 obj << /Title 28 0 R /A 25 0 R /Parent 23 0 R /Next 31 0 R >> endobj 23 0 obj << /Title 24 0 R /A 21 0 R /Parent 11 0 R /Prev 19 0 R /Next 55 0 R /First 27 0 R /Last 51 0 R /Count -7 >> endobj 19 0 obj << /Title 20 0 R /A 17 0 R /Parent 11 0 R /Prev 15 0 R /Next 23 0 R >> endobj 15 0 obj << /Title 16 0 R /A 13 0 R /Parent 11 0 R /Next 19 0 R >> endobj 11 0 obj << /Title 12 0 R /A 9 0 R /Parent 509 0 R /Prev 7 0 R /Next 123 0 R /First 15 0 R /Last 55 0 R /Count -4 >> endobj 7 0 obj << /Title 8 0 R /A 5 0 R /Parent 509 0 R /Next 11 0 R >> endobj 510 0 obj << /Names [(Doc-Start) 183 0 R (Hfootnote.1) 220 0 R (Hfootnote.2) 221 0 R (Hfootnote.3) 308 0 R (Hfootnote.4) 309 0 R (cite.rfc1035) 410 0 R (cite.rfc4035) 357 0 R (page.1) 182 0 R (page.10) 382 0 R (page.11) 391 0 R (page.12) 403 0 R (page.13) 414 0 R (page.14) 428 0 R (page.15) 448 0 R (page.16) 465 0 R (page.2) 225 0 R (page.3) 279 0 R (page.4) 299 0 R (page.5) 313 0 R (page.6) 339 0 R (page.7) 361 0 R (page.8) 371 0 R (page.9) 376 0 R (section*.1) 226 0 R (section*.10) 384 0 R (section*.11) 385 0 R (section*.12) 386 0 R (section*.13) 387 0 R (section*.14) 392 0 R (section*.15) 393 0 R (section*.16) 394 0 R (section*.17) 395 0 R (section*.18) 396 0 R (section*.19) 398 0 R (section*.2) 353 0 R (section*.20) 404 0 R (section*.21) 405 0 R (section*.22) 406 0 R (section*.23) 407 0 R (section*.24) 408 0 R (section*.25) 421 0 R (section*.26) 422 0 R (section*.27) 423 0 R (section*.28) 458 0 R (section*.29) 459 0 R (section*.3) 355 0 R (section*.30) 460 0 R (section*.31) 461 0 R (section*.32) 466 0 R (section*.33) 468 0 R (section*.4) 362 0 R (section*.5) 363 0 R (section*.6) 372 0 R (section*.7) 377 0 R (section*.8) 378 0 R (section*.9) 383 0 R (section.1) 6 0 R (section.2) 10 0 R (section.3) 122 0 R (section.4) 146 0 R (subsection.2.1) 14 0 R (subsection.2.2) 18 0 R (subsection.2.3) 22 0 R (subsection.2.4) 54 0 R (subsection.3.1) 126 0 R (subsection.3.2) 130 0 R (subsection.3.3) 134 0 R (subsection.3.4) 138 0 R (subsection.3.5) 142 0 R (subsection.4.1) 150 0 R (subsection.4.2) 154 0 R (subsection.4.3) 158 0 R (subsection.4.4) 162 0 R (subsection.4.5) 166 0 R (subsection.4.6) 170 0 R (subsection.4.7) 174 0 R (subsubsection.2.3.1) 26 0 R (subsubsection.2.3.2) 30 0 R (subsubsection.2.3.3) 34 0 R (subsubsection.2.3.4) 38 0 R (subsubsection.2.3.5) 42 0 R (subsubsection.2.3.6) 46 0 R (subsubsection.2.3.7) 50 0 R (subsubsection.2.4.1) 58 0 R (subsubsection.2.4.10) 94 0 R (subsubsection.2.4.11) 98 0 R (subsubsection.2.4.12) 102 0 R (subsubsection.2.4.13) 106 0 R (subsubsection.2.4.14) 110 0 R (subsubsection.2.4.15) 114 0 R (subsubsection.2.4.16) 118 0 R (subsubsection.2.4.2) 62 0 R (subsubsection.2.4.3) 66 0 R (subsubsection.2.4.4) 70 0 R (subsubsection.2.4.5) 74 0 R (subsubsection.2.4.6) 78 0 R (subsubsection.2.4.7) 82 0 R (subsubsection.2.4.8) 86 0 R (subsubsection.2.4.9) 90 0 R] /Limits [(Doc-Start) (subsubsection.2.4.9)] >> endobj 511 0 obj << /Kids [510 0 R] >> endobj 512 0 obj << /Dests 511 0 R >> endobj 513 0 obj << /Type /Catalog /Pages 508 0 R /Outlines 509 0 R /Names 512 0 R /PageMode /UseOutlines /OpenAction 177 0 R >> endobj 514 0 obj << /Author( Jelte Jansen, Wouter C.A. Wijngaards )/Title(Response Differences between NSD and other DNS Servers)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfeTeX-1.21a)/Keywords() /CreationDate (D:20061102103525+01'00') /PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4) >> endobj xref 0 515 0000000001 65535 f 0000000002 00000 f 0000000003 00000 f 0000000004 00000 f 0000000000 00000 f 0000000009 00000 n 0000256611 00000 n 0000416511 00000 n 0000000054 00000 n 0000000084 00000 n 0000262450 00000 n 0000416387 00000 n 0000000129 00000 n 0000000201 00000 n 0000262511 00000 n 0000416313 00000 n 0000000252 00000 n 0000000310 00000 n 0000262574 00000 n 0000416226 00000 n 0000000361 00000 n 0000000421 00000 n 0000267655 00000 n 0000416102 00000 n 0000000472 00000 n 0000000499 00000 n 0000267717 00000 n 0000416028 00000 n 0000000555 00000 n 0000000616 00000 n 0000267842 00000 n 0000415941 00000 n 0000000672 00000 n 0000000733 00000 n 0000270496 00000 n 0000415854 00000 n 0000000789 00000 n 0000000841 00000 n 0000270621 00000 n 0000415767 00000 n 0000000897 00000 n 0000000964 00000 n 0000270748 00000 n 0000415680 00000 n 0000001020 00000 n 0000001109 00000 n 0000272735 00000 n 0000415593 00000 n 0000001165 00000 n 0000001254 00000 n 0000275206 00000 n 0000415519 00000 n 0000001310 00000 n 0000001401 00000 n 0000275333 00000 n 0000415406 00000 n 0000001452 00000 n 0000001496 00000 n 0000278109 00000 n 0000415332 00000 n 0000001552 00000 n 0000001605 00000 n 0000278232 00000 n 0000415245 00000 n 0000001661 00000 n 0000001728 00000 n 0000278356 00000 n 0000415158 00000 n 0000001784 00000 n 0000001842 00000 n 0000278481 00000 n 0000415071 00000 n 0000001898 00000 n 0000001976 00000 n 0000278606 00000 n 0000414984 00000 n 0000002032 00000 n 0000002115 00000 n 0000278731 00000 n 0000414897 00000 n 0000002171 00000 n 0000002253 00000 n 0000281761 00000 n 0000414810 00000 n 0000002309 00000 n 0000002380 00000 n 0000281888 00000 n 0000414723 00000 n 0000002436 00000 n 0000002499 00000 n 0000282015 00000 n 0000414636 00000 n 0000002555 00000 n 0000002637 00000 n 0000282142 00000 n 0000414549 00000 n 0000002694 00000 n 0000002777 00000 n 0000282269 00000 n 0000414460 00000 n 0000002834 00000 n 0000002927 00000 n 0000282396 00000 n 0000414369 00000 n 0000002985 00000 n 0000003062 00000 n 0000285259 00000 n 0000414277 00000 n 0000003120 00000 n 0000003184 00000 n 0000285385 00000 n 0000414185 00000 n 0000003242 00000 n 0000003316 00000 n 0000285511 00000 n 0000414093 00000 n 0000003374 00000 n 0000003439 00000 n 0000285637 00000 n 0000414015 00000 n 0000003497 00000 n 0000003569 00000 n 0000285762 00000 n 0000413884 00000 n 0000003616 00000 n 0000003688 00000 n 0000285825 00000 n 0000413805 00000 n 0000003740 00000 n 0000003797 00000 n 0000289152 00000 n 0000413712 00000 n 0000003849 00000 n 0000003908 00000 n 0000289216 00000 n 0000413619 00000 n 0000003960 00000 n 0000004028 00000 n 0000289343 00000 n 0000413526 00000 n 0000004080 00000 n 0000004142 00000 n 0000289471 00000 n 0000413447 00000 n 0000004194 00000 n 0000004250 00000 n 0000294080 00000 n 0000413329 00000 n 0000004297 00000 n 0000004366 00000 n 0000294141 00000 n 0000413250 00000 n 0000004418 00000 n 0000004475 00000 n 0000294204 00000 n 0000413157 00000 n 0000004527 00000 n 0000004586 00000 n 0000298134 00000 n 0000413064 00000 n 0000004638 00000 n 0000004726 00000 n 0000298262 00000 n 0000412971 00000 n 0000004778 00000 n 0000004864 00000 n 0000298390 00000 n 0000412878 00000 n 0000004916 00000 n 0000004982 00000 n 0000298518 00000 n 0000412785 00000 n 0000005034 00000 n 0000005125 00000 n 0000301731 00000 n 0000412706 00000 n 0000005177 00000 n 0000005254 00000 n 0000006568 00000 n 0000006734 00000 n 0000214275 00000 n 0000005306 00000 n 0000214149 00000 n 0000214213 00000 n 0000411114 00000 n 0000400833 00000 n 0000410950 00000 n 0000400050 00000 n 0000395521 00000 n 0000399888 00000 n 0000213480 00000 n 0000394924 00000 n 0000393140 00000 n 0000394764 00000 n 0000392635 00000 n 0000389865 00000 n 0000392472 00000 n 0000213638 00000 n 0000388769 00000 n 0000381117 00000 n 0000388607 00000 n 0000380521 00000 n 0000378714 00000 n 0000380361 00000 n 0000213796 00000 n 0000377613 00000 n 0000368425 00000 n 0000377453 00000 n 0000213973 00000 n 0000367824 00000 n 0000364875 00000 n 0000367663 00000 n 0000363968 00000 n 0000357764 00000 n 0000363808 00000 n 0000412218 00000 n 0000009672 00000 n 0000009873 00000 n 0000009920 00000 n 0000213458 00000 n 0000302213 00000 n 0000302181 00000 n 0000224800 00000 n 0000217300 00000 n 0000214479 00000 n 0000224674 00000 n 0000224737 00000 n 0000217770 00000 n 0000356807 00000 n 0000348885 00000 n 0000356645 00000 n 0000217926 00000 n 0000218082 00000 n 0000347523 00000 n 0000331940 00000 n 0000347362 00000 n 0000218242 00000 n 0000218403 00000 n 0000218564 00000 n 0000218730 00000 n 0000218895 00000 n 0000219060 00000 n 0000219225 00000 n 0000219391 00000 n 0000219556 00000 n 0000219722 00000 n 0000219888 00000 n 0000220054 00000 n 0000220220 00000 n 0000220381 00000 n 0000220547 00000 n 0000220713 00000 n 0000220879 00000 n 0000221045 00000 n 0000221211 00000 n 0000221376 00000 n 0000221542 00000 n 0000221707 00000 n 0000221873 00000 n 0000222037 00000 n 0000222203 00000 n 0000222369 00000 n 0000222536 00000 n 0000222703 00000 n 0000222870 00000 n 0000223037 00000 n 0000223204 00000 n 0000223371 00000 n 0000223538 00000 n 0000223705 00000 n 0000223872 00000 n 0000224039 00000 n 0000224195 00000 n 0000224354 00000 n 0000224515 00000 n 0000226379 00000 n 0000252357 00000 n 0000226149 00000 n 0000224911 00000 n 0000252293 00000 n 0000250371 00000 n 0000250531 00000 n 0000250692 00000 n 0000250847 00000 n 0000251008 00000 n 0000251169 00000 n 0000251329 00000 n 0000251489 00000 n 0000251650 00000 n 0000251811 00000 n 0000251972 00000 n 0000252132 00000 n 0000229264 00000 n 0000229472 00000 n 0000229519 00000 n 0000250349 00000 n 0000256798 00000 n 0000255447 00000 n 0000252483 00000 n 0000256548 00000 n 0000255621 00000 n 0000255832 00000 n 0000256043 00000 n 0000331622 00000 n 0000329585 00000 n 0000331463 00000 n 0000256201 00000 n 0000256391 00000 n 0000256670 00000 n 0000256734 00000 n 0000262637 00000 n 0000258970 00000 n 0000256935 00000 n 0000262386 00000 n 0000259256 00000 n 0000259417 00000 n 0000259578 00000 n 0000259739 00000 n 0000328684 00000 n 0000320196 00000 n 0000328522 00000 n 0000259900 00000 n 0000260066 00000 n 0000260232 00000 n 0000260398 00000 n 0000260562 00000 n 0000260728 00000 n 0000260894 00000 n 0000261059 00000 n 0000261225 00000 n 0000261391 00000 n 0000261557 00000 n 0000261722 00000 n 0000261888 00000 n 0000262055 00000 n 0000262221 00000 n 0000267967 00000 n 0000264867 00000 n 0000262776 00000 n 0000267592 00000 n 0000265121 00000 n 0000265287 00000 n 0000265453 00000 n 0000265618 00000 n 0000265784 00000 n 0000265950 00000 n 0000266117 00000 n 0000266282 00000 n 0000266448 00000 n 0000266615 00000 n 0000266781 00000 n 0000266947 00000 n 0000267114 00000 n 0000267779 00000 n 0000267275 00000 n 0000267904 00000 n 0000267433 00000 n 0000301918 00000 n 0000270811 00000 n 0000270310 00000 n 0000268078 00000 n 0000270432 00000 n 0000270557 00000 n 0000270684 00000 n 0000319050 00000 n 0000308229 00000 n 0000318889 00000 n 0000412335 00000 n 0000272797 00000 n 0000272487 00000 n 0000270950 00000 n 0000272609 00000 n 0000272672 00000 n 0000275396 00000 n 0000274956 00000 n 0000272908 00000 n 0000275078 00000 n 0000275142 00000 n 0000275269 00000 n 0000278793 00000 n 0000277924 00000 n 0000275535 00000 n 0000278046 00000 n 0000278169 00000 n 0000278294 00000 n 0000278418 00000 n 0000278543 00000 n 0000278668 00000 n 0000282460 00000 n 0000281154 00000 n 0000278891 00000 n 0000281635 00000 n 0000281699 00000 n 0000281824 00000 n 0000281951 00000 n 0000282078 00000 n 0000282205 00000 n 0000281304 00000 n 0000282332 00000 n 0000281470 00000 n 0000285888 00000 n 0000284834 00000 n 0000282599 00000 n 0000285135 00000 n 0000285198 00000 n 0000285322 00000 n 0000285448 00000 n 0000285574 00000 n 0000285699 00000 n 0000284976 00000 n 0000301981 00000 n 0000289598 00000 n 0000287944 00000 n 0000285986 00000 n 0000289088 00000 n 0000288126 00000 n 0000288287 00000 n 0000288446 00000 n 0000288606 00000 n 0000288767 00000 n 0000288928 00000 n 0000289279 00000 n 0000289407 00000 n 0000289534 00000 n 0000412452 00000 n 0000294267 00000 n 0000291129 00000 n 0000289737 00000 n 0000294017 00000 n 0000291391 00000 n 0000291556 00000 n 0000291722 00000 n 0000291888 00000 n 0000292048 00000 n 0000292214 00000 n 0000292380 00000 n 0000292541 00000 n 0000292701 00000 n 0000292868 00000 n 0000293034 00000 n 0000293200 00000 n 0000293365 00000 n 0000293524 00000 n 0000293685 00000 n 0000293851 00000 n 0000298646 00000 n 0000296376 00000 n 0000294378 00000 n 0000298070 00000 n 0000296582 00000 n 0000296747 00000 n 0000296914 00000 n 0000297079 00000 n 0000297246 00000 n 0000297412 00000 n 0000297578 00000 n 0000297743 00000 n 0000297909 00000 n 0000298198 00000 n 0000298326 00000 n 0000298454 00000 n 0000298582 00000 n 0000302044 00000 n 0000300196 00000 n 0000298785 00000 n 0000301668 00000 n 0000301792 00000 n 0000300386 00000 n 0000301855 00000 n 0000300552 00000 n 0000300737 00000 n 0000307486 00000 n 0000302245 00000 n 0000307324 00000 n 0000300922 00000 n 0000301108 00000 n 0000301295 00000 n 0000301482 00000 n 0000307958 00000 n 0000307748 00000 n 0000319753 00000 n 0000319447 00000 n 0000329257 00000 n 0000328957 00000 n 0000331852 00000 n 0000331824 00000 n 0000348381 00000 n 0000347986 00000 n 0000357399 00000 n 0000357099 00000 n 0000364559 00000 n 0000364263 00000 n 0000368209 00000 n 0000368047 00000 n 0000378289 00000 n 0000377961 00000 n 0000381003 00000 n 0000380741 00000 n 0000389461 00000 n 0000389113 00000 n 0000392968 00000 n 0000392850 00000 n 0000395407 00000 n 0000395145 00000 n 0000400518 00000 n 0000400302 00000 n 0000411833 00000 n 0000411475 00000 n 0000412553 00000 n 0000412631 00000 n 0000416583 00000 n 0000418961 00000 n 0000419000 00000 n 0000419038 00000 n 0000419168 00000 n trailer << /Size 515 /Root 513 0 R /Info 514 0 R /ID [<1784B550E045DD0920A5548BA7339155> <1784B550E045DD0920A5548BA7339155>] >> startxref 419523 %%EOF nsd-4.12.0/doc/coding-style0000644000175000017500000000056015002373054015067 0ustar mozziemozzieCoding Style for NSD [This is incomplete, but a start] o No space after function/keyword o { on the same line as the if/while/for statement o If an 'if' has one statement in the 'then' part omit the braces: if (!x) return NULL; Indent the 'then' part with tabs o Function: return-type functionname(parameters, ...) { ... } nsd-4.12.0/doc/UPGRADING0000644000175000017500000000730415002373054014011 0ustar mozziemozzieUpgrading from NSD 3.x to NSD 4 by Wouter C.A. Wijngaards, NLnetLabs, Jul 2012 This document lists the changes in the upgrade from NSD 3 to NSD 4 systems. (scroll down for the NSD 2.x to NSD 3 upgrade manual). * nsdc is gone. You can control the daemon via kill -HUP and kill -TERM, or you can use nsd-control. * to setup nsd-control you have to run nsd-control-setup (as root) and enable remote-control in the nsd.conf file. It uses SSL to contact the daemon. * the nsd.conf file from NSD3 can be used for NSD4 (defaults for new stuff). * the difffile: setting is no longer used but ignored for backwards compatibility. * zones listed in nsd.conf are served. * the zonelistfile: setting sets the file where zones that are added dynamically (and can be removed dynamically) are stored. * the xfrdir: is used to store temporary zone transfer files. * it is possible to define patterns in the nsd.conf file and use the patterns to give config settings for the zones. * patterns accept the same sort of settings which NSD3-zones did. * you can make super-patterns with the include-pattern: setting * the zonefile: statement creates directories when needed, if they do not exist. In the zonefile: statement you can use %s (and other codes) to use (part of) the name of the zone to generate the pathname of the zonefile. * if there is no zonefile (for slave zones) it is not used. * nsdc rebuild and so on is gone, use nsd-control reload or kill -HUP. * it scans if zonefiles are modified and reads those. * you can also specify a zone by name and have nsd read that file. * if you nsd-control reconfig it rereads the config file for zones. * nsdc patch is not necessary * the database is edited at runtime. * it mmap's the nsd.db file for file I/O, this increases virtual memory usage of NSD with the size of the file. * if you like cronjobs, you could have one to nsd-control write and write slave zones that have changed to their zonefile. * other nsdc commands, reconfig (reread patterns, zones, keys), add a zone, delete a zone, and zone transfer control, statistics. Upgrading from NSD 2.x to NSD 3 by Wouter C.A. Wijngaards, NLnetLabs, Aug 2006 This document lists the changes in the upgrade from NSD 2 to NSD 3 systems. * The nsdc.conf file is gone. * specify the config file to nsdc by using the -c option. * binaries are searched for in the installation bin directory, in the PATH and in the directory of nsdc.sh itself. * other options go into the new nsd.conf file. * The nsd.masters file is gone, replaced by nsd.conf. * Look at nsd.conf.5 manual page to see format. * you can list nsd-commandline-options, zones, masters, slaves, keys. * TSIG support: please list the TSIG keys in nsd.conf, or do this with include: "keys.conf" and provide additional security for that file. * For every zone include lines: zone: name: "example.com" zonefile: "example.com.txt" * For secondary zones include in the zone entry: request-xfr: allow-notify: * For master zones include in the zone entry: provide-xfr: notify: * NSD does not provide IXFR, so for secondaries that connect to NSD use request-xfr: AXFR that will only use AXFR, not IXFR to request zone transfers. * No more need for a cron job to do a nsdc update. * nsd will update automatically all secondary zones from master. * You should never need to do nsdc update or nsdc notify by hand. * You can still use a cronjob to do nsdc patch. nsdc patch moves the zone transfer content from temporary storage to the zone files, recompiles the database and reloads nsd. nsd-4.12.0/doc/TODO0000644000175000017500000001577115002373054013245 0ustar mozziemozzie$Id$ AUTOCONF - check/translate arguments to --with-facility ZONE COMPILER - unify dns type table (name, dns type, yacc token, rdata types) prettier? - unify dns class table (name, dns type, yacc token) prettier? - one db file per zone (as an option?) (featurecreep)? req by Alex (Bit). So that after rsync, zonec is fast with many zones. - if a zone is dropped from the config file, but not removed from the nsd.db. NSD refuses to start. Should skip/drop the zone. Redesign file format, so that you can skip a zone more easily, this also makes multiply db files easier. - profile the zonec compiling speed. Speed it up. Many people complain about this. - wireformat interop. testing for IPSECKEY type. - chown nsd nsd.db (Paul Wouters nsd-users mail) SERVER - make sure that we dont copy anything from the query we dont want to copy, like funny headers etc - From Aaron Hopkins: set O_NONBLOCK on all sockets. Now a udp raging herd of server can get woken up when a message arrives. One server handles the packet, the rest blocks on that socket and does not serve other sockets. - From Aaron Hopkins: write tcp length and tcp data in one write operation, instead of multiple calls to write. Avoids Nagle algo delay in this case. preallocate 2 bytes in front of buffer to put them into. - Test TCP performance (do a lot of AXFRs, different zone sizes, and compare time averages). - From Aaron Hopkins: after you do select calls, do multiple read calls per select. This polling improves performance in high-load situations. Speed test to prove that it does so. - Turn off TC bit on all error replies. - Bug #133: print empty statistic blocks. Not sure if the feature is wanted. - XFRD should throttle the number of notifys going out for a zone to x/minute. (even if updates are very often). - Option to only notify a batch of slaves (from loads) at a time, with timeout between. - Round robin selection to send notify to secondaries. So the last one on the notify list does not diverge. - xfrd NOTIFY timeouts exponential backoff. - query SOA before getting AXFR and then cutting it off, it causes an errlog on the master. - when verbose, print the ip addresses that cause network errors to the log. - the server reaps children every minute, this is bad for powersaving laptops. - Implement AXFR clarify, RFC 5936. SECURITY PURITY - some data is in network order some in host order, make it clear with prefixes prettier? - brush up the function and identifiers names - The XFRD zone state can be split up in expired/service-possible and in idle/zone-transfer-busy state flags. Is this more beautiful? - no more #ifdefs, remove them all, but keep configure options. - getflags on socket before setflags nonblocking. - exponential backoff for retries xfrd and notify. - conformance to RFC: NSD accepts TSIG before OPT in additional, but this is not legal, only TSIG after OPT is allowed. - Allow for username: uid:gid, next to uid.gid. - Log error when serial in xfrd.state is inconsistent with that from nsd.db. NSD PATCH - -q(?) option: no output when no patch necessary - cleaner output on normal operation (don't mention memory) - patch on demand after a xfrd reload has occurred (including checks for disk memory and a reload timeout (no more often than 15 minutes or so)?). CLEANUP - make so that startup sends SOA_INFO to xfrd just like reload does, prettier? - dlopen and dynlib checks can be removed from autoconf scripts. - If presentation format NSEC3 stays, put optout-iterations into one 4byte datatype, easier reading and printing, avoids ugly special cases. DOCUMENTATION - document what to do when adding (or removing) a config option (what changes have to be made in the code). OPTIMISATIONS - delete entire zone for AFXR during reload read in, now walks the tree, but could use a double linked list to speed up. - less memory churn in deleting RRs/adding RRs: keep rrset->capacity num. initial read in capacity==limit, if you want to add RRs, alloc capacity*2. - less memory churn in deleting rrsets : keep a linked list of deleted rrsets for reuse. Keep a list (based on buckets of size of the malloc) of rr arrays. Keep a list (based on buckets of size of malloc) of rdata arrays. Keep a list (buckets on size) of rdata_data allocs. For reuse, buckets on char size, because we know most are small anyway large ones can be discarded/churned. - Look for special purpose memory allocators for NSD. - compress dnames in ixfr queries (write_soa_buffer) (zone 2x, mname, rname). small gain, nasty code. - compress dnames in tsig records, keyname, algorithmname. - compress names in packets by pointing to uncompressed_dname entries. After each DNAME(with uncompressed target) follows a CNAME that can be compressed in this way. - Do not give servfail during reload quit sync process. Only stop old server processes once the new ones are forked and answering for secondary zones (so when xfrd is done with sending zone state to all children). The brief double answers are preferable to brief SERVFAIL. - nsd manual programs contain identical functions that are written down multiple times. Do we need to introduce a util_programs.c or something? - reduce the memory leak on zone transfers (deleted domains are not removed from tree). - Options server: ip-address: and zone: outgoing-interface are pretty much the same. - Options to make NSD restrict AXFR response messages to a single RR (RFC5936) TESTS - tpkg test for bug 157: a valid NSID EDNS0 option generates FORMERR on nsd-3.0.5 - tpkg test for bug 163: unable to read nsd.db when chroot'ed - tpkg test for bug 164: chkconfig - Update tpkg long tests - tpkg test for bug 347: NSEC3 no data tests when requesting DS From tpkg/bugzilla-bugs todo: ! - other ways to test this? ! 3 "RCODE for dynamic updates" --- how to send dynamic updates? ! 20 "256 questions per-se should generate form err" ! 22 "trailing byte in queries (see also bug4)" ALLOW TESTING WITH TRACES ! 31 "query section not included in 'NotImp' answers to updates" ! 37 "invalid packet echoed on FormErr" - how to send stuff with tcp replay ! 100 "zonec alters RRSIG inception/expiration" on sparc only --- hmmmm ! 29 "NSD sends answer on notify" - cannot send notify with DIG M - Moet nog M 157 "return FORMERR if edns query is received with version=0 and rdlen>0" M 163 "..." M 164 "chkconfig" - - too little information to write a testcase - 4 "Correctly handle queries with too much data" to little info - 6 "different name encodings?" - 7 "sometimes label compression skip some parts" - 8 "do not exit on sendto buffer exhaustion" - 10 "Segmentation violation while trying to destroy the database on exit" - 11 "EDNS(0) spurious formerr" - 14 "Magic string alignment" - 15 "nsd hangs on some queries..." - 16 "zonec dumps core with HASH -z nl nl -c . examples/zones/root" - 18 "name compression not quite 100% yet" - 28 "Wrong additional section RRcount in case of EDNS." - 35 "sending wrong name errors (NXDOMAIN)" - 36 "we should not bounce on RR Type when doing a referral" nsd-4.12.0/doc/TESTPLAN0000644000175000017500000003556415002373054013734 0ustar mozziemozzieTEST PLAN for NSD. By W.C.A. Wijngaards, July 2006, NLnetLabs. 1. Introduction --------------- NSD 3 contains far more features than a typical point release. These features need to be tested and checked to make sure they work well. This document describes a plan to test all the features that have been added to NSD. Regression testing is also very important. The old features must remain working. We have a set of tpkg packages to help with it. And also root-trace speed tests to regression test NSD. The feature tests are to be automated, using tpkg packages where possible. 2. Minor Features ----------------- Some minor features for the test: 2.1. DNAME ---------- DNAME support - there are already extensive DNAME tests. (closed). 2.2. NSEC3 ---------- NSEC3 support - use the perl automated nsec3 test - port to tpkg perhaps. Note NSEC3 hash length byte to be implemented, test against others. Test interoperability of that. A simple zone transfer with Bind. (experimental, no need to test any more). 2.3. NSID --------- Would make a nice nsid.tpkg package. NSID support - run NSD with different NSIDs and queries. a- test NSID with zero length, query with NSID. b- very long length, query with NSID c- 012345678 and query for different things. 1- query OK things. - query error 2- nxdomain, 3- loop, 4- nodata. 5- query error (bad queries, wrong zone) - is NSID present. d- NSID and TSIG. 1- query has OK TSIG 2- query has BAD TSIG 3- query for nxdomain 4- bad query, wrong zone e- configure NSID from config file? - is this possible f- test if NSID in NOTIFY responses. (should there?) ldns-notify and parse result packet for nsid. g- test if NSID in AXFR responses. (should there?) drill axfr and see if nsid in result packets. (experimental, so low priority). (need a way to send NSID enabled queries - no test). 3. Transfers ------------ For the transfers the test are to be done using - NSD as a master(AXFR) in 3.1, or a ldns-ixfr miniserver(IXFR) as a master in 3.2 that serves pre-made ixfr answers. The zone transfer tests can be put in one tpkg by using servers at different ports. The allow- lines are then for localhost, all ports (since the sending process uses ephemeral ports, all must be allowed). The request- lines contain the correct port numbers to send to. 3.1. AXFR --------- 3.1.1. AXFR features -------------------- Setup is a secondary zone which requests to a master. the master zone is updated. Then, the secondary should be informed with the notify: statements. And test if secondary got the same zone as master. By doing axfr from both servers and check if the same, and serial nr. Tests 3.1.1 can be one tpkg. (with serial numbers for SOA, to perform serial rollover). - secondary starts with a zone without content (soa=1) so the zone is only mentioned in the config, the zonefile is empty/nonexist on the slave. Master has a soa and three text records. - axfr an empty zone - only the SOA (soa=2) - axfr a zone with only little data. (soa=3) some NS, MX, A, AAAA records. [NOTE: apparently, due to the linked list mgt in domains (of rrset*) the ordering of rrtypes for a domain is reversed after a zone transfer for NSD, i.e. for query type=any. Ordering within an rrset is preserved. Created fix to ordering, but is slow for many rr types... ] - old zone unsigned, new zone signed. (soa=4) sign with two KSKs and one ZSK. And a prepublished ZSK in the zone. ZSK1: Kexample.com.+005+44537 ZSK2: Kexample.com.+005+03824 (prepublish) KSK1: Kexample.com.+005+53988 KSK2: Kexample.com.+005+25320 (presign) - old zone signed, new zone unsigned. (soa=5) different zone contents, some names are still there, unchanged, some names are there RRs changed, some names there different RRtypes, and some names removed, some names added. www: unchanged (including nsec,rrsig). webmail: mail prio changed. printer: name removed. terms: different RR types, now A type. mail: type TXT added. apex: type DNSKEY, nsec, rrsig removed. newservice, ooo: new names - new zone with nsec3. (soa=6) iter=33 salt=AA44FF11 slave detects NSEC3 settings. - new parameters for nsec3. (soa=7) iter=1078 salt=00998877665544332211AADDCCFF slave detects NSEC3 settings. - new zone no longer uses nsec3. (soa=8) uses nsec. - axfr an empty zone (only the SOA) (soa=9 + a lot for serial wraparound) 2**31 = 2147483648 9 + 2**31 : 2147483657 also tested 9 + 2**31-3 -- works. notify and transfer, zone updated. 9 + 2**31-2 -- works. notify and transfer, zone updated. 9 + 2**31-1 -- notify works, but at transfer time 'serial old'. fixed: works, zone updated. 9 + 2**31 -- notify is ignored, 'serial old'. 9 + 2**31+1 -- notify is ignored, 'serial old'. - axfr wraparound zone, couple txts. (soa=2) serial=2 works after serial=9 + 2**31-2 before. These can be done in order. Test done for AXFR. RRset-type ordering preserve fixed. Serial rollover fixed. Serial printed as unsigned. 3.1.2. Huge xfr - see test tpkg for this. It works already. 3.1.3. AXFR and TSIG Like 3.1.1. but enable tsig. Tested, it works. 3.2. IXFR --------- 3.2.1. IXFR Features -------------------- Setup is a secondary with ldns-mini-ixfr server as a master. (ldns/examples/nsd-test/ldns-testns.c). The mini ixfr server responds with canned replies to a IXFR query. - secondary loaded with only the soa = 1. notified with 10. ixfr server responds with soa=1. (i.e. no update available). - same, ixfr server responds with soa=2, and TC (udp). on tcp connection, it responds with a simple difference package. SOA2 SOA1 SOA2 newTXTA newTXTB SOA2 adds a couple records. - to soa is 3, and this one removes the TXT records, makes a new TXTB record and a TXTC record. test that TXTA domain does not exist NXDOMAIN. test that TXTB is updated. test that TXTC exists. - from 3 to 5, with 4 in between. make a ixfr packet that is 3 .. 4 and 4 .. 5 concatenated without compression, so it means more work for processing. So, in the ixfr packet TXTB is removed from 3, added in 4, removed from 4, added in 5. Also in vs4 a txt5 record is added, which stays around. - from 5 to 7, but this time the redundant work is removed from ixfr packet. - 7 to 8, have one domain name where two RR types exist, A and DNAME. remove one RR type in IXFR then make sure the other type still exists. - 8 to 9, have a name with many different A records. Remove one A record from it. Add another A record to it. Test if the rest is there. [Note: when you delete on RR from an RRset, the ordering of the RRset changes, the contents of the rrset get shuffled (last put in empty slot).] 3.2.2. a huge ixfr. ------------------- create test for it. Should be several MBs worth or data removed, MBs of data that stays the same, and MBs that are added. To make sure that the code can handle multiple packet IXFRs, and the state memory between IXFR packets. - created testns version for multiple packet reply. Small, multiple packets. Test from 3.1. but using multiple packets: one RR per packet. This test also falls over from udp to tcp for ixfr. - This works. The Mbs in size is tested in huge axfr test already. 3.2.3. Test remove domain ------------------------- - is_existing = 0 used to remove a domain. Check and test carefully. - test delete middle name i.e. you have a zone with: c.example.com TXT "x" b.c.example.com TXT "x" a.b.c.example.com TXT "x" and you delete the b.c. record. The b.c becomes empty nonterminal. If you then delete a.b.c. TXT, the b.c becomes NXdomain. [- fixed delete with IXFR for empty nonterminals.] - test delete/add a domain and NXdomain/exist replies. - tested in 3.2.1 already, works. - test delet domain and wildcard replies. - Tested, it works, fix for IXFR that makes empty nonterminals. 3.3. Timeouts ------------- Get zone to expire. Check it does not answer. Start only a secondary server, no master. Set expire timeout short. Timers set as refresh=1 retry=1 expire=10 minimum=10 Provide an update. Check it does answer again. Startup the master server after a while. Transfer should happen within the retry interval. Wait for zone to expire again. Check that. Provide old zone on the master, after expire the slave must transfer it. The above works, old zone is transferred and served. Test that the master says that serial number is OK, in 3.2.1 tests. This test also includes IXFR reply from the master that contains AXFR contents. 3.4. TSIG zone transfers ------------------------ Already TSIG tpkg tests, with transfers TSIG protected, so that is ok. TSIG notifies - test it, create test for it. - notify accepted, nsd->nsd notify by starting master and slave server with tsig keys for a zone, update zone at master. Done in 3.1.3. - notify refused. nsd->nsd notify same but use different secret at one server. Test done. 4. IPC -------- 4.1. deadlocks -------------- Have 100.000 zones, all with short SOA timeouts, expire=1 sec. refresh=10. Expire very quickly. This gives many messages from xfrd to server. Send notifies to the server in a loop from a shell script. Lots of messages the other way around. Provide a master server that will serve all the zones (and say they are ok). then proceed to send queries for the zones to the server and see if you get answers. Wait for an hour and try again. Result, the IPC works okay, but xfrd uses much memory, 16Kb for TSIG regions, per zone. With the 2.5 kb in xfrd almost 20 Kb per zone. For 2G for 100.000. A bit much memory, for the largely unused tsig regions. Fixed, tsig for xfrd uses no preallocated worst case memory use, but only a small footprint. During use this may grow; about 1 K per zone perhaps. About 2.5Kb per secondary zone in xfrd, below 1 Kb for a master zone, that works out for 100.000 secondary zones as 250 Mb for xfrd. Perhaps do also with 100 child servers for the NSD. see if it can keep up and the result if it cannot keep up sending to child servers. Since it has to send for each zone to each child a message, this will take more resources. Tested, it cannot keep up. Child servers operate using old zone status of expired/ok, also the machine load is 100%. Also fixed tsig.other_size to be checked when reading TSIG from network. Due to the length and size, more an incidental test, but can be tpkg-ed. 4.2. IPC FORKS -------------- Infinite loop of reloads on a server. Has 10 child servers. wait. See if it runs out of sockets, file descriptors, etc. incidental test. Tested, with adjusted source that repeats reloads. This puts strain on the reload ipc handshake code. And ipc socket code. It works fine. 5. Random mess test ------------------- Setup 7 servers. In master->intermed->slave, with multiple master(2), intermed(3) and slave(2) servers. TSIGs (different) for everyone. Perhaps also include never respond entries (fake address) in acls. - Load random SOA + random data in servers. Backup the setup so it is repeatable. Let them work out what version to run. - Provide updated zone for a master. See what happens. - Send notifies to the slave servers. - Send notifies to the intermed servers. - Send notifies to the master servers. - Kill some server. Start it again. - Kill some server & delete some file (ixfr.db or xfrd.status). - delete ixfr.db - delete xfrd.status - delete ixfr and xfrd files. - run nsdc patch on a server. - pretend an intermediary was offline for a long time with old zone files and old ixfr.db and xfrd.state(!!) files. and see what happens :-) It should refresh/expire and so based on timers in xfrd.state. Tested: - nsd returns formerr on IXFR queries because of data in NS section. But this is correct, fixed NSD, so it is no longer formerr, but refused / not authorised instead. (or whatever we put in axfr.c). - depending on which server they are asking, servers will use one of the master zones (after expiry time exceeded). If master updated, intermediaries, then slaves update themselves too. - NSD would not start with a corrupt diff file. Now logs error and ignores, fixes, the diff file. 6. Portability test ------------------- Port NSD to as many platforms as possible - local: sparc5(ok), alpha(ok), amd64/OpenBsd(jelte thuis), open=FreeBSD(ok), linuxes(ok), MacOsX(ok), Sunos4(ok). - sf compilefarm for more. - x86-linux2 has ip6 disabled. tests dont work with that. - minix3 if we can get it working (the minix3 setup fails somehow). - would be good to have a test set of tpkg (and tools required) to run after a port-test. A very portable set of tpkgs. OSTYPE: (g)make. autoreconf. (g)indent. -> defaults for * systems. dig 8.3 too old (format of output). Need 9+. however dig/bind is not portable enough. ldns: pcat, pcat-diff, pcat-print. xfr1,2:nsd-ldnsd. pcat-grep.pl manual: md5sum/md5. hping(sudo). long: ldns-testns. Made tests more portable, ran tests on linux, freebsd, Solaris. Full testset run on SPARC/SunOS2.5, and fixed two unaligned memory accesses, all tests succeed now. Full testset runs on Powerpc/MacOSX. 7. CODE REVIEW -------------- Code has already had 1x review by Wouter, some review by Miek. More review (again), Jelte, Wouter. - Do some spots of interest. - perhaps a full review as well. 8. todo-tests ideas ------------------- These would be nice as tpkgs, but perhaps manual tests are needed. 8.1. test combinations of configure options and shells ------------------------------------------------------ " run tests with different shells, aka ==-bug bash 1.1. is too old for [[ in tpkg and tests. Some hosts have awk that puts a space before .pre files in tpkg. Some hosts have bash in /usr/local/bin so tpkg fails on that. run tests with different configure options and combinations of them. Many tests fail with disable-ipv6. implement this in a xen-like environment so that different OSs can be checked. run this daily or only when subversion changes for each test, run our "test-suite" " 8.2. patch file remove ---------------------- rm patch file, check xfrd's behavior. Refetches zones Checked in section transfer_axfr. 8.3. 64 bit ----------- GB 64 bit file size transfers. On alpha so nastiest alignment on 64bit machine. Do transfer of > 4 Gb zone. Needs lots of memory(swap space) and disk space. Not done; no host for test. 8.4. Valgrind ------------- run with valgrind - on two nsds. then do the nsd-nsd, and notify the master to get axfr to happen test, with tsig as well enabled. Done, found one uninit variable. 8.5. Chroot ----------- test chroot and the new files/directories. (And the file/dir not in chroot problem, and if all is OK that it works). Done, default locations for ixfr.db and xfrd.state have full pathnames. 8.6. nsdc --------- In temporary test setup above, test nsdc tool. works. Make sure that if nsdc patch breaks a zone transfer in progress it is reattempted later on. hard to test. 8.7. nsd-patch -------------- nsd-patch - run nsd patch and compare zone files, like AXFR/IXFR tests. Done test axfr run, or test-mess. 8.8. gcov --------- gcov to look at code coverage of the tests. Tests added to improve coverage. nsd-4.12.0/doc/REQUIREMENTS0000644000175000017500000010417115002373054014414 0ustar mozziemozzie$Id$ NSD Requirements and Specifications ______________________________________________________________________ A. Scope. NSD is a complete implementation of an authoritative DNS nameserver. This document describes the basic requirements and specifications for this implementation. B. Requirements B.1. General Requirements These requirements are in order of importance: 1. Conformity to the relevant DNS RFCs If complying with the letter of the RFCs will cause a conflict with high load resilience reasoned trade-offs will be made and documented. 2 Code diversity from other implementations NSD is developed from scratch and does not share code or design with other implementations. 3. Authoritative server only NSD is designed to provide authoritative answers only. There are no facilities for caching or recursion. 4. Open source The code will be open source after the first public release. 5. Regression tested against bind8/9 Extensive regression tests with real trace data and synthetic exceptional data will be carried out. For the real traces any differences with bind8/9 will be documented. Should there be substantial differences a bind8/9 compatibility option will be considered. The testing tools will be published separately as much as possible. 6. Resilience to high load As many as UDP queries answered as possible per time interval. Aware of useless queries and limiting answers to conserve output bandwidth. This may supersede strict RFC compliance. Mitigation of DDoS attacks as far as feasible. 7. Documentation The implementation will be well documented with the aim of allowing others to understand its operation in order to be able to maintain the code. This includes these requirements, a general design document and well documented code. 8. Reviewed code All code will be reviewed by at least two persons other than the primary author before being included in a release version. 9. Simplicity NSD will not do things that are not strictly necessary for its task: authoritative name serving. If in doubt a feature is more likely not to be included. The code strives to be as simple and straightforward as possible, even if it looks stupid ;-). 10. Reasonable Portability Should be reasonably portable across hardware architectures and OS platforms. Rough targets: (Intel/SPARC/Alpha)(FreeBSD,Linux,Solaris) 11. Maintenance for initial period NLnet Labs and the RIPE NCC will support NSD for at least 12 months after publication. B.2. Explicit NON-Requirements 1. No caching NSD will not provide cached or recursive answers. 2. No slavish responsiveness NSD may decide to limit answers to queries it considers malicious or useless if this enables it to provide better service to queries it considers valid. Conserving output bandwidth is a consideration. 3. No end-user friendliness NSD operators are considered to have basic Unix and networking knowledge and are also considered to be able to read and understand reasonably written user documentation. 4. No creeping featurism NSD will not implement any functionality that is not strictly necessary for the task of authoritative name serving. Examples: round robin sequence of RRset members in consecutive answers, Also no dynamic plugins. C. Technical Specification. C.0 Environment The server runs with the least possible permissions. NSD will not implement special VM work-arounds to accommodate zones larger than order 10 million RRs in 32-bit address space machines. Operators requiring huge-zone support can use 64-bit machines. C.1. Zone file format and RR records. Zone file format as specified in rfc1035 (5.1), including the $TTL entry for default TTL as in RFC2308 (4) and the binary label format as in RFC2673. We implement most RRs currently assigned by IANA (http://www.iana.org/assignments/dns-parameters) except for RRs that are obsoleted by IANA or assigned experimental, those MAY not be implemented. See below and/or release notes. Zone file MUST not contain errors. i.e. the zonecompiler may fail or produce unpredictable results when: - RRs that are obsolete and not implemented are encountered. - Syntax errors are found (RFC1035 5.2) + not all RRs are of the same zone + not exactly one SOA RR is present at the top of the zone. + delegations are present but required glue is not present. + Out of Zone, non-glue data is encountered. + not all RRs in a RRset have the same TTL (RFC2181 5.2) + if a DNAME exists at node N there may not be any other data at 'N' (except CNAME or DNAME) and there MUST not be any other data at subnodes of 'N' (RFC 2672 section 3). - The default minimum TTL is not specified by the $TTL directive Zones that are parsed by the zonecompiler will be served by the nsd daemon. Only zone files of CLASS "IN" are supported. The zone file parser sets the TTL of those RRs that do not have their TTL defined to the minimum TTL as defined by the $TTL directive unless the RR is part of a RRset and the TTL is set for one of the RRs in the RRset. Parsing of the names in zone files is case insensitive (Note: RFC1035 2.3.3 also see 1034 3.1 "The basic rule is that case can be discarded only when data is used to define structure in a database, and two names are identical when compared in a case insensitive manner." ) The database relies on case; all names will be parsed to lower case. Case of dnames in RDATA will be preserved except for dnames for which dname compression in RDATA is allowed, those dname fields are converted to lower case. (for that subset of RRs compression has preference over case preservation). Also see Appendix B for dname compression in RDATA. DNSSEC consideration (as of 2.0.0): DNSSEC processing of data in a zone will only take place if that zone is marked to be secure. A zone is marked secure if the SOA record is signed. The zone data is not cryptographically checked at the time the zone db is generated; NSD always clears the AD flag on answering data from a secure zone in the database. NSD always copies the CD bit from the query to the response. NSD does not include the DNSKEY RRset in the additional section on queries for the SOA or NS records at the zone apex. It is not clear whether including the DNSKEY RRset is advantageous and not doing so simplifies NSD. C.2. Server and connection management. The server listens on port 53. The server answers with the same IP address and port (53) as the queries has been sent to. Replies are sent to the address/port the queries originated from. (rfc 2181 4) UDP. The server is optimized to handle UDP queries. Large packet sizes are supported. The size is set by the OS (e.g. net.inet.udp.maxdgram on FreeBSD). TCP. The server accepts TCP connections. Note that there may be one or more DNS messages in the stream. Each message is prepended with a 2 byte size (rfc 1035 4.2.2) Connection management (rfc1035 4.2.2.) + the server should not block other activities waiting for TCP data + The server should assume that the client will initiate connection closing and should delay closing its end of the connection until all outstanding client requests have been satisfied. + For closing dormant connections the timeout should be in the order of 2 minutes. NSD specific: + The maximum number of open TCP connections is configurable. It is assumed the OS copes with attacks on the TCP stack (e.g like SYN attacks) C.3 Incoming DNS Message processing. NSD specific choices. These issues are not addressed in the RFCs. Behavior is defined below. + Non parsable messages are replied to with a FORMERR. + Each UDP packet only carries one DNS Message. Any data behind the DNS message is considered garbage and is ignored. + Incoming DNS messages with the QR bit set to 1 (response) are discarded. (In spirit of rfc 1035 sect 7.3) + RD is copied into the response (rfc 1035 4.1.1) the RA bit is set to 0 and the QUERYID is copied into the response message. + OPCODE 0 (QUERY) results in normal handling of packet (rfc1035) OPCODE 1 (IQUERY) results in RCODE=4 NOTIMPL (rfc1035) OPCODE 2 (STATUS) results in RCODE=4 NOTIMPL (rfc1035) OPCODE 3 (RESERVED) results in RCODE=4 NOTIMPL OPCODE 4 (NOTIFY) results in RCODE=4 access control list processing and then handling of the notify. (rfc1995) OPCODE 5 (UPDATE) results in RCODE=4 NOTIMPL (rfc2136 sect 3) + AA bit in query packet is ignored. + TC bit set in a query packet is answered with FORMERR. [This must always be a broken implementation since the max length of the name is 255 octets.] + RCODES are ignored. + QDCOUNT=1 results in further processing. QDCOUNT!=1 results in RCODE=1 FORMERR + QCLASS=IN results in further processing. + QCLASS=ANY results in further processing with the AA bit in the response off (rfc 1035 6.2) + QLASS=CHAOS only leads to further processing if the queries are for the names ID.SERVER or VERSION.SERVER. Any other query in that namespace will lead to RCODE=REFUSED. For QTYPE other than TXT a NOERROR with a trivial SOA RR in the AUTHORITY section will be returned. Behavior for QTYPE=TXT is defined in draft-ietf-dnsop-serverid-00.txt + QCLASS!=IN && QCLASS!=ANY && QCLASS!=CHAOS results in RCODE=REFUSED [Background: BIND8 generates a SERVFAIL but I would say that a A NOERROR message with empty Answer, Authority and Additional section is also a good answer and more in the spirit of RFC 1034 section 4.3.1. We choose to mimic the behavior of bind. BIND9 generates a status RCODE=5 REFUSED. ] + Other sections should be empty otherwise FORMERR. + except, EDNS and TSIG opt records are allowed. + TSIG signature is checked, otherwise a TSIG error. + Presence of OPT RR indicates support of EDNS (rfc2671). If the VERSION > 0 then the server will respond with an OPT with RCODE=BADVERSION and VERSION=0 (The server supports EDNS0) In further processing ENDS0 support is taken into account. + If the DNSSEC OK bit (DO bit) is set then the query will be processed as a DNSSEC request. Although RFC3225 does not explicitly specify this NSD clears the DO bit in the answer. C 4 Further Query processing. Preconditions: + the QCLASS is either IN or ANY. For both classes the IN class zones are searched in the same manner. The difference in the response will be in the Authority information. + It is known if the requester supports EDNS0 + There is only one query in the DNS message to be answered. + The RD & message ID of the incoming query has been copied into the response message. + It is known if the requester wants DNSSEC processing as indicated by the DO bit being set. C 4.1 Actions based on QTYPE of incoming Query. If QTYPE>=249 we are dealing with special queries. case QTYPE=TKEY case QTYPE=TSIG case QTYPE=IXFR respond with RCODE=5 (REFUSED) case QTYPE=AXFR respond with AXFR (TSIG is supported) case QTYPE=MAILB proceed with processing. case QTYPE=MAILA proceed with processing. case QTYPE=ANY proceed with processing. QTYPE < 249 process the query Further processing of the packet is based on the algorithm from 1034 as modified by (rfc2672 4). Below is the algorithm as applies to an authoritative cache-less server and with the preconditions from above. We have also included DNSSEC considerations (rfc2535 and rfc3225) The first versions of NSD will not have DNSSEC processing implemented. (Read this as the DO bit is not set). 1. Search the available zones for the zone which is the nearest ancestor to QNAME. If such a zone is found, go to step 2, otherwise step 3. 2. Start matching down, label by label, in the zone. The matching process can terminate several ways: a. If the whole of QNAME is matched, we have found the node. If the data at the node is a CNAME, and QTYPE doesn't match CNAME, copy the CNAME RR into the answer section of the response, change QNAME to the canonical name in the CNAME RR, and go back to step 1. If the DO bit is set in the query the RRSIG(CNAME) needs to be copied in the answer section as well. Otherwise, copy all RRs which match QTYPE into the answer section. Also copy corresponding RRSIGs into the answer section if the DO bit was set, goto step 4. If QTYPE is 'ANY' copy all RRs including the security related RR types regardless if the DO bit was set into the answer section. If none of the RRtypes matched QTYPE, the DO bit was set and the zone is marked secure then the answer section is left empty and b. If a match would take us out of the authoritative data, we have a referral. This happens when we encounter a node with NS RRs marking cuts along the bottom of a zone. Copy the NS RRs for the subzone into the authority section of the reply. If the DO bit has been set then if the zone is marked secure then if there is a NSEC record or DS record then include the DS bit and associated RRSIG(DS) into the authority section if the DS record is present for this delegation. If there is no DS record present for this delegation then include the NSEC record with the corresponding RRSIG(NSEC) in the authority section. else we are in an opt-in part of the zone and we should include the NSEC RR of the last secured RR in the zone and the corresponding RRSIG(NSEC) into the authority section of the answer. fi fi Put whatever addresses are available into the additional section, using glue RRs if the addresses are not available from authoritative data. If the DO bit was set then also copy the RRSIGs for the addresses for which the server is authoritative. Go to step 4. c. If at some label, a match is impossible (i.e., the corresponding label does not exist), look to see whether the last label matched has a DNAME record. BEGIN DNAME (supported as of NSD 3.0) If a DNAME record exists at that point, copy that record into the answer section, if the DO bit is set also copy the RRSIG. If substitution of its for its in QNAME would overflow the legal size for a , set RCODE to YXDOMAIN [DNSUPD] and exit; otherwise perform the substitution and continue. If the query was not extended [EDNS0] with a Version indicating understanding of the DNAME record, the server SHOULD synthesize a CNAME record as described above and include it in the answer section. Go back to step 1. Note that there should be no descendants of a DNAME in the same zone (rfc2672 3). So if a DNAME has been found only go to step 1 if another zone can be found. NSD will refuse to zonecompile a zone that has descendants of a DNAME. It always synthesizes CNAME records. END DNAME If there was no DNAME record, look to see if the "*" label exists. If the "*" label does not exist, check whether the name we are looking for is the original QNAME in the query or a name we have followed due to a CNAME. If the name is original, set an authoritative name error (RCODE=3 NXDOMAIN) in the response, if the DO bit was set then include the appropriate NSEC records (see section 4.5.) in the authority section, then exit. If the "*" label does exist, match RRs at that node against QTYPE. If any match, copy them into the answer section, but set the owner of the RR to be QNAME, and not the node with the "*" label. If the DO bit is set copy the RRSIG for the * label and matching QTYPE also set the owner of the RRSIG RR to be QNAME). In addition a NSEC record indicating that no specific matches are possible should be returned in the additional section. Otherwise just exit. Go to step 4. 3. If a there was no delegation of authoritative data return the root delegation in the authority section and continue with 4. Also see Appendix B.1 4. Using local data only, attempt to add other RRs which may be useful to the additional section of the query if the DO bit was set in the query then for retrieval of SOA or NS a DNSKEY of the same name should be added. For retrieval of type A, AAAA or A6 RRs the DNSKEY should also be included. See section 4.2 as well. Note that on a QNAME match the NS records are not copied into the AUTH section (This is a requirement from step 4 'matching down the cache' from rfc1034 4.3.2). This is a requirement only for caching servers. BIND8 will copy the NS in the Auth section for authoritative server too. C 4.2 Additional Data processing. Additional data is added as long as there is space in the packet. When processing the additional section priority is (rfc 2535 3.5 and rfc 2874 4) + A + A6 + AAAA + DNSKEY For truncation see section C.4.4 If the DO bit is set RRSIGs will be included with the additional data. Although not specified in the RFCs we will assume the following priority: Note that A glue is always added before any AAAA glue. + A + RRSIG A + A6 + RRSIG A6 + AAAA + RRSIG AAAA + DNSKEY + RRSIG DNSKEY NSD will act as being authoritative for one zone without having the other zones in cache. In other words: If a NSD is authoritative for say both ripe.net and nlnetlabs.nl and both these zones are secondary for each others NS. Then, at least with my zone parser a query for ripe.net NS would return ANSWER: ripe.net NS ns.ripe.net NS ns.nlnetlabs.nl Additional ns.ripe.net A 10.0.0.1 and not ANSWER: ripe.net NS ns.ripe.net NS ns.nlnetlabs.nl Additional ns.ripe.net A 10.1.0.1 ns.nlnetlabs.nl A 10.2.0.2 This behavior is a consequence of NSD using precompiled packets. These are 'constructed' zone by zone. It is an optimisation of speed versus network optimisation. In NSD2 and later this behaviour still exists, even though the packets are constructed at run time, only information from the current zone is added to a response. C 4.3 Label compression in RDATA In the spirit of RFC 1035 section 3.3. and 4.4.1 ("Pointers can only be used for occurrences of a domain name where the format is not class specific.") we only do label compression for labels in rdata for which this is specifically mentioned in the RFC defining the RR. -NS, SOA, CNAME, and PTR (rfc 1035 3.3) Others defined in (rfc 1035 3.3) are not compressed. BIND8 does compression for all RR from rfc 1035 for which dnames appear in the rdata. (Note that other RFCs do refer to e.g. MX dname in rdata being compressed (e.g. rfc2974 4.). -MB, MG, MR, MINFO, MX also have compressed dnames. These RRs and their compression are described in RFC 883. -NSEC, RRSIG and DNSKEY MUST NOT have dname compression (rfc 4034). For RRs not mentioned here no label compression in the rdata is performed. C 4.4 Truncation handling. (as rfc2181 9) If inclusion of a RR set that is REQUIRED in either the answer or authority section leads to message truncation. The section is left empty and the truncation (TC) bit is set. If the DO bit is set RRSIG RRs are required in the answer and authority section. Inclusion of NS RRs in the authority section when QTYPE=DNSKEY is removed since NSD version 3.2.3. QTYPE=DS followed in version 3.2.7. This is to prevent resolvers from unnecessarily falling back to TCP. Only DNSKEY and DS records are considered, because it showed that especially these DNS packets are 'troublesome'. The feature 'minimize responses' is included since NSD 3.2.9. NS RRsets that would go into the Authority section in positive responses are not considered REQUIRED and therefore will NOT lead to setting of the TC bit. The minimal response size is: - 512 in case of no EDNS; - 1460 in case of EDNS/IPv4; - 1220 in case of EDNS/IPv6; - the advertized buffer size if that value is smaller than the the EDNS defaults. The feature can be disabled during build time with --disable-minimal-responses. If inclusion of an RRset in the Additional section is not possible RRs are omitted one by one. This may lead to incomplete RRsets. Omission of RRs from the Additional section because of message size constraints will NOT lead to setting of the TC bit. (rfc2181 9) We allow for incomplete RRsets in the additional section. C 4.5 NSEC processing. The NSEC record is required to be in the authority section if a QNAME or a QTYPE cannot be matched (see section 5 or RFC2535). If the DO bit on the query is not set then NSEC records should only be required if QNAME and QTYPE match. If the do bit on the query is set then we have to do NSEC processing if a zone is marked as secure otherwise we should do nothing. If the QNAME matches a name in the zone but the QTYPE does not match then the answer section should remain empty and the Authority section should have either the NSEC RR that matches QNAME or the NSEC RR (opt-in) that indicates QNAME is in an insecure part of the zone. C 4.6 Timeout management. NSD manages timeouts on the SOAs for secondary zones according to RFC. Timeouts are randomized, to avoid network bursts. The randomization used is 90-100% of the original value - meaning that it can never be delayed. This means zones cannot expire later than they should. It does mean the average timeout becomes 95% of the original. The random number calculation is primitive but fast. It is about spreading load not about randomness per se (in the crypto sense). ------------------------------------------------------------------------------- Appendix A IANA list of RR records RR records details. "A" 1, # RFC 1035, Section 3.4.1 No additional processing "NS" 2, # RFC 1035, Section 3.3.11 Additional A type processing. dname compression in RDATA "MD" 3, # RFC 1035, Section 3.3.4 (obsolete) "MF" 4, # RFC 1035, Section 3.3.5 (obsolete) "CNAME" 5, # RFC 1035, Section 3.3.1 No additional section processing. dname compression in RDATA "SOA" 6, # RFC 1035, Section 3.3.13 No additional section processing. SOA TTL semantics updated by rfc2308 dname compression in RDATA "MB" 7, # RFC 1035, Section 3.3.3 Additional processing type A of MADNAME "MG" 8, # RFC 1035, Section 3.3.6 No additional section processing. "MR" 9, # RFC 1035, Section 3.3.8 No additional section processing. "NULL" 10, # RFC 1035, Section 3.3.10 NOT IMPLEMENTED Not allowed in master files. (Not implemented in BIND) "WKS" 11, # RFC 1035, Section 3.4.2 (deprecated in favor of MX [RFC-1123] but not Obsolete) "PTR" 12, # RFC 1035, Section 3.3.12 No additional section processing. dname compression in RDATA "HINFO" 13, # RFC 1035, Section 3.3.2 No additional section processing. "MINFO" 14, # RFC 1035, Section 3.3.7 No additional section processing. "MX" 15, # RFC 1035, Section 3.3.9 Additional section processing type A of host in Exchange "TXT" 16, # RFC 1035, Section 3.3.14 No additional section processing. "RP" 17, # RFC 1183, Section 2.2 No additional section processing. "AFSDB" 18, # RFC 1183, Section 1 type A additional section processing for dname compression for hostname "X25" 19, # RFC 1183, Section 3.1 No additional section processing. "ISDN" 20, # RFC 1183, Section 3.2 No additional section processing. "RT" 21, # RFC 1183, Section 3.3 type X25, ISDN, and A additional section processing for . dname compression for intermediate-host. "NSAP" 22, # RFC 1706, Section 5 No additional section processing. NSAP requires special parsing rules. "NSAP_PTR" 23, # RFC 1348 (obsolete) "SIG" 24, # RFC 2535, Section 4.1.7: signers name field MAY be compressed. 4.1.8.1: SIG(0) specification. See section 4.2 for additional section processing. SIG signers name field MAY be compressed. (2535 4.1.7) "KEY" 25, # RFC 2535, Section See section RFC 2535 3.5 on inclusion of keys. "PX" 26, # RFC 2163, section 4 says: PX records cause no additional section processing All normal DNS conventions, like default values, wildcards, abbreviations and message compression, apply also for all the components of the PX RR. Compression is not explicitly mentioned: This label is CLASS specific: NO compression. "GPOS" 27, # RFC 1712 (obsolete) "AAAA" 28, # RFC 1886, Section 2.1 "LOC" 29, # RFC 1876 No requirements on additional section processing. "NXT" 30, # RFC 2535 No requirements on additional section processing. NXT dname field MAY be compressed. (2535 4.2) "EID" 31, # draft-ietf-nimrod-dns-xx.txt e.g. http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt "NIMLOC" 32, # draft-ietf-nimrod-dns-xx.txt e.g. http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt "SRV" 33, # RFC 2782 No dname compression of target field. (rfc2782 page 4) "ATMA" 34, # [Dobrowski] "NAPTR" 35, # RFC 2168, 2915 Contains regular expressions. Take care of escaping backslashes while parsing (rfc2915 p6): 'Replacement' field: no compression "KX" 36, # RFC 2230 KX records MUST cause type A additional section processing for the host specified by EXCHANGER. In the event that the host processing the DNS transaction supports IPv6, KX records MUST also cause type AAAA additional section processing. The KX RDATA field MUST NOT be compressed. (rfc2230 section 3) "CERT" 37, # RFC 2538 No dnames in rdata "A6" 38, # RFC 2874 No dnames in rdata "DNAME" 39, # RFC 2672 NO dname compression of target field. (rfc2672 sect 3) "SINK" 40, # [Eastlake] "OPT" 41, # RFC 2671 Pseudo RR. Not in zone files. "APL" 42 # RFC 3123 An APL RR with empty RDATA is valid and implements an empty list. "DS" 43, # RFC 4033, 4034, 4035. Included with referrals. "SSHFP" 44, # SSH Key Fingerprint, RFC 4255 "IPSECKEY" 45, # RFC 4025 Public key RSA/DSA for use in IPSEC. "RRSIG" 46, # RFC 4033, 4034, 4035. RFC 3755. Signature, uncompressed dnames. "NSEC" 47, # RFC 4033, 4034, 4035. RFC 3755. Signed next ownername, to disprove rrset types and domain name existence. Uncompressed dnames. "DNSKEY" 48, # RFC 4033, 4034, 4035. RFC 3755. Key for zone signing or key signing. Public key part. "DHCID" 49, # draft-ietf-dnsext-dhcid-rr-13.txt "NSEC3" 50, # RFC 5155. "NSEC3PARAM" 51, # RFC 5155. "TLSA" 52, # RFC 6698. Unknown 53 - 98, "SPF" 99, # RFC 4408 (Experimental). "UINFO" 100, # [IANA-Reserved] "UID" 101, # [IANA-Reserved] "GID" 102, # [IANA-Reserved] "UNSPEC" 103, # [IANA-Reserved] "NID" 104, # RFC 6742 "L32" 105, # RFC 6742 "L64" 106, # RFC 6742 "LP" 107, # RFC 6742 "EUI48" 108, # RFC 7043 "EUI64" 109, # RFC 7043 "TKEY" 249, # RFC 2930 "TSIG" 250, # RFC 2845 "IXFR" 251, # RFC 1995 "AXFR" 252, # RFC 1035 "MAILB" 253, # RFC 1035 (MB, MG, MR) "MAILA" 254, # RFC 1035 (obsolete - see MX) "ANY" 255, # RFC 1035 "URI" 256, # RFC 7553 "CAA" 257, # RFC 6844 ______________________________________________________________________ Appendix B Details on specific design and implementation choices. B.1. Returning the root delegation when no answer can be found From RFC1034/1035 it is not obvious if returning a root delegation is a (non-)requirement for authoritative servers. We have decided not to implement a root-hints since an authoritative server should in normal circumstances only receive queries for which the server is authoritative. Also see RFC 1123 section 6.1.2.5. Whenever an answer cannot been provided we return a SERVFAIL. It has been argued that this is a policy decision and thus a REFUSE should be returned. However, in the spirit of RFC1034/1035 a server should return cached data, if that cache cannot be reached a SERVFAIL is an appropriate response. Also see the discussion on the 'namedroppers list' Starting April 2002 with subject "name server without root cache " (ftp://ops.ietf.org/pub/lists/) ______________________________________________________________________ Appendix C (Planned) Features NSD Version 1.0.0. and above The first release ( 1.0.0 ) contains an implementation of the standard RFC 1034 and RFC 1035, of proposed standards RFC2181 (clarifications), RFC2308 (negative caching). AXFR is not implemented in v1.0.0. The RRs specified in the following RFCs are implemented in v1.0.0 - RFC 1183 (Multiple RRs) - RFC 1706 (NSAP) (Informational) - RFC 1876 (LOC RR) - RFC 1886 (AAAA RR) - RFC 2230 (KX RR) (Informational) - RFC 2536 (CERT RR) - RFC 2671 (EDNS0) - RFC 2782 (SRV) - RFC 2915 (NAPTR RR) - RFC 2915 (SRV RR) - Version 1.0.1 will also support features from draft-ietf-dnsop-serverid-00.txt: The following names have associated TXT RRs in the CHAOS class: ID.SERVER. and VERSION.SERVER. - RFC2535 (DNSSEC) will be implemented in (1.1.0) once the current drafts DS and OPT-IN have made it to the standards track. (DNSSEC also includes RFC2536 (DSA), RFC2537 (RSA), RFC3225 (DO bit) Version 1.1.0 will not allow wildcards in DNSEC signed zones. NSD Version 2.0. and above - AXFR will be implemented in 1.0.1 with simple IP based ACLs. In 1.1.0. AXFR will also supported with RFC 2845 (TSIG) Using external tool nsd-xfer, that supports TSIG to download a zone from a server. - DNSSEC supported RRSIG/NSEC/DNSKEY, RFC 4033, 4034, 4035. - wildcards allowed in dnssec secured zones. - RFC 2673 (Binary labels) - RFC 2874 (A6) NSD Version 3.0. and above AXFR: - NSD serves AXFR, with TSIG if needed. - NSD requests AXFR from xfrd. This is noncompliant with RFC. It does not ask for the SOA serial number using a query beforehand (nsd-xfer does). It terminates the AXFR after the first packet if it determines the AXFR is not needed. RFC 1995 (IXFR) support only for making requests to other servers. - IXFR is not served. RFC 1996 (NOTIFY): - will ignore extraneous data in notify (instead of checking if they differ from content in zone). Only checks SOA serial. This is too hard, since other information is not available in xfrd, the process that handles the notify. - Will not send notify to NS-servers of a zone. Only notify sent to 'notify:' entries in config file. - Incoming has an ip-based and key-based access control list. - can be with TSIG. RFC 2845 (TSIG): - TSIG is supported for notify, axfr, ixfr, regular queries. RFC 2672 (DNAME) support. Secondary zones: - follows SOA timers. (NSD 2 and before did not) (RFC 1034, 1035). RFC 4509 (SHA-256 DS) support. RFC 4635 (HMAC SHA TSIG) support for mandatory algorithms: hmac-md5, hmac-sha1, hmac-sha256. RFC 5001 (NSID) support. RFC 5155 (NSEC3) support. RFC 5702 (SHA-2) support. RFC 5936 (AXFR) support. RFC 6605 (ECDSA) support. RFC 6698 (DANE) support for TLSA RR type. RFC 6742 (ILNP) support for NID, L32, L64, LP RR types. RFC 6844 (CAA) support for CAA RR type. RFC 7043 (EUI48+64) support for EUI48, EUI64 RR types. RFC 7553 support for URI RR type. Not implemented: RFC2136 (Dynamic update) are not implemented and will not be implemented as zone control is not implemented in NSD itself. Appendix D. Changes to this file. 14 january 2014 (Matthijs Mekking) - Updated file with CAA RRtype support. 18 june 2013 (Matthijs Mekking). - Updated file with EUI48 and EUI64 RRtype support. 25 april 2013 (Matthijs Mekking). - Removed requirements label compression for RP, RT and AFSDB. 19 november 2012 (Matthijs Mekking). - Updated file with RFC 6698 (DANE) support for TLSA RR type and RFC 6742 (ILNP) support for NID, L32, L64, LP RR types. 17 april 2012 (Matthijs Mekking). - Updated file with RFC 5936 (AXFR) and RFC 6605 (ECDSA) support. 17 october 2011 (Matthijs Mekking). - Updated file with RFC 5702 (SHA-2) and RFC 4509 (SHA-256 DS) support. 17 october 2011 (Matthijs Mekking). - Added section on minimal responses. 24 february 2010 (Matthijs Mekking). - Updated file with RFC 5001 (NSID) and RFC 5155 (NSEC3) support (version 3.0.0 and above). 30 october 2008 (Matthijs Mekking). - Added support for RFC 4635 (HMAC SHA TSIG). 26 july 2006 (Wouter Wijngaards). - Comments changed to background items. - KEY->DNSKEY, SIG->RRSIG in the text, dnssec-bis style. ______________________________________________________________________ $Id$ nsd-4.12.0/doc/RELNOTES0000644000175000017500000032641015002373054013726 0ustar mozziemozzieNSD RELEASE NOTES 4.12.0 ================ FEATURES: - Merge #418: Support for DSYNC, EID, NIMLOC, SINK, TALINK, DOA, AMTRELAY and IPN resource record types. - Merge #420: Zones get state "old-serial" with `nsd-control zonestatus` when the served serial is older than the one received by the transfer daemon. - Merge #429: Add prometheus metrics BUG FIXES: - Fix re-enable to configure dns-cookies from config file, which was accidentally removed with the 4.11.1 release. - Fix #426: nsd crashes with patterns in config_apply_pattern. - Fix for #430: Confusing documentation: word "outgoing". - Fix for #430: Confusing documentation: word "outgoing". Add wording to tcp-count, xfrd-tcp-max, xfrd-tcp-pipeline options. - Fix that nsec3 prehash after a full transfer can create the nsec3 zone trees if they are needed. - Fix in nsd-mem for a zone with ixfr data. - Fix ixfr read routine for use after the temp region is freed of rr. - Fix ixfr file read to manage numlist in temp domains. - Fix nsd-mem to clean ixfr storage. - Fix log print assert in server sockets for printing '-' empty. - Fix notify_fmt test for xfrd file location. - Fix sanitizer warnings in read_uint32. - Fix sanitizer warning in tsig write of zero length mac and otherdata. - Fix to please sanitizer for ixfr store of data in cancelled state. - Fix multiple zone transfers in one reload so that xfrd does not check the update as failed and restart the transfer. - Fix read of ixfr file with rdata subdomain. - Fix test checkconf for metrics options. - Updated simdzone to include fixes for NSAP-PTR, LOC, uninitialized reads, and comment nit. - Fix #436: Fix print of RR type NSAP-PTR. - Fix unit test call to zone_parse_string and initialize padding. - Fix escape more characters when printing an RR type with an unquoted string. - Fix memory leak in the process of addzone. - Fix to update common.sh for speed of kill_pid. - Fix nsd-checkzone ixfr create cleanup on exit. 4.11.1 ================ BUG FIXES: - Fix #415: Fix out of tree builds. Thanks Florian Obser (@fobser). - Fix #414: XoT interoperability with BIND and Knot - Fix #421: old-main can quit before the reload process received from old-main that it is done on the reload_listener pipe. Thanks Otto Retter. - Fix whitespace in comment. - Fix #424: Stalled updates after corrupt transfer. 4.11.0 ================ FEATURES: - Support reloading configuration on SIGHUP. - Fix #383: log timestamps in ISO8601 format with timezone. This adds the option `log-time-iso: yes` that logs in ISO8601 format. - Updated cookie secrets management. The default cookie secret file location can be set at compile time with the --with-cookiesecretsfile=path option to configure. The default location is changed to {dbdir}/cookiesecrets.txt. The previous default location will be checked at startup when there is no cookie secrets file at the new default location. A staging cookie can now also be configured in the configuration file and secrets configured in the configuration file now take precedence over those read from file. All DNS related setting in the configuration file will be reevaluated and effectuated after nsd-control reconfig. - Merge #398: RFC 9660 The DNS Zone Version (ZONEVERSION) Option - Merge #406: ohttp and tls-supported-groups SvcParam suppor - Merge #408: NINFO, RKEY, RESINFO, WALLET, CLA and TA RR types - Merge #409: Writing of NSAP-PTR, GPOS and HIP RR types - Merge #407: Better balanced verbosity levels for logging. BUG FIXES: - Fix title underline and declaration after statement warnings. - Add cross platform freebsd, openbsd and netbsd to github ci. - Update simdzone to include fix for netbsd double bswap declarations, and also semantic checks for DS and ZONEMD. And CFLAGS has -march prepended to fix detection. - Merge #376: Point the user towards tcpdump for logging individual queries. - Track $INCLUDEs in zone files. - Fix ci to update macos-12 to the macos-15 runner image. - Merge #390: Apply non-xfr tasks before xfr tasks. This fixes an issue where non-xfr tasks are lost when they are batch processed together with non-xfr tasks. This merge also changes that notifies are passed on from the serve processes to the xfrd directly instead of via main. This was necessary to allow applying the non-xfr tasks without forking a backup-main for the sole purpose of forwarding notifies. - Merge #391: Update copyright lines (in version output). - Fix #392: Inconsistent documentation about control-interface. - Merge #395: Explain the zonefile example better. - Merge #394: Fix the path to use doc/manual/. - Fix analyzer issue in do_print_cookie_secrets to check for failure. - Merge #404: Introducing Sphinx substitution in code blocks. As well as other fixes with Sphinx build. - Update Copyright lines in help output - Merge #395: Explain zonefile example better - Merge #394: Fix doc path (fixes "Edit on GitHub" button in the docs) - Fix Makefile for parallel build failure around bison rule. - Fix #405: Fix typo in documentation. - Treat a mismatch in RRset TTLs as a warning. 4.10.1 ================ FEATURES: - Merge #352 from orlitzky: contrib: add OpenRC service script, config file, and tmpfiles entry. - Merge #337 from bilias: Mutual TLS-AUTH. BUG FIXES: - Fix incorrect punctuation of log messages. - Fix for #317, document more text on pidfile permissions. - Fix #334: RFC8482 behavior documentation. - Fix for OpenSSL 3.0 deprecated functions. - Merge #341: Fix allow-query wording in nsd.conf.5.in. - Fix test script from making spurious output. - Fix cpu_affinity and socket_partitioning tests for --enable-log-role. - Fix #344: Update simdzone. - Fix #347: Adjust verbosity for TLS (+TCP) to be 5. - Merge #348: Move TLS logging to verbosity level 5. - For #347: Also adjust verbosity of log message for remaining TCP connections. - Merge #349: log file name before loading. - Use MAKE variable rather than make command directly in Makefile. - Serialize WKS RRs using numeric values rather than names. - Fix propagation of Makefile targets to simdzone. - Do not log ACL mismatch on followed CNAMEs. - Fix link of xfr-inspect for libssl dependency. - Initialize tls_auth_port and tls_auth_xfr_only options. - Merge #358: Fix Hurd build error due to log_err. - Update simdzone to fix detection of AVX2 support. 4.10.0 ================ FEATURES: - Merge #278: Replace Flex+Bison based zone parser with simdzone. Performance of loading zones and IXFRs is greatly improved by using the simdzone project by NLnet Labs. The optimized presentation format parser leverages SIMD instructions in modern CPUs to improve throughput. Right now SSE4.2 and AVX2 instruction sets are supported, other instruction sets will use the fallback implementation, which still is a decent improvement over the Flex+Bison based parser. BUG FIXES: - Fix that when the server truncates the pidfile, it does not follow symbolic links. - Fix #317: nsd should not chown its PID file. - For #317: Modify nsd service script to stop NSD from creating a pid file that systemd is not using. - Fix #324: Clarify the purpose of contrib/bug390.patch. - Fix IXFR requests upstream for zones with a long name. Thanks for the report to Yuuki Wakisaka from Internet Initiative Japan Inc. - Unit test for dname subdomain test used by xfrd-tcp.c. - Fix #329: TCP accept queues number. - Fix that the reload handler for sigchild uses signal_add, and also that the signal handler is restored when done. - Fix that when server verify is done it resets the sigchild handler. - Fix makedist.sh for simdzone inclusion. - Fix makedist.sh to remove simdzone git tracking information and scripting temporaries from tarball. - Fix error output of makedist.sh. - Use simdzone version with name parser fix. - Bump simdzone version to fix OpenBSD build issues. - Bump simdzone to include minor fixes. 4.9.1 ================ BUG FIXES: - Use rooted temporary path in makedist.sh. 4.9.0 ================ FEATURES: - Merge #315: Allow SOA apex queries to otherwise with allow-query protected zones for clients matching a provide-xfr rule, because clients that are allowed to transfer the zone need to be able to query SOA at the apex preceding the actual transfer. - Merge #304: Support for Catalog zones version "2" as specified in RFC 9432. Both the consumer as well as the producer role are implemented, but only a single catalog consumer zone is allowed. The "coo" property, only relevant with multiple catalog consumer, is therefore not supported. The "group" property is supported. Have a look at the nsd.conf man page for details on how to configure and use catalog zones. BUG FIXES: - Fix to sync the tests script file common.sh. - Update test script file common.sh. - Fix #306: Missing AC_SUBST(dbdir) breaks installation with 4.8.0. - Fix for #306: Create directory for xfrd.state and zone.list files in make install. - Merge #307 from anandb-ripencc: Many improvements to the nsd.conf man page. - Fix #308: Deprecate "multi-master-check" in favour of "multi-primary-check". - Merge #309: More RFC 8499 compliance. - Fix control-reconfig-xfrd test for zonestatus primary that is printed by nsd-control zonestatus. - Move acx_nlnetlabs.m4 to version 47, with crypt32 check. - Move acx_nlnetlabs.m4 to version 48, with ssp and getaddrinfo include check. - Fix #313: nsd 4.8 stats with implausible spikes. - Fix compile with memclean for xfrd nsd.db close. - In xfrd del secondary zone, the timer could perhaps have event_added, and if so, it would not be event_del if a tcp connection is active at the time. This could cause the libevent event lists to fail. Also fix to make sure to set event_added for the nsd-control ssl nonblocking handshake and check event_added there too, for extra certainty. - Merge #316: Fix to reap defunct children by the reload process that emerged when some serve child processes were still serving TCP request while the others had already quit, while the reload process was waiting for the signal from the backup/old main process that all children exited. - Fix (also from Merge #316) to reap exited children more frequently from server main loop for processes that exited during reload, but missed the initial reaping at start of the main loop because they took somewhat longer to exit. - Fix timing sensitivity in ixfr_outsync test. - Test if debug is available in do-tests. - Enforce timeout from NSD in ixfr_gone test. - Update expressions in ixfr_and_restart test. - Make algorithm explicit in control-repattern test. - Switch algorithm to hmac-256 for testplan_mess test. - Replace multiple strcat and strcpy by snprintf. 4.8.0 ================ FEATURES: - Merge #281: Proxy protocol. An implementation of PROXYv2 for NSD. It can be configured with proxy-protocol-port: portnum with the port number of the interface on which proxy traffic is handled. The interface can support proxy traffic for UDP, TCP and TLS. - Merge #301: improve the logging of ixfr fallbacks to axfr. - Merge #305: faster stats. Statistics can be gathered while a reload is in progress. BUG FIXES: - Merge #282: Improve nsd.conf man page. - Fix unused but set variable warning. - Fix #283: Compile failure in remote.c when --disable-bind8-stats and --without-ssl are specified. - Fix #284: dnstap_collector.c: SOCK_NONBLOCK is not available on Mac/Darwin. - Fix unused variable warning in unit test of udb. - Merge #287: Update nsd.conf.5.in. - Fix autoconf 2.69 warnings in configure. - Merge #295: Update e-mail addresses, add ref to support contracts - Fix for interprocess communication to set quit sync command from main process explicitly. - Fix processing of consolidated IXFRs. - Remove on-disk database. - Answer first query for connections accepted just before reload. - Fix: Always instate write handler after reading a query over TCP. - Fix #14: Set timeout to 3s when servicing remaining TCP connections. - Merge #302: Test package fixes. Correct Auxfiles, kill_from_pidfile function and fix drop_updates, rr-test and xfr_update tests. - Fix unit test kill_from_pidfile function for nonexistent files because the argument is evaluated before the test expression. - Fix rr-test to also convert the contents of the just written output file. - Fix test set to remove -f nsd.db and rm nsd.db commands. - Fix test set to remove difffile option. 4.7.0 ================ FEATURES: - Merge #263: Add bash autocompletion script for nsd-control. - Fix #267: Allow unencrypted local operation of nsd-control. - Merge #269 from Fale: Add systemd service unit. - Fix #271: DNSTAP over TCP, with dnstap-ip: "127.0.0.1@3333". - dnstap over TLS, default enabled. Configured with the options dnstap-tls, dnstap-tls-server-name, dnstap-tls-cert-bundle, dnstap-tls-client-key-file and dnstap-tls-client-cert-file. BUG FIXES: - Fix #239: -Wincompatible-pointer-types warning in remote.c. - Fix configure for -Wstrict-prototypes. - Fix #262: Zone(s) not synchronizing properly via TLS. - Fix for #262: More error logging for SSL read failures for zone transfers. - Merge #265: Fix C99 compatibility issue. - Fix #266: Fix build with --without-ssl. - Fix for #267: neater variable definitions. - Fix #270: reserved identifier violation. - Fix to clean more memory on exit of dnstap collector. - Fix dnstap to not check socket path when using IP address. - Fix to compile without ssl with dnstap-tls code. - Dnstap tls code fixes. - Fix include brackets for ssl.h include statements, instead of quotes. - Fix static analyzer warning about nsd_event_method initialization. - Fix #273: Large TXT record breaks AXFR. - Fix ixfr create from adding too many record types. - Fix cirrus script for submit to coverity scan to libtoolize the configure script components config.guess and config.sub. - Fix readme status badge links. - make depend. - Fix for build to run flex and bison before compiling code that needs the headers. - Fix to remove unused whitespace from acx_nlnetlabs.m4 and config.h. - For #279: Note that autoreconf -fi creates the configure script and also the needed auxiliary files, for autoconf 2.69 and 2.71. - Fix unused variable warning in unit test, from clang compile. - Fix #240: Prefix messages originating from verifier. - Fix #275: Drop unnecessary root server checks. 4.6.1 ================ FEATURES: - Set ALPN "dot" token during connection establishment as per RFC9103 section 7.1 (Thanks Cesar Kuroiwa). - Add SVCB dohpath support BUG FIXES: - Fix static analyzer reports, fix wrong log print when skipping xfr, fix to print error on pipe read fail, and assert an xfr is in progress during packet checks. - Use AC_PROG_CC_STDC with autoconf versions prior to 2.70. - Add missing documentation for zone verification. - Fix #212: Change commandline control actions to always log. - Merge #231 from moritzbuhl: Fix checking if nonblocking sockets work on OpenBSD. - Change zone parsing to accept non-trailing newline. 4.6.0 ================ FEATURES: - Port zone-verification from CreDNS to NSD4. BUG FIXES: - Fix static analyzer reports on ixfrcreate temp file. - Fixup wrong ixfrcreate fread return check. 4.5.0 ================ FEATURES: - Merge PR #209: IXFR out This adds IXFR out functionality to NSD. NSD can copy IXFRs from upstream to downstream clients, or create IXFRs from zonefiles. The options store-ixfr: yes and create-ixfr: yes can be used to turn this on. Default is turned off. The options ixfr-number and ixfr-size can be used to tune the number of IXFR transfers and total data size stored. This is configured per zone, the IXFRs are served to the hosts that are allowed to perform zone transfers. And if TSIG is configured, signed with the same key. The content is stored to file if a zonefile is configured for the zone, in the zonefile.ixfr and zonefile.ixfr.2, .. files. They contain readable text format. The number of IXFRs is num.rixfr in statistics output, also per zone if per zone statistics are enabled. If offline, nsd-checkzone -i can create ixfr files. NSD already supports requesting IXFRs, this addition allows NSD to serve IXFR transfers to clients. NSD stops responding with NOTIMPL to IXFR requests, also for zones that do not have IXFR enabled. The clients gets a full zone reply or a status reply if the serial is up to date. BUG FIXES: - Fix code analyzer zero divide warning. - Fix code analyzer large value with assertion. - Fix another code analyzer zero divide warning. - Fix code analyzer warning about uninitialized temp storage in loop. - Fix spelling error in comment in svcbparam_lookup_key. - Update cirrus script FreeBSD version. 4.4.0 ================ FEATURES: - Merge #193: Lower memory usage of the XFRD process by default. Instead of preallocating all elements, they are allocated when used. There are options for managing the memory usage, defaults are the same as before. xfrd-tcp-max sets the number of sockets for tcp connections that xfrd can make to download zone contents. And xfrd-tcp-pipeline the number of simultaneous transfers over the same connection. BUG FIXES: - Fix #200: nsd-checkzone succeeds even with incorrect serial in SOA record. - Merge #204 from jonathangray: correct some spelling mistakes. - Fix to change file mode before changing file owner for the nsd-control unix socket file. - Fix to document nsd-checkzone -p in the man page for nsd-checkzone. - Fix #206: build with --without-ssl fails. - Merge #207 Sync nsd-control-setup with unbound-control-setup to generate certificates with SANs. - Fix unit tests for nds-control-setup exit code and the xfrd-tcp-max default. 4.3.9 ================ BUG FIXES: - Fix #198: nsd-control reconfig core dump. - Fix to remove git tracking and ci information from release tarballs. - Fix unit tests for new answer-cookie default. - Fix socket_partitioning unit test for FreeBSD. - Fix SVCB test to work around older dig with drill. 4.3.8 ================ FEATURES: - Merge #185 by cesarkuroiwa: Mutual TLS. - Set default for answer-cookie to no. Because in server deployments with mixed server software, a default of yes causes issues. BUG FIXES: - Fix to compile with OpenSSL 3.0.0beta2. - Fix configure detection of SSL_CTX_set_security_level. - Fix deprecated functions use from openssl 3.0.0beta2. - For #184: Note that all zones can be targeted by some nsd-control commands in the man page. - Fixes for #185: Document client-cert, client-key and client-key-pw in the man page. Fix yacc semicolon. Fix unused variable warning. Use strlcpy instead of strncpy. Fix spelling error in error printout. - Merge #187: Support using system-wide crypto policies. - Fix #188: NSD fails to build against openssl 1.1 on CentOS 7. - Fix sed script in ssldir split handling. - Fix #189: nsd 4.3.7 crash answer_delegation: Assertion `query->delegation_rrset' failed. - Fix #190: NSD returns 3 NSEC3 records for NODATA response. - Fix compile failure with openssl 1.0.2. - Fix #194: Incorrect NSEC3 response for SOA query below delegation point. 4.3.7 ================ FEATURES: - Syntax of SVCB and HTTPS RR type as per draft-ietf-dnsop-svcb-https - Client side DNS Zone Transfer-over-TLS (XoT) support as per draft-ietf-dprive-xfr-over-tls - Interoperable DNS Cookies support as per RFC7873 and RFC9018 BUG FIXES: - Fix for #170: Fix build warnings when IPv6 is disabled. - Fix #170: Disabled IPv6 and DNSTAP enabled triggers a build error. - Fix for #128: Skip over sendmmsg invalid argument when port is zero. - Fix #171: Invalid negative response (NSEC3) after IXFR. - Fix to make nsec3_chain_find_prev return NULL if one nsec3 left. - Fix #174: NS Records below delegation are not ignored (nsd-checkzone also does not raise any issue). - Fix #176: please review Loglevel on missing zonefile. - Update the ACX_CHECK_NONBLOCKING_BROKEN test for the configure script. - Fix #179: log notice and server-count. - Update configure nonblocking test to use host. - Fix #168: Buffer overflow in the dname_to_string() function - Fixes for child server processes getting out of sync with the dnstap-collector process - Fix gcc-11 warning on array bounds. - Fix compile of cookies on FreeBSD without IPv6. - Fix for loop initial declaration for nonc99 compiler - Fix typo in xfrd-tcp.c. 4.3.6 ================ FEATURES: - Fix #146 with #147: DNSTAP log the local address of the server with the dnstap logs. - Enable configuring a control-interface by interface name. - A -p option to nsd-checkzone to print a successfully read zone. - Add Extended DNS Errors RFC8914 - Per zone Access Control List for queries with an allow-query: option. BUG FIXES: - Prevent a few more yacc clashes. - Merge PR #153 from fobser: Repair -fno-common linker errors automatically. - Fix uninitialized access of log_buf in error printout on apply ixfr. - Fix AF_LOCAL compile error for Solaris. - Fix ifaddrs compile error for Solaris. - Fix ifaddrs.h compile error for Solaris. - Man page documentation for dnstap options. - Fix segfault on high verbosity for TLS channels with dnstap log local address. - Fix #163: A TSIG noncompliance with RFC 2845. - Fix that wildcard is printed as a star instead of escaped, in logs and in written zone files. - Fix double config.h include in configlexer.c - Fix to remove configyyrename from makedist.sh and also update the flex and bison rules there to add the "c_" prefix. - Fix configure to use header checks with compile. - Fix warning about unused function log_addr. - Fix #154: TXT with parentheses fails in 4.3.5. - Align parsing of TXT elements with how bind does it. - Fix configure failure for enable systemd because of autoconf. 4.3.5 ================ BUG FIXES: - Fix #143: xfrd no hysteresis with NOT IMPLEMENTED rcode. - Fix #144: Typo fix in nsd.conf.5.in. - For #145: Fix that service of remaining TCP and TLS connections does not allow new queries to be made, the connection is closed. Only existing queries and zone transfers are answered, new ones are rejected by a close of the channel. - Fix that nsd-control has timeout when connection is down. - remove windows socket ifdefs from nsd-control. - Fix #148: CNAME need not be followed after a synthesized CNAME for a CNAME query. - Fix configure.ac for autoconf 2.70. - Fix #150: TXT record validation difference with BIND. - Fix #151: DNAME not applied more than once to resolve the query. - Fix #152: '*' in Rdata causes the return code to be NOERROR instead of NX. 4.3.4 ================ FEATURES: - Merge PR #141: ZONEMD RR type. BUG FIXES: - Fix #129: ambiguous use of errno, in log message if sendmmsg fails. - Fix #128: Fix that the invalid port number is logged for sendmmsg failed: Invalid argument. - Fix #127: two minor `-Wcast-qual` cleanups - Fix #126: minor header hygiene - Fix #125: include config.h in compat/setproctitle.c and fix prototype of `setproctitle` - Fix #133: fix 0-init of local ( stack ) buffer. - Fix missing parenthesis on size of fix to init buffer. - Fix #134: IPV4_MINIMAL_RESPONSE_SIZE vs EDNS_MAX_MESSAGE_LEN. - Fix to add missing closest encloser NSEC3 for wildcard nodata type DS answer. - Remove unused init_cfg_parse routine from configlexer. - Fix #138: NSD returns non-EDNS answer when QUESTION is empty. - Fix #142: NODATA answers missin SOA in authority section after CNAME chain. - Fix for CVE-2020-28935 : Fix that symlink does not interfere with chown of pidfile. 4.3.3 ================ FEATURES: - Follow DNS flag day 2020 advice and set default EDNS message size to 1232. - Merged PR #113 with fixes. Instead of listing an IP-address to listen on, an interface name can be specified in nsd.conf, with ip-address: eth0. The IP-addresses for that interface are then used. - Port TSIG code for openssl 3.0.0-alpha6. BUG FIXES: - Fix make install with --with-pidfile="". - Merge #115 from millert: Fix strlcpy() usage. From OpenBSD. - Merge #117: mini_event.h (4.3.2 and 4.3.1) on OpenBSD cannot find fd_set - patch. - Fix that configure checks for EVP_sha256 to detect openssl, because HMAC_CTX_new is deprecated in 3.0.0. - Fix #119: fix compile warnings from new gcc. - Fix #119: warn when trying to parse a directory. - Merge PR #121: Increase log level of recreated database from WARNING to ERR. - Remove unused space from LIBS on link line. - Updated date in nsd -v output. 4.3.2 ================ FEATURES: - Fix #96: log-only-syslog: yes sets to only use syslog, fixes that the default configuration and systemd results in duplicate log messages. - Fix #107: nsd -v shows configure line, openssl version and libevent version. - Fix #103 with #110: min-expire-time option. To provide a lower bound for expire period. Expressed in number of seconds or refresh+retry+1. BUG FIXES: - Fix for posix shell syntax for trap in nsd-control-setup - Fix to omit the listen-on lines from log at startup, unless verbose. - Fix uninitialised values for bindtodevice option at startup with reuseport and multiple interfaces. - Fix #95: Removed make test check because tpkg not included in release tarballs. - Fix unused parameter compile warnings. - Fix #97: EDNS unknown version: query not in response. - Fix #99: Fix copying of socket properties with reuseport enabled. - Document default value for tcp-timeout. - Merge PR#102 from and0x000: add missing default in documentation for drop-updates. - Fix unlink of pidfile warning if not possible due to permissions, nsd can display the message at high verbosity levels. - Removed contrib/nsd.service, example is too complicated and not useful. - Do not log EAGAIN errors for sendmmsg, to stop log spam on OpenBSD. - Merge #108 from Nomis: Make the max-retry-time description clearer. - Retry when udp send buffer is full to wait until buffer space is available. - Remove errno reset behaviour from sendmmsg and recvmmsg replacement functions. - Fix unit test for different nsd-control-setup -h exit code. - Merge #112 from jaredmauch: log old and new serials when NSD rejects an IXFR due to an old serial number. - Fix #106: Adhere better to xfrd bounds. Refresh and retry times. - Fix #105: Clearing hash_tree means just emptying the tree. 4.3.1 ================ BUG FIXES: - Fix #70: error: 'fd_set' undeclared. - Fix #71: error: 'for' loop initial declaration used outside C99 mode. - Fix to move declarations out of for loops in event test too. - Fix #76: cpuid typedef for Hurd, DragonflyBSD compile. - Fix #75: configure test for sched_setaffinity, and use cpuset_setaffinity otherwise. Also test for presence of sysconf. - Fix #74: GNU Hurd fix cast from pointer to integer of different size. - Fix for #74, #75: cpuset test for header contents and provide code. - Fix #78: Fix SO_SETFIB error on FreeBSD. - Merge PR #83 from noloader: Fix GNU HURD sched_setaffinity compile. - Fix #80: NetBSD and implicit declaration of reallocarray. - Fix unknown u_long in util.c for Issue #80 . - Merge PR #86 from noloader: Use precious variables for GREP, EGREP, SED, AWK, LEX and YACC. - For PR #86: Fix that programs loaded after CFLAGS and stuff is set, specifically the compiler, so that it can work if it needs special flags from that. Fix that lex only needs to support -i if actually defined, otherwise the output included in the source tarball can be used. - Merge PR #90 by phicoh: O_CLOEXEC should be FD_CLOEXEC. - Merge PR #92 by tonysgi: Fix typo. - Merge PR #91 by gearnode: nsd-control-setup recreate certificates. The '-r' option recreates certificates. Without it it creates them if they do not exist, and does not modify them otherwise. 4.3.0 ================ FEATURES: - Fix to use getrandom() for randomness, if available. - Fix #56: Drop sparse TSIG signing support in NSD. Sign every axfr packet with TSIG, according to the latest draft-ietf-dnsop-rfc2845bis-06, Section 5.3.1. - Merge pull request #59 from buddyns: add FreeBSD support for conf key ip-transparent. - Add feature to pin server processes to specific cpus. - Add feature to pin IP addresses to selected server processes. - Set process title to identify individual processes. - Merge PR#22: minimise-any: prefer polular and not large RRset, from Daisuke Higashi. - Add support for SO_BINDTODEVICE on Linux. - Add support for SO_SETFIB on FreeBSD. - Add feature to drop queries with opcode UPDATE. BUG FIXES: - Fix fname null check of fname in namedb_read_zonefile. - Fix implicit cast of size in udb_radnode_array_grow. - Fix ignore of return value of ssl_printf in remote.c. - Fix unused check of fd in parent_handle_reload_command. - Attempt to fix signedness of nscount lookup in ixfr query_process. - Fix identical branches for ssl_print of errors in remote.c. - Fix type cast bounds, signedness of opt_rdlen in edns_parse_record. - Fix to separate header and data lines in parse_zone_list_file. - Fix to define max number of EDNS records we are willing to spend time on. - Fix size of string len and capacity type cast in udbradtree. - Fix to protect rrcount in tsig_find_rr from overflow. - Annotate radix_find_prefix_node not reachable trail code. - Fix to protect rrcount in packet_find_notify_serial from overflow. - Fix to close socket on error in create_tcp_accept_sock. - Fix to log on failure to chmod for socket for remote control. - Fix to remove unneeded if in open of socket for remote control. - Fix to restore input parameter on call failure in create_dirs. - Please checker by terminating and initialising string read by remote control. - Fix to define upper bounds on rr counts read from untrusted packet data. - Separate acl_addr_match_range functions for ip4 and ip6, to please checkers. - Avoid unused variable warning in new match_range_v4 function. - Fix whitespace in nsd.conf.sample.in, patch from Paul Wouters. - use-systemd is ignored in nsd.conf, when NSD is compiled with libsystemd it always signals readiness, if possible. - Note that use-systemd is not necessary and ignored in man page. - Fix unreachable code in ssl set options code. - Fix bad shift in assertion code analyzer complaint. - Fix responses for IXFR so that the authority section is not echoed in the response. - Merge PR#60: Minor portability fixes from michaelforney, with avoid pointer arithmetic on void* and avoid unnecessary VLA. - Fix that the retry wait does not exceed one day for zone transfers. CHANGES: - Set FD_CLOEXEC on opened sockets. 4.2.4 ================ FEATURES: - Fix #48: Add make distclean that removes config.h made by configure. And add maintainer-clean that removes bison and flex output. BUG FIXES: - Detect fixed time memcmp for openssl 0.9.8 compatibility. - Detect EC_KEY_new_by_curve_name for openssl 0.9.8. - include limits.h for UINT_MAX. - If no recvmmsg, dont use msg_flags member, but errno for error, where our fallback function left it, msg_flags also does not exist on some systems. - Remove unused variable warning for portability. - Fix #52: do not log transient network full errors unless higher verbosity is set. - Fix regressions in configparser.y where global variables were not set for minimal-responses, round-robin and log-time-ascii. 4.2.3 ================ FEATURES: - For #39: confine-to-zone configures NSD to not return out-of-zone additional information. Contributed by Greg Bock. - For #21: pidfile "" allows to run NSD without a pidfile, for startup management tools like daemontools. - For #21 add contrib/patch_for_s6_startup_and_other_service_supervisors.diff that adds support for readiness notification with READY_FD from Cameron Nemo. BUG FIXES: - Fix #35: excessive logging of ixfr failures, it stops the log when fallback to axfr is possible. log is enabled at high verbosity. - Fixup warnings during --disable-ipv6 compile. - The nsd.conf includes are sorted ascending, for include statements with a '*' from glob. - Fix #38: log address and failure reason with tls handshake errors, squelches (the same as unbound) some unless high verbosity is used. - Fixup clang analysis warning in xfrd_parse_received_xfr_packet master dereference. CHANGES: - Number of different UDP handlers has been reduced to one. recvmmsg and sendmmsg implementations are now used on all platforms. Compatible implementations are in place for systems that lack the system calls. - Socket options are now set in designated functions for easy reuse. - Socket setup has been simplified for easy reuse. - Configuration parser is now aware of the context in which an option was specified. - Fix #44: document that remote-control is a top-level nsd.conf attribute. 4.2.2 ================ BUG FIXES: - Fix #20: CVE-2019-13207 Stack-based Buffer Overflow in the dname_concatenate() function. Reported by Frederic Cambus. It causes the zone parser to crash on a malformed zone file, with assertions enabled, an assertion catches it. - Fix #19: Out-of-bounds read caused by improper validation of array index. Reported by Frederic Cambus. The zone parser fails on type SIG because of mismatched definition with RRSIG. - PR #23: Fix typo in nsd.conf man-page. - Fix that NSD warns for wrong length of the hash in SSHFP records. - Fix #25: NSD doesn't refresh zones after extended downtime, it refreshes the old zones. - Set no renegotiation on the SSL context to stop client session renegotiation. - Fix #29: SSHFP check NULL pointer dereference. - Fix #30: SSHFP check failure due to missing domain name. - Fix to timeval_add in minievent for remaining second in microseconds. - PR #31: nsd-control: Add missing stdio header. - PR #32: tsig: Fix compilation without HAVE_SSL. - Cleanup tls context on xfrd exit. - Fix #33: Fix segfault in service of remaining streams on exit. - Fix error message for out of zone data to have more information. 4.2.1 ================ FEATURES: - Added num.tls and num.tls6 stat counters. - PR #12: send-buffer-size, receive-buffer-size, tcp-reject-overflow options for nsd.conf, from Jeroen Koekkoek. - Fix #14, tcp connections have 1/10 to be active and have to work every second, and then they get time to complete during a reload, this is a process that lingers with the old version during a version update. BUG FIXES: - Fix #13: Stray dot at the end of some log entries, removes dot after updated serial number in log entry. - Fix TLS cipher selection, the previous was redundant, prefers CHACHA20-POLY1305 over AESGCM and was not as readable as it could be. - Consolidate server tls context create and remote control context create, with hardening for the remote control tls context too. - Fix to init event structure for reassignment. - Fix to init event not pointer, in reassignment. - Fix #15: crash in SSL library, initialize variables for TCP access when TLS is configured. - Fix tls handshake event callback function mistake, reported by Mykhailo Danylenko. - Initialize event structures before event_set, to stop uninitialized values from setting event library lists and assertions, that would sometimes also show after event_del. - Do not use symbol from libc, instead use own replacement, if not available, for accept4. - Fix output of nsd-checkconf -h. 4.2.0 ================ FEATURES: - Print IP address when bind socket fails with error. - Fix #4249: The option hide-identity: yes stops NSD from responding with the hostname for chaos class queries. Implements the RFC4892 security considerations. - Patch to add support for TCP Fast Open, from Sara Dickinson (Sinodun). - Patch to add support for tls service on a specified tls port, from Sara Dickinson (Sinodun). - Use travis for build check, initial unit test and clang analysis. - TLS OCSP stapling support, enabled with tls-service-ocsp: filename, patch from Andreas Schulze. BUG FIXES: - Fix to delete unused zparser.default_apex member. - Fix that the TLS handshake routine sets the correct event to continue when done. - Fix that TLS renegotiation calls the read and write routines again with the same parameters when the desired event has been satisfied. - Fix that TCP Fastopen has better error message and supports OSX. - Fix to avoid buffer alloc with global buffer in tls write handler. - Fix to initialize event structure when accepting TCP connection. - Disable TLS1.0, TLS1.1 and weak ciphers, enable CIPHER_SERVER_PREFERENCE, patch from Andreas Schulze. - further setup ssl ctx after the keys are loaded, for ECDH. - Fix #10: Fix memory leaks caused by duplicate rr and include instructions. - Fix to define _OPENBSD_SOURCE to get reallocarray on NetBSD. 4.1.27 ================ FEATURES: - Deny ANY with only one RR in response, by default. Patch from Daisuke Higashi. The deny-any statement in nsd.conf sets ANY queries over UDP to be further moved to TCP as well. Also no additional section processing for type ANY, reducing the response size. - Fix #4215: on-the-fly change of TSIG keys with patch from Igor, adds nsd-control print_tsig, update_tsig, add_tsig, assoc_tsig and del_tsig. These changes are gone after reload, edit the config file (or a file included from it) to make changes that last after restart. BUG FIXES: - Fix #4213: disable-ipv6 and dnstap compile error. - Fix to reduce region_log_stats if condition, this removes a debug statement. - Fix for FreeBSD port with dnstap enabled. - Fix to remove unused code. - Fix #6: nsd-control-setup: Change validity time to a shorter period (<2038). - Fix unused definition in header remote.h. - Fix #4236: IPV4_MINIMAL_RESPONSE_SIZE=1480 is slightly too big. - Fix #4235: IP_PMTUDISC_OMIT on IPv4/UDP sockets. - Fixed radtree_insert memory leak. - Fixed access recycled variable. 4.1.26 ================ FEATURES: - DNSTAP support for NSD, --enable-dnstap and then config in nsd.conf. - Support SO_REUSEPORT_LB in FreeBSD 12 with the reuseport: yes option in nsd.conf. - Added nsd-control changezone. nsd-control changezone name pattern allows the change of a zone pattern option without downtime for the zone, in one operation. BUG FIXES: - Fix #4194: Zone file parser derailed by non-FQDN names in RHS of DNSSEC RRs. - Fix #4202: nsd-control delzone incorrect exit code on error. - Tab style fix to use tab for 8 spaces, from Xiaobo Liu. - Fix #4205: enable-recvmmsg in mixed IPv4/IPv6 environment fails. This sets the msg_hdr.msg_namelen correctly after receipt. - Fix to not set GLOB_NOSORT so the nsd.conf include: files are sorted and in a predictable order. - Fix #3433: document that reconfig does not change per-zone stats. 4.1.25 ================ FEATURES: - nsd-control prints neater errors for file failures. BUG FIXES: - Fix that nsec3 precompile deletion happens before the RRs of the zone are deleted. - Fix printout of accepted remote control connection for unix sockets. - Fix use_systemd typo/leftover in remote.c. - Fix codingstyle in nsd-checkconf.c in patch from Sharp Liu. - append_trailing_slash has one implementation and is not repeated differently. - Fix coding style in nsd.c - Fix to combine the same error function into one, from Xiaobo Liu. - Fix initialisation in remote.c. - please clang analyzer and fix parse of IPSECKEY with bad gateway. - Fix nsd-checkconf fail on bad zone name. - Annotate exit functions with noreturn. - Remove unused if clause during server service startup. - Fix #4156: Fix systemd service manager state change notification When it is compiled, systemd readiness signalling is enabled. The option in nsd.conf is not used, it is ignored when read. 4.1.24 ================ FEATURES: - #4102: control interface via local socket. configure it with control-interface: "/path/nsd.ctl" The path has to start with a / to separate it from an IP address. The local socket does not use SSL, but unencrypted traffic, use file and containing directory permissions to restrict access. - configure --enable-systemd (needs pkg-config and libsystemd) can be used to then use-systemd: yes in nsd.conf and have readiness signalling with systemd. - RFC8162 support, for record type SMIMEA. BUG FIXES: - Patch to fix openwrt for mac os build darwin detection in configure. - Fix that first control-interface determines if TLS is used. Warn when IP address interfaces are used without TLS. - #4106: Fix that stats printed from nsd-control are recast from unsigned long to unsigned (remote.c). - Fix that type CAA (and URI) in the zone file can contain dots when not in quotes. - #4133: Fix that when IXFR contains a zone with broken NSEC3PARAM chain, NSD leniently attempts to find a working NSEC3PARAM. 4.1.23 ================ BUG FIXES: - Fix NSD time sensitive TSIG compare vulnerability. 4.1.22 ================ FEATURES: - refuse-any sends truncation (+TC) in reply to ANY queries over UDP, and allows TCP queries like normal. - Use accept4 to speed up answer of TCP queries, on Linux, FreeBSD and OpenBSD. BUG FIXES: - Fix nsec3 hash of parent and child co-hosted nsec3 enabled zones. - Fix to use same condition for nsec3 hash allocation and free. 4.1.21 ================ FEATURES: - --enable-memclean cleans up memory for use with memory checkers, eg. valgrind. - refuse-any nsd.conf option that refuses queries of type ANY. - lower memory usage for tcp connections, so tcp-count can be higher. BUG FIXES: - Fix unused variable warnings and uninit variable in statistics printout from clang analyzer. - Fix spelling error in xfr-inspect. - Fix #3562: explain build error when flex missing. - Fix buffer size warnings from compiler on filename lengths. - Fix #4093: Release notes not using 2018. 4.1.20 ================ BUG FIXES: - Fix memory leak in zone file read of unknown rr formatted RRs. - Fix memory leak when rehashing nsec3 after axfr or zonefile read, in the selectively allocated precompiled nsec3 hashes. 4.1.19 ================ BUG FIXES: - ignore fallthrough compiler warning in flex EOF rule. - Fix warnings emitted by clang for --enable-packed. Alignment is not a problem for x86_64, don't enable packed when the platform requires aligned access. - Fix spelling error in xfr-inspect. - Fix 3392: Fix regression in 4.1.18 for notify lists with ip4 and ip6 targets. - Add test for support of -Wno-address-of-packed-member for --enable-packed. 4.1.18 ================ FEATURES: - xfr-inspect, it is not installed, it prints xfr files from /tmp made with 'make xfr-inspect' in the source dir. - retry timeout between sending notifies dropped from 15 to 3 sec. - NSD sends 16 notifies simultaneously. - configure --enable-packed reduces memory usage, at expense of unaligned reads. Saves about 17%. - Save memory by selectively allocate precompiled nsec3 hashes, saves about 16% memory. - make ip-transparent option work on OpenBSD. - Save about 2% memory by changing usage count size in name tree. - Fix #2871: Increase number of sockets for xfrd transfers. BUG FIXES: - Fix gcc 7.1.1 warnings. - Fix writev compile warning on FreeBSD. - Fix #1446: A corrupted zone file "propagates" to good ones. - nsd-control zonestatus prints wait time between attempts, for zones that are in that waiting time. - Fix collision printout of nsec3 to print name, hash and reverse. - Fix #1567: Change crit to err log level for gettimeofday failure. Add defines for compile without syslog. - Fix crash for DS query when parent and child zones both configured in nsd.conf and parent zone has not loaded properly. 4.1.17 ================ FEATURES: - zone parser parses type AVC (it has TXT format). - Fix #1272: use writev to put tcp length field with data for outgoing zone transfer requests. BUG FIXES: - Fix potential null pointer in nsec3 adjustment tree. - Fix text format of deletes for CDS and CDNSKEY, single 0 to represent empty base64 or hex string. 4.1.16 ================ FEATURES: - zone parser can parse acronyms for algorithms ED25519 and ED448. - Fix 1243: Option to make NSD emit really minimal responses, minimal-responses: yes in nsd.conf. BUG FIXES: - Calculate new udb index after growing the array, fix from Chaofeng Liu. - Fix missing _t to _type conversion for disable-radix-tree option. - Printout serial error with hint it may be too big. - Fix 1228: OpenSSL include is not guarded with HAVE_SSL - Patch for expire state in multi-master when masters includes broken master, from Manabu Sonoda. - minor manpage fix. 4.1.15 ================ BUG FIXES: - Fix nsd-control and ipv6 only. - Squelch zone transfer error address family not supported by protocol at low verbosity levels. - Fix #1195: Fix so that NSD fails on non-compliant values for Serial. - Fix to rename _t typedefs because POSIX reserves them. - Fix that nsec3 hash collisions only reported on verbosity level 3. 4.1.14 ================ FEATURES: - Fix #1132 for SERVFAIL zones perform backoff, and remembers the timeout on next startup. BUG FIXES: - Fix null memcpy for radixtree with single link element. - Robust fix against missing master in tcp_open for xfrd. - Fix wildcards in include: config statements with chroot enabled. - suppress compile warning in lex files. - Fix to try every master once, then wait for timeout or notify. - Save backoff timeout into xfrd.state file, this file has a higher version number now. Old files are skipped silently (causes refresh) and created as new files upon exit. - Fix restart of zone transfers when new config becomes available. 4.1.13 ================ FEATURES: - multi-master-check: yes can be used to check all masters for the last version, using the higher version from the configured masters, from Manabu Sonoda. - Support RR type OPENPGPKEY from RFC 7929. - Can config key algorithms with the digest name, eg. 'sha256'. - configure --disable-radix-tree for about 15% lower memory usage. - for type SRV add A/AAAA to the additional section (if possible), just like we already do for type MX. - more extensible edns option handling. BUG FIXES: - Fix compile warnings about unused result from write and strtol. and signcompare in minmax retrytime. - Fix #812: fix that make depend fails after distribution. - Fix #817: xfrd update failed loop. - Add robustness against unallocated data in nsec3 trees. - Fix README spelling error of BSD license (reported by Joerg Jung). - Fix multimaster for not tried full zone transfer for a expired zone. - Fix #827: fix compile with openssl 1.1.0 with api=1.1.0. 4.1.12 ================ BUG FIXES: - Fix malformed edns query assertion failure, reported by Michal Kepien (NASK). 4.1.11 ================ FEATURES: - When tcp is more than half full, use short timeout for tcp session. - Patch for {max,min}-{refresh,retry}-time from YAMAGUCHI Takanori. - Fix #790: size-limit-xfr can stop NSD from downloading infinite zone transfer data size, from Toshifumi Sakaguchi. Fixes CVE-2016-6173 JVN#63359718 JPCERT#91251865. BUG FIXES: - Fix build without IPv6, patch from Zdenek Kaspar. - Fix #783: Trying to run a root server without having configured it silently gives wrong answers. - Fix #782: Serve DS record but parent zone has no NS record. - Fix nsec3 missing for nsec3 signed parent and child for DS at zonecut. 4.1.10 ================ FEATURES: - ip-freebind: yesno option in nsd.conf sets IP_FREEBIND socket option for Linux, binds to interfaces and addresses that are down. - NSD includes AAAA before A for queries over IPV6 (in delegations). And TC is set if no glue can be provided with a delegation because of packet size. - print notice that nsd is starting before taking off. BUG FIXES: - Fix for openssl 1.1.0, HMAC_CTX size not exported from openssl. - Fix #751: NSD fails to occlude names below a DNAME. - If set without nsd.db print "" as the default in the man pages. - Fix #755: NSD spins after a zone update and a lot of TCP queries. - Fix for NSEC3 with zone signed without exact match for empty nonterminals, the answer for that domain gets closest encloser. - #772 Document that recvmmsg has IPv6 problems on some linux kernels. 4.1.9 ================ BUG FIXES: - Change the nsd.db file version because of nanosecond precision fix. 4.1.8 ================ FEATURES: - #732: tcp-mss, outgoing-tcp-mss options for nsd.conf, patch from Daisuke Higashi. - #739: zonefile changes when mtime is small are detected on reload, if filesystem supports precision mtime values. - RR type CSYNC (RFC7477) syntax is supported. BUG FIXES: - take advantage of arc4random_uniform if available, patch from Loganaden Velvindron. - Fix flto check for OSX clang. - Define _DEFAULT_SOURCE with _BSD_SOURCE for glibc 2.20 on Linux. - Fix #736: segfault during zone transfer. - Fix #744: Fix that NSD replies for configured but unloaded zone with SERVFAIL, not REFUSED. 4.1.7 ================ FEATURES: - support configure --with-dbfile="" for nodb mode by default, where there is no binary database, but nsd reads and writes zonefiles. - reuseport: no is the default, because the feature is not troublefree. - configure --enable-ratelimit-default-is-off with --enable-ratelimit to set the default ratelimit to disabled but available in nsd.conf. - version: "string" option to set chaos version query reply string. BUG FIXES: - Fix zones updates from nsd parent event loop when there are a lot of interfaces. - portability fixes. - patch from Doug Hogan for SSL_OP_NO_SSLvx options, for the new defaults in the ssl libraries. - updated contrib/nsd.spec, from Bálint Szigeti, with new configure options. - Allocate less memory for TSIG digest. - Fix #721: Fix wrong error code (FORMERR) returned for unknown opcode. NOTIMP expected. - Fix zonec ttl mismatch printout to include more information. - Fix TCP responses when REUSEPORT is in use by turning it off. - Document default in manpage for rrl-slip, ip4 and 6 prefixlength. - Explain rrl-slip better in documentation. - Document that ratelimit qps and slip are updated in reconfig. - Fix up defaults in manpage. 4.1.6 ================ BUG FIXES: - 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. 4.1.5 ================ BUG FIXES: - Fix #706: default port 53 not opened on ip4 because of getaddrinfo hints initialisation failure. 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. BUG FIXES: - 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 separately 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.3 ================ FEATURES: - nsd-control addzones and delzones read list of zones from stdin. - hmac sha224, sha384 and sha512 support, patch from David Gwynne. - max-interfaces raised to 32. BUG FIXES: - Fix #665: when removing subdomain, nsd does not reparse parent zone. - Fix task and zonestat files to be stored in a subdirectory in tmp to stop privilege elevation. - Fix crash in zone parser for relative dname after error in origin. - Fix that formerrors are ratelimited. 4.1.2 ================ FEATURES: - Incoming notifies have serial number logged (at verbosity 1). BUG FIXES: - Remove some duplicate header includes (from Brad Smith). - Fix tcp waiting list for zone transfers where the bind and connect calls fail. - Fix segfault in zone reader on invalid input. (thanks John Van de Meulebrouck Brendgard) - Fix segfault on double origin in zone reader (thanks John Van de Meulebrouck Brendgard). - Fix b64pton out of bounds error on invalid zonefile input. (thanks John Van de Meulebrouck Brendgard) - Fix origin directive from unused old value and subdomain parser failure, reported by John Van de Meulebrouck Brendgard. - Fix use after free after zonefile syntax error followed by ttl or origin directive, reported by John Van de Meulebrouck Brendgard. - Fix syntax error followed by too many TXT elements parse crash reported by John Van de Meulebrouck Brendgard. - Fix buffer overflow in config parse of domain name, reported by John Van de Meulebrouck Brendgard. - Use reallocarray for integer overflow protection, patch submitted by Loganaden Velvindron. - Fix allocation integer overflow checks. - Fix #654: Fix contradiction in notify logging verbosity level. - Fix #655: Fix contradiction in verbosity for zone transfers. - Made log message more consistent, changed 'axfr refused' log message to be more consistent with other messages. Also notify refused. - verbosity 2 logs axfr refused and notify refused. verbosity 1 contains less log messages. 4.1.1 ================ FEATURES: - RFC 7344: CDS and CDNSKEY (read record types). - per zone statistics with --enable-zone-stats, config zone with zonestats: "name", zones configured with the same string are added. - Disabled use of SSLv3 in nsd-control. - nsd-checkconf -f prints out full name of pidfile (with dir). - Synthesize CNAMEs with same TTL as DNAME. BUG FIXES: - Fix that expired zones stay expired after a server restart. - Fix "xfrd_handle_ipc: bad mode" log errors when compiled with --disable-bind8-stats. - Fix #616: retry xfer for zones with no content after command. - Fix char used as array index warnings on NetBSD. - Fix that queries for noname CH TXT are REFUSED instead of nodata. - Fixes for wildcard addition and deletion, speedup for some cases. - Fix that failure to add tcp to tcp base does not leak the socket. - Patch nsd_munin_ from Philip Paeps to use type ABSOLUTE. - Fix spinning NSD with lots of failing transfers, due to pointer comparison using void pointer subtraction (from Otto Moerbeek). - Fix bug#637: fix that nsd.db grows limitlessly, an off by one on one megabyte free chunks, created during AXFRs of large zones, that caused the one megabyte chunk to be leaked. - Fix casts for ctype functions (from Todd Miller). - correct some hyphen-used-as-minus-sign (from Andreas Schulze) in man pages. - Fix zonesdir chroot error message. 4.1.0 ================ FEATURES: - database: "" starts without mmap of database. Less memory is used, zones are read from text zonefile. - optimised zonefile parse code and zonefile write code. - zonefiles-write option in nsd.conf, enabled when database is "". The server writes changed zonefiles to disk every hour. - xfrdfile: "" disables xfrd.state. If enabled, zones that are same as before are not checked for a serial update at server start. - include: "foo/nsd.d/*.conf" works, wildcard glob on includes. - nsd shuts down during init process if given signal. - log-time-ascii option, default yes, with readable timestamp in log. - nsd-control addzone reports if zone already exists. - Fix #564: add nsd-checkzone tool to check zonefile correctness. - Increased default --with-max-ips from 8 to 16, this increases the number of interfaces you can specify in nsd.conf to listen to. BUG FIXES: - Fixed shutdown message sporadically not printed on exit (Thanks Anand Buddhdev). - Documented zonefile %s syntax in nsd.conf man page. - Fix manpage to put colon after zonefiles check and write. - Change from 'Zone" to "zone" with ".. serial .. is updated" log message. - Changed maxbackoff for no-content secondary zones from 4h to 24h. - Fix print filename of encompassing config file on read failure. - Fix delete or rename of a lot of zones and make it take a non-enormous time. - Speed up deletion of zone contents a lot, (56s to 1s), speeds up delete, rename and AXFR for zones. - Fix #571: unused variable and incompatible pointer warnings when compiled on a system without INET6. - Fix write_socket return value check in server.c (Thanks Brad Smith, Mark Kettenis). - Fix that xfrd reaps children also if the signal is lost. - Fix #577: makefile incorrectly installed manpages from srcdir. - Fix #587: Default value for statistics is 0. - Fix #553: Improve TXT parsing. - Fix #590: rrl log does not print wildcard as a star but escaped. - Fix #591: rrl log messages at verbosity level 1. - fix strptime implicit declaration error on OpenBSD. - Fix -O3 compile flag to -O2 to avoid miscompilations. - Allow user to override the -g -O2 CFLAGS in ./configure. - Fix endian.h include for OpenBSD. - Fix #600: document that provide-xfr provides AXFR and not IXFR. - Fix rising-load-average or memory-leaks in OSes (Linux since 2.6), that keep track of all past process parents, or leak memory for them. Fix makes it so there is no very deep string of process parents. - Remove .LP after .SH in man pages. 4.0.3 ================ BUG FIXES: - Fix nsd.db unclean close check. Previous databases are considered unclean by the code and are created anew. - Adds nsd.db larger than 400Tb check for sanity. Also test if filesize as documented in the file is correct. - nsd waits for tasks to complete on stop, prevents nsd.db corruption. - fix to not delete tmpdir too early in shutdown process. - disabled udb checking functionality that made it very slow, this was enabled when enable-checking was turned on. 4.0.2 ================ FEATURES: - Return REFUSED for queries to non-hosted zones. BUG FIXES: - Fix expired zones to give SERVFAIL, also when parent zone loaded. - documented nsd-control zonestatus output in nsd-control manpage. - remove mention of nsdc from nsd-checkconf manpage. - Disabled recvmmsg and sendmmsg usage by default because kernel versions have implementation issues: ipv6 ignored, security issues. - Detect libevent2 install automatically by configure, and use event2 header files if necessary. - Fix #551: change Regent to Copyright holder in the LICENSE, to match the definition on opensource.org for the BSD License. - Fix #552: zonefile loads on nsd-control reconfig when the name of the file has changed. - Fix leak of zone name after zonefile read and fix malloc too large that would be leaked in the radix tree. - Fix from 3.2: make SOA RDATA comparisons in XFR more lenient (only check serial). - Fix that NSD will delete and recreate not-clean-closed databases. 4.0.1 ================ FEATURES: - recognizes ip-address and interface as synonyms for convenience. - Support for EUI48 and EUI64 RR types enabled by default (RFC 7043). - Support for CAA RRtype (RFC 6844). - NSID can be set with "ascii_somestring" in ascii. BUG FIXES: - Fix xfrd when zone transfer TCP contains zero length packets. - Fix for NSEC3 zones where parent zone is co-hosted, also NSEC3, because AXFRs overwrote nsec3 administration in the child zone. - Fix that bad IXFR updates do not result in double SOA records, and that an AXFR is started (attempted) when the zone state seems to be inconsistent with the master's zone state. - Log ip address for sendto and sendmmsg failures. - Fix segfaults after read of zones with rr type WKS from zonefile. - Seed PRNG for openssl at start of daemon, fixes SSL connection issue. - Bugfix #534: IXFR query loop over UDP for zones that are unchanged. - (same as in 3.2.16): fix wildcard cname to nxdomain repeated rrset. - (same as in 3.2.16): Bugfix #542: Match RRSIG TTL with SOA TTL in negative response. - Check if configure in srcdir collides with outofdir build. - Fix #546: output format errors in nsd_munin_ (Thanks Tom Hendrikx). - Fix printout of high-chars in TXT on NetBSD. 4.0.0 NSD 4.0 =============== FEATURES: - documented in doc/NSD-4-features. Change configuration without restart, direct nameserver control with nsd-control, support a higher number of zones. Higher performance (compared to NSD3). - nsdc is gone. Use kill -HUP for reload (also checks if zonefiles have changed and rereads them), and kill -TERM for quit. Or use nsd-control for detailed control. - cron job for nsdcpatch is gone. nsd-control write creates zonefiles. - nsd.db has a new format that compacts itself when it is changed, thus nsdc patch is no longer necessary. - nsd.db is memory mapped, NSD needs (part of) that mmap in ram. - tcp-count can go above 1000; epoll/kqueue support with libevent. - nsd-control reconfig for updates with no restart (zones, keys, ..) - nsd-control-setup to create keys for nsd-control (enable nsd-control with remote-control: yes in nsd.conf). - the NSD 3 feature of special zone stats are not ported to 4 yet, as it would entail a complete reimplementation of the feature. FEATURES (incremental from BETA5): - configure --disable-recvmmsg for compat with older Linux kernels, by default it autodetects support in the kernel on the buildmachine. - Fix time at 2038, uint32s changed to time_t, support 64bit time_t. - Fix use of 32bit time, for 2038, thanks to Theo de Raadt for patch. BUG FIXES (incremental from BETA5): - Bugfix #518 Incorrect RRL prefix length option names in nsd.conf man page from Ville Mattila. - Fix that xfrd, and nsd-control, does not stop responding when reload errors out. The pid is sent like it should by server_main. - Fix that EOF in quoted string error does not cause reload to exit. - Fixup errors from the stack code checker. - Removed use of random when arc4random is available. Thus, random and srandom are then not linked with the executable. - Fix segfault with no logfile and chroot (Thanks Patrik Lundin). 4.0.0b5 BETA 5 release of NSD 4.0 ================================== FEATURES: - Optimizations for startup, qps and tcp speed, beta bug fixes and merge with code changes with NSD 3.2.16. - nsd-mem tool (make nsd-mem) to estimate memory usage. - Same as NSD 3.2.16: --enable-draft-rrtypes(EUI48, EUI64), rr-slip, rrl-ipv[46]-prefix-length, ip-transparent config options. - configure option --disable-flto. - improved RRL logging (query details that caused blockage). - nsd-control status prints out ratelimit if ratelimit is enabled. - nsd-control verbosity prints out verbosity level without argument. - Fix #491: pick program name (of executable) as syslog identity. - printout percentage for long activities (to log). After about 5 seconds have passed. BUG FIXES: - The same fixes up to NSD 3.2.16. - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify. - Fix tcp zonetransfer pipeline lookup function. - Fix compile on bigendian netbsd alpha. - Fixup the growth and shrinkage of nsd.db. This should use less calls to remap and change the file and mmap size. - notify information is logged at correct verbosity level, 1. - Fix memory statistics in nsd_munin_. - faster nsec3 updates. - Fixup contrib/bug390.patch for 4.0.0b4. - remove leak of nsec3. - allocate radixtree in region for small (5%) total savings and about 15% savings in the radixtree itself (due to many small alloc savings in region). - Patch from Lukas Wunner that makes nsd.conf include files work inside chroot/etc environments on repattern and reconfig. - Fix race on exit of nsd, for restarts, so that the pidfile-pid process waits until port53 has been closed before exiting. - Patch from Lukas Wunner that makes chroot more consistent. Make all paths absolute with the chrootdir in front, or use an absolute zonesdir with other paths relative to that. - Fix segfault on repeated reconfigs, double free of zone apex name. - Fix zone parser allocations are put in the db region. - Fix memory leak in zone parser for txt record. - Optimizations: -O3 if possible (user can override CFLAGS), udp buffers are set to 1m by default (if socket options exist), use recvmmsg and sendmmsg, or only recvmmsg, or recvfrom. - nsd.db 12% smaller, no nsec3 hash storage. Also ups udb version because of the format change. The nsd.db is recreated when a different version number is detected on startup. - Fix region-allocator for speedup of load and change of large data. - Increase tcpbacklog default to 256 (silently capped to 128 on BSD). For remote control keep it at 16, it has less TCP load. It does not actually increase TCP performance (some except), but reduces connection loss when there is a spike in TCP connections. - unlink xfr file if transfer is stopped, timeouted or interrupted. And unlink xfr file in progress when the zone is deleted. 4.0.0b4 BETA 4 release of NSD 4.0 ================================== BUG FIXES: - remove -fwhole-program gcc flag usage. We cannot reliably detect if it works without failure. - fix zonefiles-check: entry in nsd.conf - fix gcc warning, do not use uninit value for rng init. - remove printout of "bad transfer" to the log for notimpl. - printout log less verbosely, not every axfr packet. - RRL documented in nsd.conf.sample - Fix is_apex flag for zones read from udb. - Fix that nsec3 zones are precompiled when read from udb. This caused assertion failures. - Less printout of 'bad transfer'. - Fix AXFR of NSEC3 slave zone. - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify on verbosity 2. 4.0.0b3 BETA 3 release of NSD 4.0 ================================== BUG FIXES: - applied patch from Robin Hack to remove double pid file truncation. - repattern is called reconfig (because most config options are picked up, except for superuser options (chroot, logfile, port)) - document that the zonefile attribute can be empty. - documented that the _implicit_ pattern names are used internally. - Added zonefiles-check option, default yes, check mtimes of zone files on sighup and startup (from Robin Hack). - Fix spurious assertion failure for some rrl blocks. - Tabs and spaces nicer in nsd.conf.sample. - List libevent in README. - Fix configure for gentoo gcc and headers. - do-ip4 and do-ip6 nsd.conf options just like unbound. - do not leave task files in /tmp if nsd fails to startup because of file permissions. - create xfrdir on make install (does not remove on make uninstall, because this could be /tmp). - Fix segv if xfrdir does not exit. - log ip address with tcp failure. - Fix time calculation of zone transfer. 4.0.0b2 BETA 2 release of NSD 4.0 ================================== FEATURES: - Add and remove zones from nsd.conf with nsd-control repattern. - Merge changes from 3.2.15 (such as xname-rcode fix). BUG FIXES: - Fix for use with libev. - 'nsd-control start' runs an absolute path to start sbin/nsd. - Fix for use with libevent-2.1.2. - --with-logfile sets the logfile inside the example documentation. - Fixed addzone and delzone inside chroot (thanks Will Pressly). - Fix make outside of source directory. 4.0.0b1 BETA 1 release of NSD 4.0 ================================== FEATURES: - add and remove zones without restart. - nsdc is gone, use nsd-control for direct server control. - performance increases - support lots of zones - and more ... - longer desc in doc/NSD-4-features BUG FIXES: - core code is fixed like 3.2.15r3763 (12 dec 2012). 3.2.16 (development branch) ================================= FEATURES: - New config option "ip-transparent:" to allow NSD to bind to non local addresses. Default no. - Use IPV6 minimum MTU settings with TCP to reduce failures that are caused by delays in learning working PMTU when communicating through a tunnel. - Bugfix #496: Support for EUI48 and EUI64 RR types. Experimental, turned off by default. Enable with --enable-draft-rrtypes. - New config option "rrl-slip:" to set the average number of packets discarded before we send back a truncated response. - New config option "rrl-ipv4-prefix-length:" and "rrl-ipv6-prefix-length:" to set the prefix lengths. - Improved RRL logging, also print triggering query src address and QTYPE. - Provide RRL documentation in nsd.conf.sample. BUG FIXES: - Bugfix #357: Parent process waits until children closed down sockets, to prevent NSD failing to bind to sockets when restarting. - Bugfix #487: lookup3.c determine endianness for BSD systems. - Bugfix #491: pick program name (0th argument) as syslog identity. - Bugfix #494: Exit with return code 1 if socket code fails. - RRtypes ASFDB, RP, RT should not compress dnames. - Fix outgoing-interface: Don't fail if family is IPv6 but only IPv4 outgoing-interface is set, or vice versa. - RRtypes ASFDB, RP, RT should not compress dnames. - Check that zone directory is within chroot directory. - Better XFR checking, fallback to AXFR (if allowed) if three malformed XFR packets have been seen. 3.2.15 ================================= FEATURES: - Support for ILNP RR types: NID, L32, L64, LP (RFC6742). - RRL, --enable-ratelimit at configure time and config options. - TSIG initialization only fails when there is no digest found at all. BUG FIXES: - Bugfix #478: Declaration after statement (for gcc 2.95). - Bugfix #483: Better error message in case of TSIG error. - Bugfix #485: TTL should not be greater than 2^31 - 1. - Fix RCODE when CNAME loop final answer does not exist, should return NXDOMAIN as stated by RFC 6604. - Fix --disable-full-prehash bug, where after multiple incoming IXFRs, NSEC3 can be removed unjustified. 3.2.14 ================ FEATURES: - TCP writev support. BUG FIXES: - Fix build on OpenBSD (thanks Oliver Peter). - Prioritize notify sender for requesting XFR (thanks Ilya Bakulin). - Fix crash in zonec if TXT string too long (thanks Ilya Bakulin). - tzset before chroot for correct timezone (thanks Camiel Dobbelaar). - Fix --disable-full-prehash bug when nsdc patch happens while ixfr too, it did not rehash the new database. - Bugfix #464: Conditionally define MAXHOSTNAMELEN. 3.2.13 ================ BUG FIXES: - Fix for nsd-patch segfault if zone has been removed from nsd.conf (thanks Ilya Bakulin). - Bugfix #460: man page correction - identity. - Bugfix #461: NSD child segfaults when asked for out-of-zone data with --enable-zone-stats. [VU#517036 CVE-2012-2979] 3.2.12 ================ BUG FIXES: - Fix for VU#624931 CVE-2012-2978: NSD denial of service vulnerability from non-standard DNS packet from any host on the internet. http://www.nlnetlabs.nl/downloads/CVE-2012-2978.txt 3.2.11 ================ FEATURES: - Fallback to AXFR if IXFR is unknown at the primary. NSD considers IXFR unknown at the primary if there is a negative response for the IXFR RRtype. This does not override the value for 'allow-axfr-fallback'. - Allow for reading in new DNSKEY algorithm mnemonics (RFC5155, RFC5702, RFC5933, and RFC6605 (ECDSA)). - Zone statistics, enable with --enable-zone-stats. This stores the BIND8 stats per zone in a configurable statistics file. This option does not scale and should therefore not be enabled when serving many zones. - Support for TLSA RRtype (DANE). BUG FIXES: - Fix for qtype ANY for a wildcard domain in NSEC signed zone: Don't add the wildcard domain NSEC into the answer section. Instead, put the wildcard expanded NSEC into the answer section and keep the wildcard domain NSEC in the authority section. - Fix for accept spinning reported by OpenBSD. - Fix restart failed due to bad ixfr packet because of zone removed from nsd.conf. - Bugfix #453: typo in nsdc man page. OPERATIONAL NOTES: - NSD uses the query name for dname compression again (Fix #235 had as side effect that this didn't happen anymore and is hereby undone). 3.2.10 ================ BUG FIXES: - Bugfix #421: Truncate pidfile on shutdown, before unlink. - Bugfix #423: Fix slow zone transfer processing due to 'Fix is_existing flag for ENT' bugfix. - Fix bug #430: segfault when MAX_INTERFACES set to more than 65K. - Fix configure.ac strptime check for gcc 4.6.2, acx_nlnetlabs update. 3.2.9 ================ FEATURES: - Minimize responses to reduce truncation: NSD will only add optional records to the authority and additional sections when the response size does not exceed the minimal response size. The minimal response size is 512 (no-EDNS), 1480 (EDNS/IPv4), 1220 (EDNS/IPv6), or the advertized EDNS buffer size if that is smaller than the EDNS default. The feature is enabled by default. You can disable it by configuring NSD with --disable-minimal-responses. - Less NSEC3 prehashing. This will make NSD handle zone transfers faster, but will decrease the performance of NXDOMAIN and wildcard NODATA responses. Full prehashing is enabled by default. If you want less NSEC3 prehashing, configure NSD with --disable-full-prehash. Thanks Secure64 for the patch. BUG FIXES: - Bugfix #302: nsd accepts XFR but refuses to re-read the slave zone. - Bugfix #365: set patch style and zonec verbose for nsdc. - First step of bug #369: RRSIG DNSKEY sets zone to be treated DNSSEC. - Bugfix #375: typos in nsd.conf.5. - Bugfix #381: Binary escaped and transfers. - Bugfix #397: Don't allow relative domain names as origin in $INCLUDE directives. - Fix printout of IPSECKEY by nsd-patch. - Fix is_existing flag for ENT when domain that has a shared ENT is deleted by IXFR. (ENT == Empty Non-Terminal) - Fix bug if the zonefile is changed for a secondary but stored transfers are applied, and stop it from applying ixfr to empty zone. The zone is flagged with error and AXFR-ed. - Fix to have no authority NS set processing for CNAMEs. - Fix nsd-checkconf to check tsig algorithms properly. - Set the AA bit on responses that have an authoritative CNAME. - Fix denial of existence response for empty non-terminal that looks like a NSEC3-only domain (but has data below it). OPERATIONAL NOTES: - nsd.db version number increased because NSD 3.2.7 and earlier zonec is not compatible due to the TXT strings change. Please run nsdc rebuild before running NSD 3.2.9 and later versions. 3.2.8 ============= BUG FIXES: - Do setusercontext() before chroot(), otherwise login.conf etc. are required inside chroot. - Bugfix #216: Fix leak of compressiontable when the domain table increases in size. - Bugfix #348: Don't include header/library path if OpenSSL is in /usr - Bugfix #350: Refused notifies should log client ip. - Bugfix #352: Fix hard coded paths in man pages. - Bugfix #354: The realclean target deletes a bit too much. - Bugfix #357, make xfrd quit with many zones. - Bugfix #362: outgoing-interface and v4 vs. v6 leads to spurious warning messages. - Bugfix #363: nsd-checkconf -v does not print outgoing-interface ok. - Bugfix: nsd-checkconf -o outgoing-interface omits NOKEY. OPERATIONAL NOTES: - Use 'make clean' to clean up files that make created. - Use 'make realclean' to also clean up files that were generated by running ./configure. - Use 'make devclean' to also clean up autoconf, autoheader files. 3.2.7 ============= BUG FIXES: - Bugfix #253: Don't put NS RRs in a response with QTYPE=DS. - Bugfix #320: use arcrandom(4) for QID generation if available. - Bugfix #328: nsd-checkconf overrun. - Bugfix #343: nsdc update fix. - Bugfix #347: Wrong NSEC3 returned for nodata response QTYPE=DS no delegation. - Bugfix: Allow for huge amount of strings in TXT (and other) records. - Bugfix: nsdc can now deal with tsig algorithms other than hmac-md5. - Fixed several parts in the documentation, including #306, #345. 3.2.6 ============= BUG FIXES: - Bugfix #314: correctly print NSEC next field, escape spaces and fix label overflows. FEATURES: - Expand command line option '-a' and config option 'ip-address:' with port number. OPERATIONAL NOTES: - Configure options --disable-dnssec, --disable-nsid, --disable-tsig are removed. - Configure option --max-interfaces is renamed to --max-ips. 3.2.5 ============= BUG FIXES: - NSD will not start if chroot is configured, but changing root is not possible (it used to ignore the badly configured chroot). - Make use of the more secure strl* functions. - Bugfix #303: spelling error. FEATURES: - New option 'nsid:', to specify the NSID (Bugfix #298). - The default chroot can be set with --with-chroot=

. If not set, by default chroot will not be used (thanks Jakob Schlyter). - Optimized zonec and b64_pton compatibility code (thanks Martin Svec). - Optimized memory allocations. Use mmap/munmap instead of malloc/free. Experimental, by default off. Enable it at build time with --enable-mmap (thanks Martin Svec). OPERATIONAL NOTES: - NSID support is now enabled by default. 3.2.4 ============= BUG FIXES: - Bugfix #269: Additional C99 syntax. - Bugfix #276: Zonec prints debug data to stderr. - Bugfix #286: Document verbosity levels in nsd.conf manual page. - Bugfix #288: Ignore SIGHUP to child processes. - Fix typo in include file for setusercontext. FEATURES: - Support DLV records. - New option 'tcp-query-count:', to limit the maximum number of DNS queries on a single tcp connection. - New option 'tcp-timeout:', to override the default tcp timeout. The default can also be set at build time, --with-tcp-timeout=. - New option 'notify-retry:', to configure how many times NSD should retry a NOTIFY message. - New options 'ipv4-edns-size:' and 'ipv6-edns-size:'. to set your preferred EDNS buffer size. OPERATIONAL NOTES: - UDP/IPv4 sockets have new options set that will disable the DF flag in IP packets. 3.2.3 ============= BUG FIXES: - Bugfix #236: Allow RRs before the SOA in a zonefile. - Bugfix #249: Remove the C99 code. - Bugfix #253: Don't put NS RRs in a response with QTYPE=DNSKEY. - Bugfix #263: Make TSIG algorithm comparison case insensitive. - Bugfix #266: Build failed on systems without strptime. - Bugfix: install hickup. - Fix to use 4096 EDNS limit for IPv6 on Linux. 3.2.2 ============= BUG FIXES: - Off-by-one buffer overflow fix while processing the QUESTION section. - Return BADVERS when NSD does not implement the VERSION level of the request, instead of 0x1. - Bugfix #234. - Bugfix #235. - Reset 'error occurred' after notifying an error occurred at the $TTL or $ORIGIN directive (Otherwise, the whole zone is skipped because the error is reset after reading the SOA). - Minor bugfixes. 3.2.1 ============= OPERATIONAL NOTES: - NSD will now fallback to AXFR, only if the master does not support IXFR. - You can adjust nsdc patch to skip textfile patching. This will increase the patching process, but will not output to zonefiles anymore. By default, this is off. BUG FIXES: - When configuring, don't do strptime test when cross-compiling. - Bug #230: Output non-error messages to stdout. - Better error message when ixfr.db old file format is read. - Bug #218: shared UDP query for all interfaces. - Bug #222: Remove bashism from nsdc script. - Nicer check for SHA-256 functionality. - Fixed some minor memory leaks that occurred on reload. - nsdc: check if a lockfile has not gone stale, when lock failed. - Bugfix strptime compatibility function FEATURES: - New configuration option 'allow-afxr-fallback', "yes" by default. If set to "no", NSD will never do AXFR fallback, even if the master does not support IXFR. - Allow file rotation on nsd.log. - The new nsd-patch options -s and -o allows you to skip writing zonefiles and store the output directly to a database file, respectively. 3.2.0 ============= OPERATIONAL NOTES: - Format of ixfr.db has changed. When you are planning an upgrade to the new NSD release, make sure to process the old ixfr.db before starting the new release (by running nsdc patch). - IXFR is transmitted over TCP by default instead of UDP. If you want to continue the use of IXFR/UDP, please modify your zone configuration file to: request-xfr: UDP 1.2.3.4 tsigkey We strongly recommend to enable TSIG if you send IXFR over UDP. When all masters fail to transmit IXFR/UDP, slave will fallback to IXFR/TCP and eventually AXFR/TCP. - nsd-patch prints errors to stderr instead of stdout. BUG FIXES: - Only normalize dnames in rdatas when rrtype is listed in RFC 4034, section 6.2: Canonical RR Form, following draft-ietf-dnsext-dnssec-bis-updates (affects RRSIG and NSEC records). - Typo in zonec manpage. - Bugfix in log_finalize. - Fix race condition between nsdc patch and server reload. FEATURES: - AXFR/TCP fallback in case of failing IXFR zone transfers. - RFC 4635: support for hmac-sha1 and hmac-sha256 TSIG algorithm identifiers, "Bugfix #130". - Configure the source ip-address for notifies (master) and zone requests (slave) in nsd.conf, "Bugfix #148". - nsd-notify and nsd-xfer allow you to configure the outgoing hostname and source port, in addition to the source address. - Additional debug and verbose log messages. 3.1.1 ============= BUG FIXES: - Try to avoid race conditions with NSD reloading and nsdc running, by writing pidfile before closing old parent process. - Fixed NSEC3 memory leak in the case NSEC3 is not needed. - Fixed some memory leaks that happened on error, mostly on zone transfer errors. - Bugfix #191: nsd-checkconf allowed only (max_interfaces-1) interfaces. FEATURES: - The number of maximum interfaces allowed is configurable with --with-max_interfaces= (thanks John Lightsey). 3.1.0 ============= OPERATIONAL NOTES: - Default locations of nsd.db, ixfr.db & xfrd.state are changed to the /var/db/nsd directory. BUG FIXES: - Zone compiler gives more sane error messages when out of diskspace and bug #172: when compiling single zone file. - Changed man pages format from mdoc to mansun, to support the Solaris OS. - Log tcp read error only when connection not reset by peer or when verbosity level is high. - RRs are compared without checking the TTL value. FEATURES: - NSD is now NSEC3 enabled by default. You can disable it by configuring NSD with --disable-nsec3. - Added "hide-version" configuration setting. Enabling this feature stops NSD from answering to CHAOS class version requests. - Added bind2nsd 0.5.0 (http://bind2nsd.sourceforge.net) in contrib/. - Report source and zone for denied AXFR attempts. 3.0.8 ============= FEATURES: - Better logging for nsd-notify (show 'broken' zone) - Add configuration for chkconfig to control nsd service. BUG FIXES: - Fixed nsdc start when nsd already running: do not initialize server, since it is already running. - Fixup bug where data related files are looked up in the wrong directory when chrooted with chrootdir ending with a slash. - Fixup bug where nsd would return FORMERR if received an edns query with version set to zero and rdlen larger than zero. - Fixed strptime, so that zonec will also work on systems with broken strptime (like leopard :-)) - Do not answer nsec3 wildcard information when DO bit is not set - Better logging when creating database failed. - Various spelling errors 3.0.7 ============= BUG FIXES: - Error handling for malformed IXFRs improved. - Fixed man pages, consistent syntax. 3.0.6 ============= FEATURES: - Report source and zone for denied AXFR attempts. BUG FIXES: - More elegant handling of malformed nsec3 records from a zone transfer. - Fixup ignored return value in region-allocator. - Added bind2nsd 0.5.0 (http://bind2nsd.sourceforge.net) in contrib/. 3.0.5 ============= BUG FIXES: - Fixed problem with reload waiting very long. If the OS has a raging herd problem, NSD could block in a UDP operation and that process would stop reload from finishing. Made UDP sockets nonblocking. - Made TCP listen sockets nonblocking. NSD could block in accept. - Handle the new CERT RDATA types defined in RFC 4398 (submitted by Mans Nilsson). - Fixed a bug where zonec would choke on unknown CERT RDATA types. - Change nsd-notify retry timer from linear into exponential backoff (submitted by Mans Nilsson). - Debug flag (-d) behavior changed. Nsd now also forks children when run in debug mode. - Added verbosity mode (-V ) for extra operational logging. - zonesdir default is /etc/nsd. This can be overridden in nsd.conf. - if clients drop the tcp connection this does not result in a logfile entry, unless verbosity is set 2 or more. 3.0.4 ============= BUG FIXES: - zonec will print an error when other data is put next to a CNAME. - Fixup unaligned memory access that could occur when reading ixfr.db with a partial transfer inside. - Fixup for the WKS RR type printout by nsd-patch and nsd-xfer. - Error message 'could not read database CRC' now only given on error. - ./configure --zonesdir= now works to set a default value for the zonesdir: nsd.conf directive. Set zonesdir: "" to disable the change of directory. - Bug: reload crashes with log message 'continuing with old database', and after that no more zone updates. Manual fix is to kill -HUP, but now fixed in software to try to reload again (and again). - Small speedup where xfrd could briefly be busy-waiting. - If master sends IXFR with glue that is already present in the zone this is silently accepted. Printed in debug mode -L 2. To make the log file smaller. - Exponential backoff for zones that never worked to max of 4 hours. For expired zones the SOA retry values are used. - allow-notify acl entries 'NOKEY' match only queries without TSIG. - Answers to valid notifies contained wrong RR counts in the header. The notifies were processed correctly, but now the acknowledgement reply is in correct DNS format. FEATURES: - Added contrib/nsd.zones2nsd.conf python script to convert NSD 2 to NSD 3 config files, contributed by Stephane Bortzmeyer. - The nsdc control script will print 'nsd startup failed' if the nsd executable does not start (due to bad permissions, bad config, ...). 3.0.3 ============= BUG FIXES: - Bug #152: NSD would not use the identity from nsd.conf, fixed. - Bug #153: When running with thousands of secondary zones, NSD would run out of UDP sockets. Caused crash on FreeBSD, errors on Linux ('out of file descriptors'), depending on ulimits. Fixed. - Fixed getaddrinfo error message to be more descriptive. - Fallback to ip4 if getaddrinfo fails for ip6. - Will no longer lose a notify message during reloads (IPC). - Will no longer lose transfer in progress when notified for that zone. - Nicer error when operator forgets to rebuild after deleting a zone. 3.0.2 ============= BUG FIXES: - Nice error from zonec on a wrong configuration zone name. - Nicer warning from zonec when starting secondary zone with no zone file for the first time. - nsdc makes more portable use of 'which' (for SunOS5.9/bash2.05). - Bug #143: Improved handling of zonesdir: directive and relative pidfile, database, diff file, xfrdfile paths in nsdc.sh and nsd-patch. They would not find the files. - Bug #144: LOC RRtype default values for precision wrong. Fixed. - Bug #145: NSD failed to reload cases of simultaneous zone transfer. - Bug #146: NSD fails to write to xfrdfile when chrooted. Fixed. Also fix for difffile when chrooted. - Bug #147: NSD runs out of memory. Fixed, memory is reused. Occurred when running NSD with very big zones and large updates. - nsd -L 1 logging is smaller, -L 2 contains all debug information. (only available for debug compiles). - Bug #149: Fixed text for NOTAUTH error code. When notify is not authorised REFUSED error code returned instead. 3.0.1 ============= BUG FIXES: - nsd-patch prints SOA record at start of zone files. 3.0.0 ============= FEATURES: - AXFR/IXFR zone transfer supported. - NSD requests but does not provide IXFR transfers. - NSD keeps track of SOA timeouts for secondary zones. - TSIG authentication supported. - For queries, for notifies, for zone transfers. - NOTIFY messages of zone updates, incoming and outgoing. - DNAME type is supported, including CNAME synthesis. - config file, nsd.conf(5), place to put TSIG keys, server settings, and lists of ip-addresses/ranges for AXFR/IXFR and NOTIFY. - prepared for NSEC3 (--enable-nsec3), experimental code for testing in workshops. - prepared for NSID (--enable-nsid), experimental code for testing in workshops. OPERATIONAL NOTES: - config file needed, nsd.conf(5) supersedes nsd.zones and nsdc.conf. - AXFR transfers are denied by default. Allow in config file. - Zones only become secondary with "request-xfr:" items in config file. - NSD produces "ixfr.db" file with a journal of zone transfers. Use nsdc patch to merge changes back to zone files and remake db. - NSD produces "xfrd.state" file with zone timeout information. The file is text formatted. - NSD sends notifies automatically, nsd-notify is deprecated and will be removed from the package. - NSD requests AXFR/IXFR and reloads the updates automatically, nsd-xfer is deprecated and will be removed from the package. - Check your config file with nsd-checkconf. BUG FIXES: - contains all bug fixes from 2.3.5 and before. - The sighandler() bug is fixed more thoroughly, by using pipes for interprocess communication. - CNAMEs are followed by the server to different zones and information from that zone is returned. This saves a followup query. - bug fixes (ported) 2.3.6. - nsd-notify will retry max 15 times 5 second retries. - Bug #105: nsdc lacks locking, fixed locking for root user. - Bug #134: nsd: make -N work again - Bug #135: Typo in locking code for nsdc, fixed. - uninitialised variable fixed. - unaligned memory access (on Solaris SPARC), in zonec LOC parsing, fixed. - Bug #138: nsd aborts trying to bind all interfaces if ip6 is not enabled, instead it will fallback to ip4. - Bug #139: resync timer for stats to whole minute. - Bug #140: NSD did not clear CD bit on authoritative answers. - Bug #141: NSD did not clear flags on a formerror reply. 2.3.5 ============= BUG FIXES: - Bug #132: regression, nsd: fix compile with --disable-ipv6 - Makefile: remove gnuisms 2.3.4 ============= BUG FIXES: - Unknown type codes for type code numbers > 48 and < 97 work again. (this implies --enable-checking can be enabled again) - nsd: sighandler() fixes - Bug #118: nsd: nsd_notify waits for a response. Will retry the notify after a timeout. - Bug #124: $(DESTDIR) was added to Makefile.in. - Bug #128: zonec: parser can handle \\ at the end of a string. - zonec: lexer: add \r to the newline delimeter - zonec: use strtol with an explicit base 10 as parameter. (Scott Rose, Roy Arends) - nsd-xfer: print human readable error codes. Change logging to be more in line with the rest 2.3.3 ============= BUG FIXES: - Apply the correct patch to nsdc.sh.in. 2.3.2 ============= FEATURES: - Bug #101: add support for the SPF record. BUG FIXES: - Bug #100: replaced non-portable use of timegm(3) with portable implementation (mktime_from_utc). - Bug #103: nsd: trim the SOA's TTL to the MINIMUM value when returning a negative answer. - Bug #104: nsd: add a time_t timestamp to the log when logging to a file. - Bug #105: nsdc: use a lock file when rebuilding the database (patch by Jakob Schlyter/Ted Lindgreen/Sebastian/Ondrej Sury). - Bug #106: zonec: don't walk all 256 NSEC windows when that is not needed. - Bug #107: zonec: fixed a crash when encountering bad unknown rdata. - nsd: Don't print: "error: nsd is already running as , stopping" when in fact NSD continues to run. - nsd: Minimize the race window in sig_handler(). 2.3.1 ============= BUG FIXES: - zonec: Don't crash when generating error messages outside of zone files. - nsd: when logging to a file the pid is now printed. - nsd: Reset 'boot' time in statistics when reloading the database, since the statistics are reset to 0 on a reload. - nsd-xfer.c: Added '-a' option to specify local address to connect from. Original patch supplied by Walter Hop . - Bug #98: Allow mnemonics for DS and RRSIG algorithm field. 2.3.0 ============= FEATURES: - DNSSEC is now enabled by default. NSD should be fully compliant with RFC4033, RFC4034, and RFC4035. BUG FIXES: - nsd: Ensure that the number of -a flags does not exceed the maximum specified by MAX_INTERFACES in config.h. - nsd-xfer: Use serial number arithmetic (RFC1982) for the zone serial check - nsdc: Don't pass (fake) serial number to nsd-xfer if the zone file does not exist. - zonec: Loading many zones would cause namedb_find_zone to slow down, performance patch by Kazunori Fujiwara. - Bug #96: nsd-xfer did not handle 8-bit domain names correctly. 2.2.1 ============= FEATURES: - The message priority is now included when logging to a file. BUG FIXES: - Zero length RDATA using the unknown RR notation was not working (except for the APL RR type). - Bug #93: './configure' error message containing a comma must be properly bracketed. - Bug #94: nsd-xfer: Handle unexpected EOF when receiving AXFR data. Timeout if no data is received for more than 120 seconds (see the TCP_TIMEOUT parameter in config.h). - Bug #95: An owner starting with an asterisk label ("*") was being treated as its own wildcard child. 2.2.0 ============= FEATURES: - nsd-xfer: replacement program for named-xfer to perform zone transfers using AXFR. TSIG is supported by nsd-xfer but not yet by the nsd server. DNSSEC is also supported. TSIG requires OpenSSL version 0.9.7 or higher, configure using --disable-tsig if you do not have OpenSSL installed. Configure using --with-ssl=path if OpenSSL is not installed at a standard location. CODE CHANGES: - New data structure 'buffer_type' for representing binary buffers that can be read, written, and resized. Data in these buffers is stored in network byte order. This data structure replaces the iobuf field of 'struct query'. BUG FIXES: - Fixed endian problem in WKS record. - Protocol can now be specified numerically in WKS record. - Allow escape sequences (\DDD) in TTL, RR class, and RR type. - The zone compiler now accepts many more characters in unquoted strings such as domain name labels. The characters no longer need to be escaped with a backslash. - Close included files after reading. - Maximum TCP message size is now 65535 bytes. AXFR response packets are still limited to 16383 bytes for optimal compression of dnames. - The TSIG key for AXFRs can now also be stored in the file .tsiginfo. This makes it possible to use TSIG with multiple master servers. - Signals are no longer blocked while performing I/O so the server should respond quicker to signals. - Fixed parsing of LOC rdata. Fractions and altitude were not handled correctly. 2.1.5 ============= BUG FIXES: - Bug #90: handle \000 in TXT records correctly - Fixed undefined behavior in the use of vsnprintf when logging messages. This caused crashes on Linux/PPC. 2.1.4 ============= BUG FIXES: - nsdc: Fixed a typo that caused AXFRs to stop working. 2.1.3 ============= FEATURES: - nsd: The pidfile can be specified using the '-P' option. BUG FIXES: - Bug #87: allow @ in the rdata - Bug #88: allow ::FFFF:ipv4addr in AAAA records - Bug #89: Count the number of queries received over TCP, instead of the number of TCP connections. - Zonec: when - is used as input, set the filename to 'STDIN'. - The nsdc script handles failed AXFRs more gracefully. - NSD emits an error when it sees bitlabels (RFC 2673). - Only copy the CD bit when DNSSEC is enabled. 2.1.2 ============= FEATURES: - NSD now fully supports unknown record types using the notation specified in RFC3597. - Support for the following RR types has been added: WKS, X25, ISDN, RT, NSAP, PX, NAPTR, KX, CERT, DNAME, and APL. DNAME special processing is not supported. BUG FIXES: - Bug #84: NSD now uses SIGUSR1 instead of SIGILL to report stats. - Bug #85: Support for WKS records. - Bug #86: The characters "#%&^[]?" can now be used without backslash in zone file domain names. - Plugin callback return type fixed. - The maximum message length for IPv6 UDP packets is now limited to the IPv6 minimum MTU (1280) unless the IPV6_USE_MIN_MTU socket option is supported. 2.1.1 ============= BUG FIXES: - Bug #81: Handle unknown types correctly. - Bug #82: Zonec: don't report "0 errors" unless -v is specified. - Bug #83: Close zone files after parsing. - Handle AFSDB RR type. 2.1.0 ============= FEATURES: - New networking code allows a single server to handle both UDP and TCP connections. By default up to 10 simultaneous TCP connections are supported. Use the '-n' flag to change the default. 2.0.2 ============= BUG FIXES: - Allow the use of a mnemonic for the algorithm field of a DNSKEY record. - Behavior of the zonec -v flag has been modified. By default zonec will only print a single line with a summary of the error count. - Bug #75: Fixed typo in previous "fix". 2.0.1 ============= BUG FIXES: - Queries for QTYPE DS (DNSSEC) were not handled correctly in certain cases. - Partial support for unknown RRs. Known RR types with unknown RR data format is not yet supported. - Bug #75: Fixed bad error message when nsdc update is run for the first time. - Bug #78: Multiple zones, each with include directives, are now compiled correctly. 2.0.0 ============= FEATURES: - Experimental DNSSEC support implemented, but disabled by default. Enable using the --enable-dnssec configuration option. - IPv6 enabled by default. Disable using the --disable-ipv6 configuration option. BUG FIXES: - Bug #47: Domain name is now logged when a notify is received. - Bug #70: First include all A records in the additional section, followed by AAAA records. - Bug #77: Check length of domain name and label. - LOC records are supported again. 1.4.0-alpha1 ============= FEATURES: - New database format that is much more compact and portable across architectures. - The new zone compiler is now the default and the old zone compiler has been removed. - Name compression is done dynamically, removing one other difference with BIND in the responses generated (the full query name is now used for compression). - CNAME target records are now generated from wildcard records if necessary. REGRESSIONS: - mmap(2) isn't currently supported. - Not all RR types are supported by zonec (such as LOC). 1.3.0-alpha1 ============= FEATURES: - New name lookup algorithm. This required a change to the database format. Performance should increase at the expense of database size and memory usage. - New zone compiler (zonec2) based on flex and yacc, fully RFC compliant (still in alpha). - Database can be loaded using mmap(2) (use the --enable-mmap configure option to enable). This is useful on operating systems such as Solaris that do not allow memory overcommit. - Region based memory allocation and resource management. - New internal format for storing domain names. Each dname now includes an array of label offsets within the domain name. - Updates to the plugin API. BUG FIXES: - Bug #65: The syslog facility is now a compile time option (--with-facility=FACILITY). The default facility is DAEMON. - Bug #66: Automatic periodic dumping of the statistics (using the -s option) is now continued after a database reload. 1.2.4 ============= BUG FIXES: - Bug #72: If an RRset for a child domain is defined before the RRset of the parent domain the parent's RRset would be "lost". 1.2.3 ============= BUG FIXES: - Bug #65: The syslog facility is now a compile time option (--with-facility=FACILITY). The default facility is DAEMON. - Bug #66: Automatic periodic dumping of the statistics (using the -s option) is now continued after a database reload. - NSD would try to kill pid -1 on startup if forking of a child process failed. - Do not log EAGAIN errors on calls to recvfrom. These errors should be harmless. 1.2.2 ============= BUG FIXES: - Bug #59: NSD returns FORMERR when the query name is >= 246 bytes. - Bug #60: Zonec runs out of file descriptors with many zones. - Bug #61: nsdc uses /bin/sh hardwired (and should not). - Bug #62: NSD is not able to log to a file. - Bug #63: nsdc update and zonec are too talkative. - Bug #64: Answer for request of a host resolved by a wildcard-resource-record is not understandable by dig. 1.2.1 ============= BUG FIXES: - AXFR terminates early if a zone contains a CNAME pointing the the zone's domain name (SOA record) (bug #56). - During an AXFR memory above the top of the stack was accessed. This could lead to occasional AXFR errors (bad packets). - NSD now prints its version number and exits when invoked with the -v flag (bug #57). - NSD prints help information and exits when invoked with the -h flag. 1.2.0 ============= FEATURES: - NSD is now a single parent process (handling child termination and database reloads) plus multiple UDP and TCP child processes handling queries. Before the parent process also handled UDP queries. This change simplifies the parent and child processes and allows the use of multiple concurrent UDP servers. - Experimental plugin support. This required a minor, incompatible change to the database format. Make sure you recompile your database. Use --enable-plugins to enable. - Full IPv6 support (for multi-homing and for Linux, thanks to Colm MacCárthaigh and Jun-ichiro itojun Hagino). Use --enable-ipv6 to enable. - Support for multi-homing with TCP connections. - Support for SunOS 4.x has been dropped. CODE CHANGES: - NSD should now conform to the Single Unix Specification (http://www.unix.org/). - Const correctness for strings and some other data types. - Removed code for Berkeley DB, hash tables, and mmap(2). - Separate preprocessor flags from code flags (CPPFLAGS and CFLAGS). - Use uint8_t instead of u_char, uint{16,32}_t instead of u_int{16,32}_t. - Fixed warnings from mixing signed and unsigned types. - Use sigaction(2) instead of signal(2). - The query_process function has been split up for clarity. BUG FIXES: - CHAOS TXT queries failed on big-endian machines. - Portability fixes for Tru64 (thanks to Stephane Bortzmeyer), HP-UX, and MacOS X (thanks to Ronald van der Pol). - Removed compile time limit on maximum number of TCP child servers. - Support for debugging UDP and TCP queries. - Always ensure there is enough room for the EDNS record when answering a query with EDNS enabled. 1.1 ============= FEATURES: - ANSI C - autoconf/configure - new parser - support for various RR types in zonec - support for UNKN RR types BUG FIXES: - lots of zone parsing errors eliminated - empty node matching bug gives NXDOMAIN 1.0.3 ============= This release is a bug fix release and does not add any new features. BUG FIXES: - Ignore SIGPIPE errors (bug #43). - Keep track of TCP child servers and restart if necessary. (bug #55) - Handle database reload failures correctly. - Close UDP sockets in TCP child servers. - Handle escaped characters (besides \.) in labels. - Preserve the query's RD flag in the answer. 1.0.2 ============= FEATURES: - -DBIND8_STATS to enable bind8 like [NX]STATS - -t flag to make nsd chroot to a certain directory - -s flag to make nsd produce statistics every s seconds - /etc/nsd/nsdc.conf to overwrite default variables for nsdc.sh - less loggin and more radical tcp connection (mis)handling - prefork -n processes to handle tcp connections - multiple -a flags CHANGES: - named.stats file functionality is removed BUG FIXES: - couple of pedantic fixes in C code - last zone in database axfr bug fixed - nsdc update wont update bug fixed 1.0.1 ============= FEATURES: - NSD drops permissions after binding the sockets - ``cache'' zones are no longer allowed - ID.Server & Version.Server compile time options - AXFR implemented (with tcpwrapper for access control) - nsdc update and nsdc notify functionality - using named-xfer with TSIG for inbound axfr CHANGES: - the order of records in the database is from now on significant - since Berkeley DB doesnt define order for sequential access it is no longer supported BUG FIXES: - white space problem in zonec is fixed KNOWN BUGS: - please see appropriate man pages for the known bugs 1.0.0 RELEASE ============= KNOWN BUGS: - Although NSD allows one to configure a zone without SOA record and use it as so called ``cached'' non-authoritative data, it is decided that having this functionality is wrong, dangerous and will be removed from the further versions. - If while processing EDNS(0) OPT record NSD encounters bad EDNS(0) version it will answer with Format Error instead of EDNS(0) BADVERS PLATFORMS: Tested and working on i386 FreeBSD-4.4, i386 Linux, dec alpha Linux, sparc SunOS 4.x 1.0.0-BETA2 =========== FIXES: - wildcards bug fixed - AA bit for class ANY bug fixed - minor coredumps with really broken zones in zonec fixed - linux & SunOS port 1.0-ALPHA2 ========== FIXES: - IPv6 transport support added by Jun-ichiro itojun Hagino (Use -DINET6) - Makefile modified for easier compile time configuration - EDNS(0) bug fixed - Default database changed to all lowercase, red-black tree to make nsd DNSSEC ready - REQUIREMENTS are cleaned up and updated - Signal names changed in nsdc.sh.in - Default compile options dont include -DMIMIC_BIND8 nsd-4.12.0/doc/README.svn0000644000175000017500000000175115002373054014233 0ustar mozziemozzieIf you build NSD directly from the Subversion repository, you will need the (gnu) autotools to generate the configure script. On most systems, this can simply be done by using autoreconf: autoreconf -fi This will call autoconf, autoheader, aclocal etc. After this you can build normally with configure and make, see the general README for further information on this. Some systems do not have a symlink to separate versions, so you will have to use the specific version name. It should work with at least 2.53 and 2.59. The actual executable name may differ on various systems, most of the times it is either called autoreconf-2.59 or autoreconf259 Some systems also do not have a standard aclocal link, in which case you will have to tell autoreconf what aclocal executable to use. This can be done by setting the ACLOCAL environment variable. It should work with aclocal 1.4, 1.5 and 1.9. Examples of complete commands: ACLOCAL=aclocal19 autoreconf259 ACLOCAL=aclocal-1.9 autoreconf-2.59 nsd-4.12.0/doc/README.icc0000644000175000017500000000144615002373054014164 0ustar mozziemozzieCompiling with the Intel C Compiler (ICC) version 7.0. Configure NSD to use ICC. $ CC=icc ./configure [configure-options] Then everything should compile (just ignore the warnings), except on RedHat 8.0. This is due to a bug in the GNU C library used. This bug may apply to other Linux distributions or systems using the GNU C library. To compile NSD with the ICC compiler on RedHat 8.0 you need to patch the file /usr/include/bits/byteswap.h. The following patch should work: --- byteswap.h.orig 2003-02-26 13:59:41.000000000 +0100 +++ byteswap.h 2003-02-26 13:59:57.000000000 +0100 @@ -81,7 +81,7 @@ __v; })) # endif #else -# define __bswap_16(x) \ +# define __bswap_32(x) \ (__extension__ \ ({ register unsigned int __x = (x); __bswap_constant_32 (__x); })) #endif nsd-4.12.0/doc/README0000644000175000017500000010262715002373060013427 0ustar mozziemozzie1.0 Introduction 1.1 ... Basic theory of operation 1.2 ... Quick build & install 2.0 Building nsd 2.1 ... Unpacking the source 2.2 ... Configuring NSD 2.3 ... Building 2.4 ... Installing 3.0 Running NSD 3.1 ... Logging 3.2 ... AXFR access 3.3 ... Using TSIG 3.4 ... Zone expiry of secondary zones 3.5 ... Diagnosing NSD log entries 3.6 ... Interfaces 3.7 ... Tuning 3.8 ... Zone verification 4.0 Support and Feedback 4.1 ... Your Support 1.0 Introduction This is NSD Name Server Daemon (NSD) version 4.12.0. The NLnet Labs Name Server Daemon (NSD) is an authoritative RFC compliant DNS nameserver. It was first conceived to allow for more genetic diversity for DNS server implementations used by the root-server system and it has been developed for operations in environments where speed, reliability, stability, and security are of high importance. NSD is currently used on root servers such as k.root-servers.net and is also in use by several top-level domain registries. NSD is a complete implementation of an authoritative DNS name server. For further information about what NSD is and what NSD is not please consult the REQUIREMENTS document which is a part of this distribution. If you are a BIND user (the named daemon) consult NSD_FOR_BIND_USERS. The source code is available for download from: http://www.nlnetlabs.nl/downloads 1.1 Basic Theory of Operation NSD consists of two programs: the zone compiler 'zonec' and the name server 'nsd' itself. The name server works with an intermediate database prepared by the zone compiler from standard zone files. For NSD operation this means that zones have to be compiled by zonec before NSD can use them. All this can be controlled via rc.d (SIGTERM, SIGHUP) or nsd-control, and uses a simple configuration file 'nsd.conf'. 1.2 Quick build and install Step 1: Unpack the source with gtar -xzvf nsd-4.12.0.tar.gz Step 2: Create user nsd or any other unprivileged user of your choice. In case of later make sure to use --with-user= while running configure. You can also set "username: " in the nsd.conf file later. Install openssl and libevent. Step 3: ./configure Step 4: make all (or simply 'make'). Step 5: make install Step 6: Create and edit /etc/nsd/nsd.conf file possibly from nsd.conf.sample template that comes with the distribution. (installed by default at /etc/nsd/nsd.conf.sample) Here you need to configure the zones you want to serve. TSIG keys used for secure zone transfers must be included. Also server parameters can be set, see nsd.conf(5) man page. If you have a NSD 2 nsd.zones config file take a look at the python script contrib/nsd.zones2nsd.conf, it will convert zone and TSIG key settings for you. Step 7: Copy necessary master zone files into appropriate directories under /etc/nsd/primary & /etc/nsd/secondary. Step 8: Run nsd-control start Step 9: Test the NSD with dig, drill or host. Step 10: If you're happy add a rc.d script to start into your OS boot up sequence. The format of the rc.d startup script depends on the platform. Also stop it in the shutdown sequence. You can use SIGTERM to stop, or nsd-control stop. Step 11: If desired add 'nsd-control write' to your superuser crontab to update the zone files with the content transferred from master servers periodically, such as once per day. Got any problems or questions with the steps above? Read the rest of this file. 2.0 Building NSD 2.1 Unpacking the source Use your favorite combination of tar and gnu zip to unpack the source, for example $ gtar -xzvf nsd-4.12.0.tar.gz will unpack the source into the ./nsd-4.12.0 directory... 2.2 Configuring NSD NSD can be configured using GNU autoconf's configure script. In addition to standard configure options, one may use the following: CC=compiler Specify the C compiler. The default is gcc or cc. The compiler must support ANSI C89. CPPFLAGS=flags Specify the C preprocessor flags. Such as -I. CFLAGS=flags Specify the C compiler flags. These include code generation, optimization, warning, and debugging flags. These flags are also passed to the linker. The default for gcc is "-g -O2". LD=linker Specify the linker (defaults to the C compiler). LDFLAGS=flags Specify linker flags. LIBS=libs Specify additional libraries to link with. --enable-root-server Configure NSD as a root server. Unless this option is specified, NSD will refuse to serve the ``.'' zone as a misconfiguration safeguard. --disable-ipv6 Disables IPv6 support in NSD. --enable-checking Enable some internal development checks. Useful if you want to modify NSD. This option enables the standard C "assert" macro and compiler warnings. This will instruct NSD to be stricter when validating its input. This could lead to a reduced service level. --enable-bind8-stats Enables BIND8-like statistics. --enable-ratelimit Enables ratelimiting, based on query name, type and source. --enable-draft-rrtypes Enables draft RRtypes. --with-configdir=dir Specified, NSD configuration directory, default /etc/nsd --with-nsd_conf_file=path Pathname to the NSD configuration file, default /etc/nsd/nsd.conf --with-pidfile=path Pathname to the NSD pidfile, default is platform specific, mostly /var/run/nsd.pid --with-zonesdir=dir NSD default location for master zone files, default /etc/nsd/ --with-user=username User name or ID to answer the queries with, default is nsd --with-facility=facility Specify the syslog facility to use. The default is LOG_DAEMON. See the syslog(3) manual page for the available facilities. --with-libevent=path Specity the location of the libevent library (or libev). --with-libevent=no uses a builtin portable implementation (select()). --with-ssl=path Specify the location of the OpenSSL libraries. OpenSSL 0.9.7 or higher is required for TSIG support. --with-start_priority=number Startup priority for NSD. --with-kill_priority=number Shutdown priority for NSD. --with-tcp-timeout=number Set the default TCP timeout (in seconds). Default 120 seconds. --disable-nsec3 Disable NSEC3 support. With NSEC3 support enabled, very large zones, also non-nsec3 zones, use about 20% more memory. --disable-minimal-responses Disable minimal responses. If disabled, responses are more likely to get truncated, resulting in TCP fallback. When enabled (by default) NSD will leave out RRsets to make responses fit inside one datagram, but for shorter responses the full normal response is carried. --disable-largefile Disable large file support (64 bit file lengths). Makes off_t a 32bit length during compilation. 2.3 Building Use ``make'' to create NSD and support tools. If you get errors, try to use ``gmake'' (gnu version of make), especially on old systems. If so, do a `gmake realclean` first, to remove stuff that the make call messed up. 2.4 Installing Become a superuser (if necessary) and type ``make install'' This step should install four binaries nsd - the daemon itself nsd-control-setup - a shell script that creates keys for nsd-control. nsd-control - program that connects over SSL to nsd and gives commands. nsd-checkconf - simple C program to check nsd.conf before use. Plus the manual pages and a sample configuration file. 3.0 Running NSD Before running NSD you need to create a configuration file for it. The config file contains server settings, secret keys and zone settings. The server settings start with a line with the keyword 'server:'. In the server settings set 'database: ' with the filename of the name database that NSD will use. Set 'chroot: ' to run nsd in a chroot-jail. Make sure the zone files, database file, xfrdfile, difffile and pidfile can be accessed from the chroot-jail. Set 'username: ' to an unprivileged user, for security. For example: # This is a sample configuration server: database: "/etc/nsd/nsd.db" pidfile: "/etc/nsd/nsd.pid" chroot: "/etc/nsd/" username: nsd After the global server settings to need to make entries for the zones that you wish to serve. For each zone you need to list the zone name, the file name with the zone contents, and access control lists. zone: name: "example.com" zonefile: "example.com.zone" The zonefile needs to be filled with the correct zone information for master zones. For secondary zones an empty file will suffice, a zone transfer will be initiated to obtain the slave zone contents. Access control lists are needed for zone transfer and notifications. For a slave zone list the masters, by IP address. Below is an example of a slave zone with two master servers. If a master only supports AXFR transfers and not IXFR transfers (like NSD), specify the master as "request-xfr: AXFR ". By default, all zone transfer requests are made over TCP. If you want the IXFR request be transmitted over UDP, use "request-xfr: UDP ". zone: name: "example.com" zonefile: "example.com.zone" allow-notify: 168.192.185.33 NOKEY request-xfr: 168.192.185.33 NOKEY allow-notify: 168.192.199.2 NOKEY request-xfr: 168.192.199.2 NOKEY By default, a slave will fallback to AXFR requests if the master told us it does not support IXFR. You can configure the slave not to do AXFR fallback with: allow-axfr-fallback: "no" For a master zone, list the slave servers, by IP address or subnet. Below is an example of a master zone with two slave servers. zone: name: "example.com" zonefile: "example.com.zone" notify: 168.192.133.75 NOKEY provide-xfr: 168.192.133.75 NOKEY notify: 168.192.5.44 NOKEY provide-xfr: 168.192.5.44 NOKEY You also can set the outgoing interface for notifies and zone transfer requests to satisfy access control lists at the other end: outgoing-interface: 168.192.5.69 By default, NSD will retry a notify up to 5 times. You can override that value with: notify-retry: 5 Zone transfers can be secured with TSIG keys, replace NOKEY with the name of the tsig key to use. See section 3.3. Since NSD is written to be run on the root name servers, the config file can to contain something like: zone: name: "." zonefile: "root.zone" provide-xfr: 0.0.0.0/0 NOKEY # allow axfr for everyone. provide-xfr: ::0/0 NOKEY You should only do that if you're intending to run a root server, NSD is not suited for running a . cache. Therefore if you choose to serve the . zone you have to make sure that the complete root zone is timely and fully updated. To prevent misconfiguration, NSD configure has the --enable-root-server switch, that is by default disabled. In the config file, you can use patterns. A pattern can have the same configuration statements that a zone can have. And then you can include-pattern: in a zone (or in another pattern) to apply those settings. This can be used to organise the settings. The nsd-control tool is also controlled from the nsd.conf config file. It uses SSL encrypted transport to 127.0.0.1, and if you want to use it you have to setup the keys and also edit the config file. You can leave the remote-control disabled (the secure default), or opt to turn it on: # generate keys nsd-control-setup # edit nsd.conf to add this remote-control: control-enable: yes By default nsd-control is limited to localhost, as well as encrypted, but some people may want to remotely administer their nameserver. What you then do is setup nsd-control to listen to the public IP address, with control-interface: after the control-enable statement. Furthermore, you copy the key files /etc/nsd/nsd_server.pem /etc/nsd/nsd_control.* to a remote host on the internet; on that host you can run nsd-control with -c which references same IP address control-interface and references the copies of the key files with server-cert-file, control-key-file and control-cert-file config lines after the control-enable statement. The nsd-server authenticates the nsd-control client, and also the nsd-control client authenticates the nsd-server. When you are done with the configuration file, check the syntax using nsd-checkconf The zone files are read by the daemon, which builds 'nsd.db' with their contents. You can start the daemon with nsd or with "nsd-control start" (which execs nsd again). or with nsd -c To check if the daemon is running look with ps, top, or if you enabled nsd-control, nsd-control status To reload changed zone files after you edited them, without stopping the daemon, use this to check if files are modified: kill -HUP `cat ` If you enabled nsd-control, you can reread with nsd-control reload With nsd-control you can also reread the config file (new zones, ..) nsd-control reconfig To restart the daemon /etc/rc.d/nsd restart # or your system(d) equivalent To shut it down (for example on the system shutdown) do kill -TERM or nsd-control stop NSD will automatically keep track of secondary zones and update them when needed. When primary zones are updated and reloaded notifications are sent to slave servers. The zone transfers are applied to nsd.db by the daemon. To write changed contents of the zone files for slave zones to disk in the text-based zone file format, issue nsd-control write. NSD will send notifications to slave zones if a master zone is updated. NSD will check for updates at master servers periodically and transfer the updated zone by AXFR/IXFR and reload the new zone contents. If you wish exert manual control use nsd-control notify, transfer and force_transfer commands. The transfer command will check for new versions of the secondary zones hosted by this NSD. The notify command will send notifications to the slave servers configured in 'notify:' statements. 3.1 Logging NSD doesn't do any logging. We believe that logging is a separate task and has to be done independently from the core operation. This consciously is not part of nsd itself in order to keep nsd focused and minimize its complexity. It is better to leave logging and tracing to separate dedicated tools. dnsstat can also easily be configured and/or modified to suit local statistics requirements without any danger of affecting the name server itself. We have run dnsstat on the same machine as nsd, we would recommend using a multiprocessor if performance is an issue. Of course it can also run on a separate machine that has MAC layer access to the network of the server. The nsd-control tool can output some statistics, with nsd-control stats and nsd-control stats_noreset. In contrib/nsd_munin_ there is a munin grapher plugin that uses it. The output of nsd-control stats is easy to read (text only) with scripts. The output values are documented on the nsd-control man page. The CAIDA dnsstat tool referenced is recommended to nsd operators as a means of keeping statistics and check on abnormal query loads. http://www.caida.org/tools/utilities/dnsstat/dnsstat-3.5.1a.tar.gz Another tool is the dnstop, that displays DNS statistics on your network. http://dns.measurement-factory.com/tools/dnstop/src/dnstop-20060517.tar.gz A sample invocation of dnsstat: /usr/local/Coral/bin/crl_dnsstat -D -Ci=60 -Cd=240 -C'filter dst 10.1.1.3' -h -u if:fxp1 A sample output of a slightly modified version: # dnsstat output version: 0.2 "dfk" # begin trace interval at 1025267664.859043, duration 15.000000 # DNS messages: 74973 (4998.200000/s); DNS queries: 151983 (10132.200000/s) # print threshold: 30 messages/sec #src op type class queries msgs rd notes 208.18.162.10 - - - 533 533 0 " 0 MX IN 6 " 0 A IN 264 " 0 ANY IN 263 209.11.18.248 - - - 661 661 0 " 0 A IN 655 " 0 MX IN 6 210.117.65.137 - - - 745 745 0 " 0 A IN 745 216.54.221.131 - - - 477 477 0 " 0 A IN 477 193.97.205.80 - - - 681 681 0 " 0 A IN 3 " 0 ANY IN 678 168.30.240.11 - - - 685 685 0 " 0 A IN 405 " 0 MX IN 280 210.94.6.67 - - - 742 742 0 " 0 A IN 742 63.66.68.237 - - - 1375 1375 0 " 0 A IN 1375 168.30.240.12 - - - 493 493 0 " 0 A IN 493 139.142.205.225 - - - 5579 5579 0 " 0 A IN 3006 " 0 MX IN 2573 210.117.65.2 - - - 700 700 0 " 0 A IN 700 # end trace interval 3.2 AXFR access The access list for AXFR should be set with provide-xfr: in the nsd config file. This is per zone. See nsd.conf(5). For example to grant zone 'example.com' AXFR right to localhost for IPv4 and IPv6, use the below config options. zone: name: "example.com" provide-xfr: 127.0.0.1 NOKEY provide-xfr: ::1 NOKEY You can use dig @localhost example.com axfr to test this. 3.3 Using TSIG NSD supports TSIG for any query to the server, for zone transfer and for notify sending and receiving. TSIG keys are based on shared secrets. These must be configured in the config file. To keep the secret in a separate file use include: "filename" to include that file. An example tsig key named sec1_key. key: name: "sec1_key" algorithm: hmac-md5 secret: "6KM6qiKfwfEpamEq72HQdA==" This key can then be used for any query to the NSD server. NSD will check if the signature is valid, and if so, return a signed answer. Unsigned queries will be given unsigned replies. The key can be used to restrict the access control lists, for example to only allow zone transfer with the key, by listing the key name on the access control line. # provides AXFR to the subnet when TSIG is used. provide-xfr: 10.11.12.0/24 sec1_key # allow only notifications that are signed allow-notify: 192.168.0.0/16 sec1_key If the TSIG key name is used in notify or request-xfr lines, the key is used to sign the request/notification messages. 3.4 Zone expiry of secondary zones NSD will keep track of the status of secondary zones, according to the timing values in the SOA record for the zone. When the refresh time of a zone is reached, the serial number is checked and a zone transfer is started if the zone has changed. Each master server is tried in turn. Master zones cannot expire. They are always served. Zones are master zones if they have no 'request-xfr:' statements in the config file. After the expire timeout (from the SOA record at the zone apex) is reached, the zone becomes expired. NSD will return SERVFAIL for expired zones, and will attempt to perform a zone transfer from any of the masters. After a zone transfer succeeds, or if the master indicates that the SOA serial number is still the same, the zone will be OK again. In contrast with e.g. BIND, the inception time for a slave zone is stored on disk (in the xfrdfile: "xfrd.state"), together with timeouts. If a slave zone acquisition time is recent enough, this means that NSD can start serving a zone immediately on loading, without querying the master server. If your slave zone has expired, and no masters can be reached, but you still want NSD to serve the zone. (i.e. ''My network is in shambles, but serve the zone dangit!''). You can delete the file 'xfrd.state', but leave the zonefile for the zone intact. Make sure to stop nsd before you delete the file, as NSD writes it on exit. Upon loading NSD will treat the zonefile that you as operator have provided as recent and will serve the zone. Even though NSD will start to serve the zone immediately, the zone will expire after the timeout is reached again. NSD will also attempt to confirm that you have provided the correct data by polling the masters. So when the master servers come back up, it will transfer the updated zone within seconds. In general it is possible to provide zone files for both master and slave zones manually (say from email or rsync). Reload with SIGHUP or nsd-control reload to read the new zonefile contents into the name database. When this is done the new zone will be served. For master zones, NSD will issue notifications to all configured 'notify:' targets. For slave zones the above happens; NSD attempts to validate the zone from the master (checking its SOA serial number). 3.5 Diagnosing NSD log entries NSD will print log messages to the system log (or 'logfile:' configuration entry). Some of these messages are discussed below. These messages can get extra support if errors happen. - "Reload process failed with status , continuing with old database" This log message indicates the reload process of NSD has failed for some reason. The reason can be anything from a missing database file to internal errors. If this happens often, please let us know, this error message can be caught in the code, and appropriate action could be taken. We are as of yet not sure what action is appropriate, if any. - "snipping off trailing partial part of " Please let us know if, and how often, this happens. What happens is the file ixfr.db contains only part of expected data. The corruption is removed by snipping off the trailing part. - "memory recyclebin holds bytes" This is printed for every reload. NSD allocates and deallocates memory to service IXFR updates. The recyclebin holds deallocated memory ready for future use. If the number grows too large, a restart resets it. - "xfrd: max number of tcp connections (32) reached." This line is printed when more than 32 zones need a zone transfer at the same time. The value is a compile constant (xfrd-tcp.h), but if this happens often for you, we could make this a config option. NSD will reuse existing TCP connections to the same master (determined by IP address) to transfer up to 64k zones from that master. Thus this error should only happen with more than 32 masters or more than 64*32=2M zones that need to be updated at the same time. If this happens, more zones have to wait until a zone transfer completes (or is aborted) before they can have a zone transfer too. This waiting list has no size limit. - "error: NSEC3PARAM entry has unknown hash algo " This error means that the zone has NSEC3 chain(s) with hash algorithms that are not supported by this version of NSD, and thus cannot be served by NSD. If there are also no NSECs or NSEC3 chain(s) with known hash algorithms, NSD will not be able to serve DNSSEC authenticated denials for the zone. 3.6 Interfaces NSD will by default bind itself to the system default interface and service ip4 and if available also ip6. It is possible to service only ip4 or ip6 using the -4, -6 commandline options, or the ip4-only and ip6-only config file options. The commandline option -a and config file option ip-address can be given to bind to specific interfaces. Multiple interfaces can be specified. This is useful for two reasons: o The specific interface bound will result in the OS bypassing routing tables for the interface selection. This results in a small performance gain. It is not the performance gain that is the problem, sometimes the routing tables can give the wrong answer, see the next point. o The answer will be routed via the interface the query came from. This makes sure that the return address on the DNS replies is the same as the query was sent to. Many resolvers require the source address of the replies to be correct. The ip-address: option is easier than configuring the OS routing table to return the DNS replies via the correct interface. The above means that even for systems with multiple interfaces where you intend to provide DNS service to all interfaces, it is prudent to specify all the interfaces as ip-address config file options. With the config file option ip-transparent you can allow NSD to bind to non local addresses. 3.7 Tuning NSD is performant by design and most users will have little need for tuning it. For setups that do require every ounce of performance, NSD offers a number of configuration options. cpu-affinity, server--cpu-affinity and xfrd-cpu-affinity Modern computer systems have many cores available. By default the operating system's scheduling-algorithm determines which core a given task is allocated to. Processors build up state, like keeping frequently accessed data in cache memory, for the task (process/thread) that it is currently running. Whenever, a task switches cores, performance is degraded because the core it switched to has yet to build up said state. The cpu-affinity configuration options can be used to bind NSD to one or more cores. cpu-affinity can be used to designate a set of cores onto which NSD processes are scheduled. server--cpu-affinity and xfrd-cpu-affinity can be used to designate a specific core to each individual process. This improves L1/L2 cache hits and reduces pipeline stalls/flushes. For example, a name server configured to fork two NSD servers that must run on dedicated cores 0 and 2, while the transfer daemon (xfrd) must run on core 1, the configuration becomes. server: server-count: 2 cpu-affinity: 0 1 2 server-1-cpu-affinity: 0 server-2-cpu-affinity: 2 xfrd-cpu-affinity: 1 ip-address: x.x.x.x servers= ip-address options can be configured per (set of) server(s). Sockets that are configured for a specific server are closed by other servers on startup. This improves select/poll performance and avoids waking up multiple servers when a packet comes in. ip-address: x.x.x.x bindtodevice=yes ip-address: x.x.x.x setfib= The bindtodevice attribute on Linux and the setfib ip-address attribute on FreeBSD can be used to skip the interface selection process in the kernel. This improves performance, and ensures responses written to the socket are pushed out the same interface the corresponding query came in on when multiple interfaces are configured to listen on the same subnet. The aforementioned options all complement eachother and best performance is achieved by assigning a socket to a single server that runs on a dedicated core and line that up with a dedicated network interface. Network interface interrupts are best handled by a core not designated to any NSD servers. server: server-count: 3 cpu-affinity: 0 1 2 4 server-1-cpu-affinity: 0 server-2-cpu-affinity: 1 server-3-cpu-affinity: 2 xfrd-cpu-affinity: 4 ip-address: 1.2.3.11 servers=1 setfib=1 bindtodevice=yes ip-address: 1.2.3.12 servers=2 setfib=2 bindtodevice=yes ip-address: 1.2.3.13 servers=3 setfib=3 bindtodevice=yes The number of NSD servers to fork and which cores are best used depends entirely on the hardware. cpu-affinity options are supported on Linux and FreeBSD. 3.8 Zone verification NSD can be configured to verify a zone is correct before publishing it. This feature is primarily aimed at fortifying DNSSEC in the DNS notify/transfer-chain, but can be used to carry out any checks desired. An external verifier can be configured per zone. When a zone with verification enabled is received or updated via an (incremental) zone transfer, it will be submitted to the verifier for evaluation. If the verifier deems the updated zone correct (indicated with exit status 0), the zone will be served. NSD will discard the update and continue to serve the zone before the update if the exit status of the verifier is non-zero. Verifier options can be configured globally in the "verify:" clause, or specifically for a zone/pattern in the respective "zone:" and "pattern:" clauses. The global values are applied by default. The zone can be provided to the verifier in two ways. 1. The complete zone can be fed to the standard input of the verifier. This modus operandi is enabled by default and can be configured with the "verifier-feed-zone:" option. Examples for verifiers that read from the standard input are: "ldns-verify-zone -V2" (-V2 to suppress copying to stdout) or "validns -" (don't forget the dash (-) to read the zone from stdin). 2. The zone can be served to the verifier. This is disabled by default and can be enabled by configuring ip- addresses, with the "ip-address:" option in the "verify:" clause, on which the zone to be assessed will be served. Addresses can contain a port number to override the default, which is 5347 by default, but can be overridden with the "port:" option in the verify clause. For example to validate the SOA of a zone example.com by querying, with a certain DS record as the trust anchor (in file example.com.ds), the "verifier:" option could have the following value: "drill -S -k example.com.ds @localhost -p 5347 example.com SOA" A verifier is informed about the domain name of the zone to be verified and the accessibility of the system submitting the zone via environment variables. VERIFY_ZONE Domain name of the zone to be verified. VERIFY_ZONE_ON_STDIN Contains "yes" if the zone is fed over standard input, otherwise "no". VERIFY_IP_ADDRESSES Contains a list of @s on which the zone to be verified can be queried. VERIFY_IPV6_ADDRESS and VERIFY_IPV6_PORT Contains the first configured IPv6 address and port. VERIFY_IPV4_ADDRESS and VERIFY_IPV4_PORT Contains the first configured IPv4 address and port. VERIFY_IP_ADDRESS and VERIFY_PORT Contains the first configured address and port. IPv6 is preferred over IPv4. For each zone one verifier will be run at the same time, but when multiple to-be-verified zones are received, multiple verifiers may be run simultaneously. The number of verifiers that may be run simultaneously is configured with the "verifier-count:" option in the "verify:" clause and defaults to 1. The time a verifier may take can be configured with the "verifier-timeout:" option in the "verify:" clause (to make the general default) or in the "zone:" or "pattern:" clause to set it for a specific zone. When the time the verifier takes exceeds the timeout value, the zone to be verified will be considered bad. By default the value is 0, which means that the verifier may take as long as it needs. To enable verification for all zones. verify: enable: yes verifier: To enable verification only for a specific zone. verify: enable: yes verify-zones: no zone: name: example.com verify-zone: yes 4.0 Support and Feedback NLnet Labs is committed to support NSD and its other software products on a best effort basis, free of charge. This form of community support is offered through a mailing lists and the 'bugzilla' web interface. http://www.nlnetlabs.nl/bugs/ If for any reason NLnet Labs would stop community support of NSD such would be announced on our web pages at least two years in advance. The community mailing list nsd-users@lists.NLnetLabs.nl can be used to discuss issues with other users of NSD. Subscribe here http://lists.nlnetlabs.nl/mailman/listinfo/nsd-users NLnet Labs recognizes that in some corporate environments this commitment to community support is not sufficient and that support needs to be codified. We therefore offer paid support contracts that come in 3 varieties. More information about these support varieties can be found at https://nlnetlabs.nl/services/contracts/ Support goes two ways. By acquiring one of the support contracts you also support NLnet Labs to continue to participate in the development of the Internet architecture. We do this through our participation in the (IETF) standards process and by developing and maintaining reference implementations of standards and tools to support operation and deployment of new and existing Internet technology. We are interested in our users and in the environment you use NSD. Please drop us a mail when you use NSD at users@NLnetLabs.nl. Indicate in what kind of operation you deploy NSD and let us know what your positive and negative experiences are. 4.1 Your Support NLnet Labs offers all of its software products as open source, most are published under a BSD license. You can download them, not only from the NLnet Labs website but also through the various OS distributions for which NSD, ldns, and Unbound are packaged. We therefore have little idea who uses our software in production environments and have no direct ties with 'our customers'. Therefore, we ask you to contact us at users@NLnetLabs.nl and tell us whether you use one of our products in your production environment, what that environment looks like, and maybe even share some praise. We would like to refer to the fact that your organization is using our products. We will only do that if you explicitly allow us. In all other cases we will keep the information you share with us to ourselves. In addition to the moral support you can also support us financially. NLnet Labs is a recognized not-for-profit charity foundation that is chartered to develop open-source software and open-standards for the Internet. If you use our software to satisfaction please express that by giving us a donation. For small donations PayPal can be used. For larger and regular donations please contact us at users@NLnetLabs.nl. Also see http://www.nlnetlabs.nl/labs/contributors/. $Id$ nsd-4.12.0/doc/NSD-VERIFY-MODS0000644000175000017500000002342115002373054014655 0ustar mozziemozzieIn this file a quick overview of all the modifications that have been made for zone verification. Configuring the verifier ======================== Configure (nsd.conf) options were added. In the new "verify:" clause: enable: port: ip-address: verify-zones: verifier: verifier-count, verifier-feed-zone, and verifier-timeout. And for the "zone:" and "pattern:" clauses: verify-zone, verifier, verifier-feed-zone, and verifier-timeout. To parse the syntax for those options, configlexer.lex and configparser.y are modified. To hold those configuration values, the structs nsd_options and pattern_options in the file options.h are extended. The type of pattern_options::verifier, char**, is in the vector of arguments form that can be used by the execve family of executing functions. The helper type "struct component" is defined to help parsing a command with arguments. A zone_verifier is a list of STRING tokens. A stack of component is constructed from those strings, that eventually is converted to an argument in configparser.y. Difffile modifications ====================== It is possible that during a reload updates for multiple different zones are read. If some should be loaded (because they verified or didn't need to be verified) and some not, we have a problem because the database is updated with all the updates (also the bad ones) and we cannot easily selectively undo only the bad updates. In order to break this situation the committed field of each transfer is utilized. Initially it will be assigned the value DIFF_NOT_COMMITTED (0). When an update is verified this will be modified to DIFF_COMMITTED (1), DIFF_CORRUPT (2) or DIFF_INCONSISTENT (4) depending on whether the update was applied and verified successfully. When a reload resulted in one or more zones being corrupt or inconsistent, the newly forked server will quit with exit status NSD_RELOAD_FAILED and the parent server will initiate a new reload. Then it is clear which updates should be merged with the database (the updates which committed field is neither DIFF_CORRUPT or DIFF_INCONSISTENT). Handling of the NSD_RELOAD_FAILED exit status of a child reload server is in server_main (server.c) To allow updates to be applied again on failure, xfrd has been updated to keep all updates for each zone around until a reload succeeds. The set of updates is fixed once a reload has been initiated to avoid a potentially infinite loop. During the update window, xfrd will accept and transfer updates, but does not schedule them until the reload finishes. As a result, xfrd manages the updates stored on disk rather than the server, which previously just removed each update during the reload process regardless of the result. Potentially resulting in the same transfer being tried mutiple times if the set of updates contained a bad update. Running verifiers ================= In server_reload (in server.c) the function server_verify is called just after all updates are merged into the (in memory) database, but just before the new database will be served. server_verify sets up a temporary event loop, calls verify_zone repeatedly to run the verifiers and mark each updated zone. server_reload then inspects the update status for each zone and communicates the number of good and bad zones in the update. server_reload then decides how to continue based on the number of good and bad zones as described above. verify_zone is defined in verify.c (and .h). The function creates the necessary pipes, starts the verifier and then sets up the required events and registers them with the event loop. The state for each verifier is maintained an array of struct verifier. The size of the array is "verifier-count:" big. Each verifier that runs simultaneously is assigned a slot. When no free slots are available it waits until a running verifier is finished (or timed out) and a free slot is available for a potential next verifier to run simultaneously with the already running verifiers. The default setting is to run just one verifier at once, which will probably be fine in most situations. Once all verifiers are finised (or timed out), the event loop is exited and server_reload communicates the status for each updated zone. Environment variables for the verifiers ======================================= Verifiers are informed on how a zone can be verified through environment variables. The information on which addresses and ports a verifier may query a zone to be assessed is available and set on startup just after reading the configuration and setting up the sockets in nsd.c by calling setup_verifier_environment (also in nsd.c). Verifiers are spawned (via verify_zone) with popen3. verify_zone sets the zone specific environment variables (VERIFY_ZONE and VERIFY_ZONE_ON_STDIN) just before it executes the verifier with execvp. Server sockets are automatically closed when the verifier is executed. Logging a verifiers standard output and error streams ===================================================== Everything a verifier outputs to stdin and stderr is logged in the nsd log file. Handler with handle_log_from_fd (verify.c) as a callback are setup by server_verifiers_add. The log_from_fd_t struct is the user_data for the handler and contains besides the priority and the file descriptor, variables that are used by handle_log_from_fd to make sure logged lines will never exceed LOGLINELEN in length and will be split into parts if necessary. Note that in practice error messages are always logged before messages on the standard output, because stdout is buffered and stderr is not. Maybe it is more convenient to set stdout to unbuffered too. Feeding a zone to a verifier ============================ The complete zone may be fed to the standard input of a verifier when the "verifier-feed-zone:" configuration option has value "yes" (the default). For this purpose a verify_handle_feed (verify.c) handler is called when the standard input file descriptor of the verifier is writeable. The function utilizes the zone_rr_iter_next (verify.c) function to get the next rr to write to the verifier. The verifier_zone_feed struct is used to maintain state (the file handle, the rr pretty printing state and the zone iterator). Serving a zone to a verifier ============================ The nsd struct (in nsd.h) is extended with two arrays of nsd_socket structs: verify_tcp and verify_udp and an verify_ifs size_t which holds the number of sockets for verifying. This reflects the tcp, udp and ifs members that are used for normal serving. Several parts in the code that operate on the tcp and udp arrays is simply reused with the verify_tcp and verify_udp arrays. Furthermore, in places in server.c were before the server_close_all_sockets (server.c) function was used with the normal server sockets, the function is called subsequently for the verify sockets. Also in server_start_xfrd the sockets for verifiers are closed in the xfrd child process, because it has no need for them. Verifier timeouts ================= A handler for timeouts (as configured with the "verifier-timeout:" option) is added by server_verifiers_add at verifier initialization time. The callback is handle_verifier_timeout (verify.c) and the verifier_state_type for the verifier is used as user_data. verify_handle_timeout simply kills the verifier (by sending SIGTERM) and does not cleanup the verifier state for reuse. This is done in verify_handle_exit, which is triggered once the verifier exits, because it can handle and start more verifiers simultaneously. Aborting the reload process (and killing all running verifiers) =============================================================== A reload might (especially with a verifier) take some time. A parent server process could in this time be asked to quit. If that happens and it has a child reload server process, it sends the NSD_QUIT command over the communication channel. verify_handle_command, which is registered when the temporary event loop is created, is triggered and sends a SIGTERM signal to each of the verifiers. Refreshing and expiring zones ============================= When the SOA-Refresh timer runs out, a fresh zone is tried to be fetched from the master server. If that fails, each SOA-Retry time will be tried again. To prevent a bad zone from being verified again and again, xfrd remembers the last serial number of the zone that didn't verify. It will not try to transfer a zone with the bad serial number again. Before afer reloading, the reload process informed xfrd which SOA's were merged in the database, so that xfrd knew when zone needed to be refreshed. This is adapted to inform xfrd about bad zones. The function inform_xfrd_new_soas is called for this in server.c. It communicated either good or bad soas. When bad soas are communicated a session starts with NSD_BAD_SOA_BEGIN. For only good zones it starts with NSD_SOA_BEGIN. Each soa is preceded by a NSD_SOA_INFO. When all soas are communicated, NSD_SOA_END is send. Reception of these messages by xfrd is handled by function xfrd_handle_ipc_read in ipc.c. In the xfrd_state struct (in xfrd.h), the boolean parent_bad_soa_infos is added to help with this control flow in ipc. The soas are eventually processed by xfrd, via xfrd_handle_ipc_SOAINFO in ipc.c, with the xfrd_handle_incoming_soa function in xfrd.c. The function make sure that if a bad soa was received it is remembered in the xfrd_zone struct. Two new variables are added for the purpose to this struct: soa_bad and soa_bad_acquired. The values are stored and read to the xfrd.state file with the functions xfrd_write_state_soa and xfrd_read_state respectively. In xfrd.c function xfrd_parse_received_xfr_packet is adapted to make sure that known bad serials are not transfered again unless the transfer is in a response to a notify. And even then only when the SOA matches the one in the notify (if it contained one, otherwise any SOA is good). nsd-4.12.0/doc/NSD-FOR-BIND-USERS0000644000175000017500000001541015002373054015147 0ustar mozziemozzieNSD for BIND users ------------------ Contents 1. Zone compiler. 2. Authoritative only. 3. Config file format. 4. Keys not per IP address. 5. NOTIFY of NS-entries. 6. Less options. 7. Master-Slave meshes. 8. AXFR behaviour. 9. Ports. 10. nsd-control setup Please see the README for general information. This document assumes the reader is familiar with BIND tools and explains the differences between BIND and NSD. 1. Zone compiler. In its memory NSD maintains fragments of data that are ready to put 'on the wire' without a lot of additional work by the server. Those fragments of data need to be compiled from the zone file. Therefore NSD has a zone compiler that translates the text format zone files into a binary format database file that the server reads. 2. Authoritative only. NSD only serves authoritatively. So, NSD does not provide caching, and does not provide recursion, or resolver functionality. NSD can, in other words, function as master or slave server. This also means no root zone '.' type hint is used; leave out the root zone entirely from your configuration. NSD does not cache the root. NSD will not provide an upward referral in case an authoritative answer cannot be found. Because of this design choice (see Appendix B.1 of the REQUIREMENTS file) NSD does not need to maintain knowledge of the root-server set and there is no need for a root.hints file. Also leave out localhost zones from NSD config. 3. Config file format. The config file for NSD nsd.conf(5) is different from BIND named.conf(5). See the manual pages for differences in syntax. The zone files with resource records have the same format however. A short configuration file for BIND can look like this: // Name server configuration named.conf options { directory "/etc/dns"; pid-file "/etc/dns/pid-file"; dnssec-enable yes; listen-on-v6 { any; }; recursion no; }; // logging options for the DNS Server logging { channel mainlog { file "/var/log/dns.log" size 10m; severity info; }; category default { mainlog; }; }; // root hints zone "." IN { type hint; file "root.servers"; }; zone "localhost" IN { type master; file "localhost.zone"; allow-update { none; }; }; zone "0.0.127.in-addr.arpa" IN { type master; file "localhost.rev"; allow-update { none; }; }; // authoritative server for example.com zone "example.com" IN { type master; file "example.com.signed"; }; The equivalent configuration file for NSD is shown below. Note no ;s at the end of statements. No braces {}, and comment is with #. # Name server config for NSD, nsd.conf server: zonesdir: "/etc/dns" pidfile: "/etc/dns/pid-file" # dnssec is automatically enabled in NSD for signed zones. # ip6 is also enabled for NSD. (ip4-only: yes to turn off). # NSD does not do recursion. database: "/etc/dns/nsd.db" # logging clause comes here, no size or severity options. logfile: "/var/log/dns.log" # NOTE: no root hints. # no localhost, and no 0.0.127.in-addr.arpa zone. # authoritative server for example.com zone: name: "example.com" zonefile: "example.com.signed" 4. Keys not per IP address. BIND associates TSIG keys with an IP address. When communicating from/to that address BIND will TSIG sign. NSD associates TSIG keys with the acl entries, when performing these functions NSD will sign with TSIG. It is thus possible to configure NSD to use a different key for notifications then for zone transfers, and a different key in one direction from the other. Additionally, NSD will reply TSIG signed queries with TSIG signed responses. In BIND you might have a master that uses tsig for zone updates. // ... rest of named.conf config file // the TSIG key shared secret with the slave server key key23.example.com. { algorithm hmac-md5; secret "6KM6qiKfwfEpamEq72HQdA=="; }; // when BIND communicates with this server, use the key server 168.192.0.15 { keys { key23.example.com.; }; }; zone "example.com" IN { type master; file "example.com.signed"; allow-transfer { key key23.example.com.; }; }; For NSD the master configuration would look a little different. # ... rest of nsd.conf config file. # The TSIG key shared secret with the slave server key: name: "key23.example.com." algorithm: hmac-md5 secret: "6KM6qiKfwfEpamEq72HQdA==" # no need to list the server { keys { keyname; }; }; statement zone: name: "example.com" zonefile: "key23.example.com." # the allow-transfer and server statements from BIND rolled into one. provide-xfr: 168.192.0.15 key23.example.com. # # since NSD does not send notifies to the servers listed in the NS rrs, # the above server must be explicitly named to get notify messages. # see item 5, below. Note, the keyname is repeated here. notify: 168.192.0.15 key23.example.com. 5. NOTIFY of NS-entries. BIND sends notification messages automatically to the servers named in the SOA and NS entries of a zone. NSD does not. It sends only to the 'notify:' entries in the config file. If you want NSD to send notifications to these servers, include notify: statements in the config file for them. 6. Less options. NSD has less options than bind has. It is designed to be small. Some options that are *not* available in NSD are: provide-ixfr trusted-keys {} controls {} logging options lwres {} rrset-order recursion yes; cache options zone types: hint, forward, stub view clauses 7. Master-Slave meshes. NSD can be configure as both a slave of a (hidden) master and as a master to further slaves as well. This way meshes of name servers can be created, like with BIND. 8. AXFR behaviour. To do a manual AXFR, nsd-xfer will perform like the BIND tools. But, the initial query for the SOA is done by TCP, where the BIND tools use UDP for that SOA query. According to RFC (1034, 1035) specs, both UDP and TCP for the initial SOA probe are OK. An AXFR initiated by the built-in transfer process will not start with a SOA query at all. The first packet of the AXFR transfer will be used to determine the SOA version number in that case. This is a conscious breach of RFC spec to ease implementation and efficiency. Note that usually the built-in transfer process will request an IXFR, and preceed the IXFR with a UDP IXFR request like the RFC says. 9. Ports. Nsd can be configured to run on another port than port 53. See the 'port:' statement in the nsd.conf file. Access control list elements can be appended with @port_number to refer to a specific port only, such as 10.11.12.100@8853. NSD will not set its source port for outgoing connections to be equal to the configured port, ephemeral ports are used for notify, ixfr and axfr requests to other servers. 10. nsd-control setup The rndc tool for BIND named needs a secret to communicate securely with the server. The NSD tool nsd-control can setup its secrets with the nsd-control-setup command. It uses public keys, and SSL connections. nsd-4.12.0/doc/NSD-DIFFFILE0000644000175000017500000000274315002373054014265 0ustar mozziemozzieDIFF support file format. This file contains changes to the main NSD-DATABASE file. The file contents is in network format. The file is a transfer, with a header and a number of data segments. - File starts with 32bit value 'XFRF' - header with: - 8bit: commit=1(IXFR is OK) or rollback=0(ignore that IXFR). - 32 bit number of packets that are to be applied. 0 if file not completed. - timestamp of endtime of download (64bitsec,32bitusec). - 32 bit old serial number. (to check that db-serial is unchanged). or 0 if no serial available yet. - 32 bit new serial number. - timestamp of starttime of download (64bitsec,32bitusec). - zone name (string). - pattern name: so that a newly created zone for which the zone transfer is processed before the config-add task can be created. same string format with 32bitcount with name of the pattern. - a number of parts that start with 'XXFR' - 32 bits length field. - length bytes of content. contents is the IXFR or AXFR packet contents, max 64K. - 32 bits repeat of the length field. at end of file a log string space for a text string message (preceded by 32bitcount), i.e. 'at time came from , tsig checked with key '. or rejected . The length fields and type fields check that the input is formatted, and complete otherwise an error occurred (like, disk failure). The commit flag is only set after the write of the entire file has completed (rewind, overwrite commit value with true). nsd-4.12.0/doc/NSD-DATABASE0000644000175000017500000000176715002373054014266 0ustar mozziemozzieNSD 4.0 DATABASE FORMAT. The NSD 4.0 database format is different from NSD 2 and NSD 3. It stores RRs, but in a way that they can be edited without leaking space. The file contains a 'buddy-system-style' 'malloc' of chunks. Pointers are offsets from the start of the file. For every pointer the reverse is kept track of, so that chunks can be moved to a new position. Free space is reused, and (gradually) moved to the end to shorten the file. It is about 23x larger than the NSD3 format and about 3x to 6x slower to read and write a full database. But you can use a tree to fetch a particular item at log(N) cost, and update a single item at log(N) cost. Therefore, adding a zone or removing a zone does not need a new compile of the nsd database, but can be performed by editing the database. The file format is endian-dependent, and uses 64bit file offsets. The file chunk format is defined in udb.h. the tree for lookups is defined in udbradtree.h. The rrsets and zone format is defined in udbzone.h. nsd-4.12.0/doc/NSD-4-features0000644000175000017500000001416315002373054015073 0ustar mozziemozzieNSD 4 features By W.C.A. Wijngaards, NLnet Labs, 2012. Migration --------- The old NSD3 config file can be used without changes for NSD4. There are new config statements and some old statements are gone. The nsd.db file has a new format that allows read and write. Thus the nsd.db file needs to be re-created in NSD4 format. This happens when you start NSD4. NSD4 needs write permission on the nsd.db directory for that. If you need to rollback to NSD3, run its zonec to recreate the NSD3 nsd.db file (use nsdc rebuild). The cron job for nsdc patch is no longer needed. It can be removed. If you admire cron jobs, you can have a cron job that does "nsd-control write". This would periodically write the contents of changed zones to their zonefile. nsdc is removed, reload with kill -HUP $pid and use nsd-control. The SIGHUP makes NSD4 check zone file timestamps and reload changed zones. nsd-control reload is the same. SIGTERM stops NSD. You probably want to install and enable some of the new NSD 4 features, such as set up nsd-control and statistics. And you may want to use the new pattern config options. Removed config options ---------------------- difffile: ixfr.db is gone. This setting is no longer applicable, because the ixfr.db file is no longer used. Files are created in /tmp now. The value is ignored by NSD4 if given in nsd.conf. ip4-only and ip6-only: are replaced with more straightforward do-ip4 and do-ip6. They are still accepted in nsd.conf for backwards compatibility. New config options ------------------ zonelistfile: zone.list. This file contains a plain text listing of the dynamically added zones and their pattern. It is read and written by NSD while it is running. xfrdir: /tmp. This directory is used to store temporary zone transfer files. They are stored in a unique subdirectory that has few access permissions. tcp-count: 100. This option already exists in NSD3, but in NSD4 you can increase it above 1024, like 2048, to have higher TCP capacity. remote-control: this is a new section in the config file that configures the nsd-control remote control utility. It is very similar to unbound's remote control configuration. With control-enable: yes you can enable it, it is disabled by default. It is bound to the loopback interface by default. See the manpage or sample config for the list of options, it is possible to set the port number and keyfile paths, and configure it to be accessible from the outside. pattern: these allow you to bundle a set of zone config statements. Then for a zone you can include-pattern: "nameofpattern" to apply those config statements. patterns can also include other patterns. This is needed to allow the user to specify the config statement pattern for a newly added zone. But you can also use it to organise the configuration. zone: These already exist in NSD3 and work similarly. For NSD4, they create a zone, these zones added and removed by a restart or the nsd-control reconfig command. Zones that are dynamically added can also be dynamically removed (with nsd-control addzone and delzone), those zones are in the zones.list file. The zone can have the normal zone config statements, and it can also use include-pattern to apply config statements from a pattern to it. The nsd-control utility ----------------------- You can control the NSD4 daemon with signals, SIGHUP, SIGTERM, if you want. It reloads on SIGHUP and this includes parsing and loading changed zone files. More commands are available via the nsd-control utility. It connects over SSL with the daemon and sends the command to it, and prints the result. To enable nsd-control you have to create the private and public keys with nsd-control-setup, run it as root. Then edit nsd.conf and set remote-control: control-enable: yes in the config file. Then you should be able to use nsd-control, the nsd-control status command is a simple check if everything works. reload [zone] : without a zone name it checks if zone files have changed, if so, loads them. If you specify the zone name (nsd-control reload example.com) it'll load that zone. reconfig : this rereads the nsd.conf file without a restart. Only the zone configuration, and ratelimits are updated from it. Other settings, file paths, chroot location, interfaces and port numbers, cannot be applied and need a restart, during the restart NSD will have the permissions to bind port 53 and chroot again. It adds and removes zones that have been added and removed in the config file, and it also changes zone configurations. log_reopen : also done on SIGHUP, but this controls more exactly that only the logfile is reopened. stats and stats_noreset : print statistics. addzone name pattern : adds a new zone to the running server. If it has a zonefile this file is read in and served. If it is a slave zone, a zone transfer is attempted. delzone name : removes zone. write [zone] : write a zone contents from nsd.db to its zonefile in text format. writes all changed zones, but if you specify a particular zone, it writes that zone only. notify [zone] : for master zones here, send notifies to its slaves. If you specify a name, only that zone, otherwise all master zones. transfer [zone] : for slave zones here, attempt a zone transfer from the masters. If you specify a name, only that zone, otherwise all slave zones. force_transfer [zone] : same as transfer but uses full zone transfer with AXFR and does not perform a serial number check. Statistics ---------- With nsd-control you can get a list of statistics from NSD on demand. This makes it easier to integrate NSD into a statistics collection system. In source/contrib/nsd_munin_ is an example munin plugin. Other features -------------- * Performance increase. * Support a high zone count. * Faster zone transfers. * Add and remove zones without a restart. * Can reread zone configuration from config file without a restart. * Higher TCP service levels, more sockets. * Detect which zone files have changed. * Calculates nsec3-prehash incrementally after IXFR. * Domain tree does not have the small leak of domain nodes. More documentation ------------------ The nsd(8) man page, the nsd.conf(5) man page, the nsd-control(8) man page. nsd-4.12.0/doc/NEW-CFG-OPTION0000644000175000017500000000470515002373054014527 0ustar mozziemozzieWhen adding a new configuration option to NSD, several files need to be touched. This file is an enumeration of files that need to be edited. Suppose we are going to add a configuration option 'dummy:' that can take a string. We need to update the following files: 1. configlexer.lex 2. configparser.y 3. options.h 4. options.c 5. nsd.conf.sample.in 6. nsd.conf.5.in 7. nsd-checkconf.c 8. tpkg/checkconf.tpkg 1. Update configlexer.lex Make sure that zonec understands the new option by adding the following line into configlexer.lex dummy{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DUMMY;} 2. Update configparser.y Make sure that zonec can parse the new option by adding VAR_DUMMY to the set of tokens: %token VAR_DUMMY Update the grammar. For example, if it a server option, extend content_server: content_server: server_ip_address | ... server_hide_version | server_dummy; And write down the dummy rule: server_dummy: VAR_DUMMY STRING { OUTYY(("P(server_dummy:%s)\n", $2)); cfg_parser->opt->dummy = region_strdup(cfg_parser->opt->region, $2); } ; 3. Update options.h Make sure that there is storage for the dummy option. In struct nsd_options, add: const char* dummy; 4. Update options.c Set a default dummy string. In the function nsd_options_create(), add: opt->dummy = "dummy"; 5. Update nsd.conf.sample.in Add a reference in the sample configuration file: # This option does nothing. # dummy: "dummy" 6. Update nsd.conf.5.in Update the nsd.conf manpage: .TP .B dummy:\fR Does nothing. 7. Update nsd-checkconf.c Make the checkconf tool aware of the new option. In config_print_zone(), add: SERV_GET_STR(dummy, o); and in config_test_print_server(), add: print_string_var("dummy:", opt->dummy); 8. Update tpkg/checkconf.tpkg Make the test aware of the new option. Extract checkconf.tpkg: $ cd tpkg; $ tpkg extract checkconf.tpkg $ cd checkconf.dir And add to the various checkconf.check[1-9] files: dummy: "dummy" Go back to the tpkg directory and create the new test: $ cd .. $ tpkg create checkconf.tpkg 9. Update other files You might need to edit other files too: - If the new option requires to be enabled at build time, you need to add stuff to configure.ac and Makefile.in. - Update documentation files, like doc/README, doc/RELNOTES, doc/Changelog. - Obviously, the source code files need to be edited to implement the new functionality. nsd-4.12.0/doc/LICENSE0000644000175000017500000000273715002373054013560 0ustar mozziemozzieCopyright (c) 2001-2006, NLnet Labs. All rights reserved. This software is open source. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the NLNET LABS nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nsd-4.12.0/doc/ChangeLog0000644000175000017500000062516215002373054014330 0ustar mozziemozzie17 April 2025: Wouter - Add autoconf files to gitignore. 8 April 2025: Wouter - Fix nsd-checkzone ixfr create cleanup on exit. 4 April 2025: Wouter - Fix to update common.sh for speed of kill_pid. 1 April 2025: Wouter - Fix escape more characters when printing an RR type with an unquoted string. - Fix memory leak in the process of addzone. 27 March 2025: Wouter - Fix test checkconf for metrics options. - Updated simdzone to include fixes for NSAP-PTR, LOC, uninitialized reads, and comment nit. - Fix #436: Fix print of RR type NSAP-PTR. - Fix unit test call to zone_parse_string and initialize padding. 26 March 2025: Wouter - Fix multiple zone transfers in one reload so that xfrd does not check the update as failed and restart the transfer. - Test for the multiple transfer failure, xfr_over_notify. - Fix read of ixfr file with rdata subdomain. - Test for the ixfr rdata subdomain, ixfrout_deldomain. - Fix note in ixfrout_deldomain test. 25 March 2025: Wouter - Fix to please sanitizer for ixfr store of data in cancelled state. 24 March 2025: Jannik - Merge #429: Add prometheus metrics 14 March 2025: Wouter - Fix log print assert in server sockets for printing '-' empty. - Fix notify_fmt test for xfrd file location. - Fix sanitizer warnings in read_uint32. - Fix sanitizer warning in tsig write of zero length mac and otherdata. 13 March 2025: Wouter - Fix ixfr file read to manage numlist in temp domains. - Fix nsd-mem to clean ixfr storage. 12 March 2025: Wouter - Fix ixfr read routine for use after the temp region is freed of rr. 11 March 2025: Wouter - Fix in nsd-mem for a zone with ixfr data. 3 March 2025: Wouter - Fix that nsec3 prehash after a full transfer can create the nsec3 zone trees if they are needed. 19 February 2025: Wouter - Fix for #430: Confusing documentation: word "outgoing". Add wording to tcp-count, xfrd-tcp-max, xfrd-tcp-pipeline options. 18 February 2025: Wouter - Fix for #430: Confusing documentation: word "outgoing". 11 February 2025: Willem - Merge #420: Zones get state "old-serial" with `nsd-control zonestatus` when the served serial is older than the one received by the transfer daemon. 23 January 2025: Willem - Merge #418: Support for DSYNC, EID, NIMLOC, SINK, TALINK, DOA, AMTRELAY and IPN resource record types. 22 January 2025: Wouter - Fix #426: nsd crashes with patterns in config_apply_pattern. 20 January 2025: Willem - code repository continues with 4.11.2 under development. - Fix re-enable to configure dns-cookies from config file, which was accidentally removed with the 4.11.1 release. 19 January 2025: Willem - NSD 4.11.1 emergency quick-fix release 17 January 2025: Willem - Fix #424: Stalled updates after corrupt transfer. 15 January 2025: Wouter - Fix whitespace in comment. 7 January 2025: Willem - Fix #421: old-main can quit before the reload process received from old-main that it is done on the reload_listener pipe. Thanks Otto Retter. 3 January 2025: Willem - Fix #414: XoT interoperability with BIND and Knot 23 December 2024: Willem - Fix #415: Fix out of tree builds. Thanks Florian Obser (@fobser). 5 December 2024: Willem - The tag for the 4.11.0rc1 release became the release 4.11.0, on 12 December 2024, the code repository continues with 4.11.1 under development. 4 December 2024: Willem - Merge #407: Better balanced verbosity levels for logging. 26 November 2024: Jeroen - Fix #405: Fix typo in documentation. Thanks to @uplime for reporting. 19 November 2024: Willem - Merge #409: Writing of NSAP-PTR, GPOS and HIP RR types 16 November 2024: Willem - Merge #408: NINFO, RKEY, RESINFO, WALLET, CLA and TA RR types 12 November 2024: Willem - Merge #406: ohttp and tls-supported-groups SvcParam support 7 November 2024: Willem - Merge #398: RFC 9660 The DNS Zone Version (ZONEVERSION) Option 4 November 2024: Wouter - Fix Makefile for parallel build failure around bison rule. 28 October 2024: Jeroen - Merge #404: Introducing Sphinx substitution in code blocks. As well as other fixes with Sphinx build. - Merge #391: Update Copyright lines in help output - Merge #395: Explain zonefile example better - Merge #394: Fix doc path (fixes "Edit on GitHub" button in the docs) - Many thanks to Melroy van den Berg for the documentation improvements and fixes in PRs #391, #394, #395 and #404 28 October 2024: Jeroen - Fix #396: Treat a mismatch in RRset TTLs as a warning. 24 October 2024: Wouter - Fix #392: Inconsistent documentation about control-interface. - Merge #395: Explain the zonefile example better. - Merge #394: Fix the path to use doc/manual/. - Fix analyzer issue in do_print_cookie_secrets to check for failure. 23 October 2024: Willem - Fix #196 and merge #378: Updated cookie secrets management. The default cookie secret file location can be set at compile time with the --with-cookiesecretsfile=path option to configure. The default location is changed to {dbdir}/cookiesecrets.txt. The previous default location will be checked at startup when there is no cookie secrets file at the new default location. A staging cookie can now also be configured in the configuration file and secrets configured in the configuration file now take precedence over those read from file. All DNS related setting in the configuration file will be reevaluated and effectuated after nsd-control reconfig. - Merge #390: Apply non-xfr tasks before xfr tasks. This fixes an issue where non-xfr tasks are lost when they are batch processed together with non-xfr tasks. This merge also changes that notifies are passed on from the serve processes to the xfrd directly instead of via main. This was necessary to allow applying the non-xfr tasks without forking a backup-main for the sole purpose of forwarding notifies. 23 October 2024: Wouter - Merge #391: Update copyright lines (in version output). 18 October 2024: Wouter - Fix ci to update macos-12 to the macos-15 runner image. 25 September 2024: Wouter - Fix #383: log timestamps in ISO8601 format with timezone. This adds the option `log-time-iso: yes` that logs in ISO8601 format. - Fix to initialize log_time_iso value in options. 23 August 2024: Jeroen - Fix #57: Track $INCLUDEs in zone files 23 August 2024: Wouter - Merge #376: Point the user towards tcpdump for logging individual queries. 22 August 2024: Wouter - Add cross platform freebsd, openbsd and netbsd to github ci. - Update simdzone to include fix for netbsd double bswap declarations, and also semantic checks for DS and ZONEMD. And CFLAGS has -march prepended to fix detection. 19 August 2024: Wouter - Fix title underline and declaration after statement warnings. 15 August 2024: Jeroen - Support reloading configuration on SIGHUP. 2 August 2024: Jeroen - Update simdzone to fix detection of AVX2 support. 31 July 2024: Jeroen - Merge #367: Specify protocols used in NOTIFY. - Merge #368: Various manpage fixes. 30 July 2024: Jeroen - Merge #366: Be consistent in naming primary/secondary zones. 25 July 2024: Jeroen - Merge #358 from @jas4711: Fix Hurd build error due to log_Err. 23 July 2024: Jeroen - Update simdzone. - Tag for 4.10.1rc2. 23 July 2024: Jeroen - Update simdzone. - Tag for 4.10.1rc1. 22 July 2024: Jeroen - Initialize tls_auth_port and tls_auth_xfr_only options. 22 July 2024: Wouter - Fix link of xfr-inspect for libssl dependency. 19 July 2024: Willem - Do not log ACL mismatch on followed CNAMEs. 18 July 2024: Jeroen - Fix propagation of Makefile targets to simdzone. 18 July 2024: Wouter - Merge #337 from bilias: Mutual TLS-AUTH. 16 July 2024: Wouter - Merge #352 from orlitzky: contrib: add OpenRC service script, config file, and tmpfiles entry. 12 July 2024: Jeroen - Use MAKE variable rather than make command. On platforms where make is not the same make executing the Makefile, build issues might arise. The MAKE variable expands to the command used on the command line. 11 July 2024: Jeroen - Serialize WKS RRs using numeric values rather than names. simdzone does not use getprotobyname and getservbyname. Secondary zones received via IXFR/AXFR might fail to load because WKS RRs used "unsupported" protocols or services. 8 July 2024: Wouter - Merge #349: log file name before loading. 5 July 2024: Wouter - Fix #347: Adjust verbosity for TLS (+TCP) to be 5. - Merge #348: Move TLS logging to verbosity level 5. - For #347: Also adjust verbosity of log message for remaining TCP connections. 27 June 2024: Wouter - Fix #344: Update simdzone. 26 June 2024: Wouter - Fix test script from making spurious output. - Fix cpu_affinity and socket_partitioning tests for --enable-log-role. 24 June 2024: Wouter - Add unit test for #343 relative include in zone file. 20 June 2024: Wouter - Merge #341: Fix allow-query wording in nsd.conf.5.in. 17 June 2024: Wouter - Fix for OpenSSL 3.0 deprecated functions. 11 June 2024: Wouter - Fix #334: RFC8482 behavior documentation. 23 May 2024: Wouter - Fix for #317, document more text on pidfile permissions. 29 April 2024: Wouter - Fix incorrect punctuation of log messages. 25 April 2024: Wouter - The tag for the 4.10.0rc1 release became the release 4.10.0, on 13 June 2024, the code repository continues with 4.10.1 under development. The release contains the additional fix to change simdzone version. - Bump simdzone to include minor fixes. This is included in 4.10.0. 25 April 2024: Jeroen - Bump simdzone to fix OpenBSD build issues. - Tag for 4.10.0rc1. 24 April 2024: Wouter - Fix that the reload handler for sigchild uses signal_add, and also that the signal handler is restored when done. - Fix that when server verify is done it resets the sigchild handler. - Fix makedist.sh for simdzone inclusion. - Fix makedist.sh to remove simdzone git tracking information and scripting temporaries from tarball. - Fix error output of makedist.sh. 23 April 2024: Wouter - Fix #329: TCP accept queues number. 22 April 2024: Jeroen - Use simdzone version with name parser fix. 16 April 2024: Jeroen - Replace Flex+Bison based zone parser with simdzone. 15 April 2024: Wouter - Unit test for dname subdomain test used by xfrd-tcp.c. 9 April 2024: Wouter - Fix IXFR requests upstream for zones with a long name. Thanks for the report to Yuuki Wakisaka from Internet Initiative Japan Inc. 8 April 2024: Wouter - For #317: Modify nsd service script to stop NSD from creating a pid file that systemd is not using. - Fix #324: Clarify the purpose of contrib/bug390.patch. 4 April 2024: Jeroen - Use rooted temporary path in makedist.sh. - Tag for 4.9.1. 3 April 2024: Jeroen - Replace multiple strcat and strcpy by snprintf. - Tag for 4.9.0. 27 March 2024: Wouter - Fix that when the server truncates the pidfile, it does not follow symbolic links. - Fix #317: nsd should not chown its PID file. 26 March 2024: Jeroen - Test if debug is available in do-tests. - Enforce timeout from NSD in ixfr_gone test. - Update expressions in ixfr_and_restart test. - Make algorithm explicit in control-repattern test. - Switch algorithm to hmac-256 for testplan_mess test. - Tag for 4.9.0rc1. 25 March 2024: Jeroen - Fix timing sensitivity in ixfr_outsync test. 22 March 2024: Jeroen - Set up doc/RELNOTES for upcoming release. 26 February 2024: Willem - Merge #316: Fix to reap defunct children by the reload process that emerged when some serve child processes were still serving TCP request while the others had already quit, while the reload process was waiting for the signal from the backup/old main process that all children exited. - Fix (also from Merge #316) to reap exited children more frequently from server main loop for processes that exited during reload, but missed the initial reaping at start of the main loop because they took somewhat longer to exit. 16 February 2024: Wouter - Fix compile with memclean for xfrd nsd.db close. - In xfrd del secondary zone, the timer could perhaps have event_added, and if so, it would not be event_del if a tcp connection is active at the time. This could cause the libevent event lists to fail. Also fix to make sure to set event_added for the nsd-control ssl nonblocking handshake and check event_added there too, for extra certainty. 15 February 2024: Willem - Merge #304: Support for Catalog zones version "2" as specified in RFC 9432. Both the consumer as well as the producer role are implemented, but only a single catalog consumer zone is allowed. The "coo" property, only relevant with multiple catalog consumer, is therefore not supported. The "group" property is supported. Have a look at the nsd.conf man page for details on how to configure and use catalog zones. 12 February 2024: Willem - Allow SOA apex queries to otherwise with allow-query protected zones for clients matching a provide-xfr rule, because clients that are allowed to transfer the zone need to be able to query SOA at the apex preceding the actual transfer. 6 February 2024: Wouter - Fix #313: nsd 4.8 stats with implausible spikes. 16 January 2024: Wouter - Move acx_nlnetlabs.m4 to version 48, with ssp and getaddrinfo include check. 14 January 2024: Wouter - Move acx_nlnetlabs.m4 to version 47, with crypt32 check. 8 December 2023: Wouter - Merge #309: More RFC 8499 compliance. - Fix #310: NSD stats contain the terms "master" and "slave". - Fix control-reconfig-xfrd test for zonestatus primary that is printed by nsd-control zonestatus. 7 December 2023: Wouter - Merge #307 from anandb-ripencc: Many improvements to the nsd.conf man page. - Fix #308: Deprecate "multi-master-check" in favour of "multi-primary-check". 6 December 2023: Wouter - Fix to sync the tests script file common.sh. - Update test script file common.sh. - Fix #306: Missing AC_SUBST(dbdir) breaks installation with 4.8.0. - Fix for #306: Create directory for xfrd.state and zone.list files in make install. 29 November 2023: Wouter - Tag for 4.8.0rc1. This became 4.8.0 release on 6 December 2023. The repository continues with version 4.8.1 under development. 28 November 2023: Wouter - Set up doc/RELNOTES for upcoming release. - Fix unit test kill_from_pidfile function for nonexistent files because the argument is evaluated before the test expression. - Fix rr-test to also convert the contents of the just written output file. - Fix test set to remove -f nsd.db and rm nsd.db commands. - Fix test set to remove difffile option. 27 November 2023: Jeroen - Fix #14: Set timeout to 3s when servicing remaining TCP connections. - Fix: Always instate write handler after reading queries from TCP. - Answer first query on connections accepted just before reload. 27 November 2023: Wouter - Merge #305: faster stats. Statistics can be gathered while a reload is in progress. 27 November 2023: Willem - Merge #302: Test package fixes. Correct Auxfiles, kill_from_pidfile function and fix drop_updates, rr-test and xfr_update tests. 1 November 2023: Jeroen - Remove on-disk database. 31 October 2023: Wouter - Merge #301: improve the logging of ixfr fallbacks to axfr. 30 October 2023: Jeroen - Fix processing of consolidated IXFRs. 30 October 2023: Wouter - Fix for interprocess communication to set quit sync command from main process explicitly. 3 October 2023: Wouter - Merge #281: Proxy protocol. An implementation of PROXYv2 for NSD. It can be configured with proxy-protocol-port: portnum with the port number of the interface on which proxy traffic is handled. The interface can support proxy traffic for UDP, TCP and TLS. 21 September 2023: Wouter - Merge #295: Update e-mail addresses, add ref to support contracts 31 August 2023: Wouter - Fix autoconf 2.69 warnings in configure. 14 July 2023: Wouter - Merge #287: Update nsd.conf.5.in. 11 July 2023: Wouter - Fix unused variable warning in unit test of udb. 22 June 2023: Wouter - Fix #284: dnstap_collector.c: SOCK_NONBLOCK is not available on Mac/Darwin. 7 June 2023: Wouter - Merge #282: Improve nsd.conf man page. - Fix unused but set variable warning. - Fix #283: Compile failure in remote.c when --disable-bind8-stats and --without-ssl are specified. 31 May 2023: Wouter - Add missing items to doc/RELNOTES. - Tag for 4.7.0rc1. It became release 4.7.0 on 7 june 2023. The code repository continues with 4.7.1. 30 May 2023: Jeroen - Fix #240: Prefix messages originating from verifier. - Fix #275: Drop unnecessary root server checks. 30 May 2023: Wouter - Next version is 4.7.0, instead of 4.6.2, because of the added features, like TLS for DNSTAP. - Fix unused variable warning in unit test, from clang compile. 24 May 2023: Wouter - For #279: Note that autoreconf -fi creates the configure script and also the needed auxiliary files, for autoconf 2.69 and 2.71. 4 May 2023: Wouter - Fix to remove unused whitespace from acx_nlnetlabs.m4 and config.h. 1 May 2023: Wouter - make depend. - Fix for build to run flex and bison before compiling code that needs the headers. 13 April 2023: Wouter - Fix cirrus script for submit to coverity scan to libtoolize the configure script components config.guess and config.sub. - Fix readme status badge links. 28 March 2023: Wouter - Fix #273: Large TXT record breaks AXFR. - Fix ixfr create from adding too many record types. 16 March 2023: Wouter - Fix include brackets for ssl.h include statements, instead of quotes. - Fix static analyzer warning about nsd_event_method initialization. 15 March 2023: Wouter - Dnstap tls code fixes. 14 March 2023: Wouter - Fix dnstap to not check socket path when using IP address. - dnstap over TLS, default enabled. Configured with the options dnstap-tls, dnstap-tls-server-name, dnstap-tls-cert-bundle, dnstap-tls-client-key-file and dnstap-tls-client-cert-file. - Fix to compile without ssl with dnstap-tls code. 9 March 2023: Wouter - Fix #271: DNSTAP over TCP, with dnstap-ip: "127.0.0.1@3333". - Fix to clean more memory on exit of dnstap collector. 23 February 2023: Wouter - Fix #270: reserved identifier violation. 20 February 2023: Wouter - Merge #269 from Fale: Add systemd service unit. 16 February 2023: Wouter - Fix #266: Fix build with --without-ssl. - Fix #267: Allow unencrypted local operation of nsd-control. - Fix for #267: neater variable definitions. 2 February 2023: Wouter - Merge #265: Fix C99 compatibility issue. 30 January 2023: Wouter - Merge #263: Add bash autocompletion script for nsd-control. - Fix for #262: More error logging for SSL read failures for zone transfers. 27 January 2023: Wouter - Fix #262: Zone(s) not synchronizing properly via TLS. - Fix ixfr_and_restart test to wait for processes to come to a stop. 26 January 2023: Wouter - Fix configure for -Wstrict-prototypes. 10 November 2022: Wouter - Tag for NSD 4.6.1, the repository continues with version 4.6.2. - Fix #239: -Wincompatible-pointer-types warning in remote.c. - Fix unit tests to succeed with --disable-bind8-stats. 1 November 2022: Wouter - Fixup for non-trailing newline lexer change warnings. - Update doc/RELNOTES for changes. - Fix ixfr_gone unit test to not use system default zone list file. - Fix credns tests for vm usage, and not use system default zone list file. - Fix verify tests to use more portable bash location in script. - Fix verify_again test to use ipv4 address for test. 1 November 2022: Tom - Add SVCB dohpath support 28 September 2022: Jeroen - Set ALPN "dot" token during connection establishment as per RFC9103 section 7.1 (Thanks Cesar Kuroiwa). 21 September 2022: Tom - Change zone parsing to accept non-trailing newline. 1 September 2022: Wouter - Merge #231 from moritzbuhl: Fix checking if nonblocking sockets work on OpenBSD. 19 August 2022: Wouter - Update cirrus build script for newer Ubuntu image, and FreeBSD build with libtoolize to install auxiliary files. - Update to clang 14 in cirrus build test on Ubuntu Jammy 22.04. 7 July 2022: Tom - Fix #212: Change commandline control actions to always log. 1 July 2022: Wouter - Fix static analyzer reports, fix wrong log print when skipping xfr, fix to print error on pipe read fail, and assert an xfr is in progress during packet checks. 23 June 2022: Wouter - Tag for 4.6.0rc1. It became 4.6.0 on 30 June 2022, and it continues with version 4.6.1. 17 June 2022: Wouter - Fix compilation with libev, without event_base_loopbreak. 16 June 2022: Wouter - Fix that the unit test verify_repat cleans up nsd on exit. - Fix to remove ixfrcreate.c asserts about uint16 within limits because of warnings from analyzers. 14 June 2022: Wouter - Fix compilation without libevent and compilation of nsd-mem. - Fix verify handler add of sigchld event for compilation without libevent. 3 June 2022: Wouter - Fix static analyzer reports on ixfrcreate temp file. - Fixup wrong ixfrcreate fread return check. 13 May 2022: Wouter - The code repo continues with version 4.5.1. 6 May 2022: Wouter - Merge PR #209: IXFR out This adds IXFR out functionality to NSD. NSD can copy IXFRs from upstream to downstream clients, or create IXFRs from zonefiles. The options store-ixfr: yes and create-ixfr: yes can be used to turn this on. Default is turned off. The options ixfr-number and ixfr-size can be used to tune the number of IXFR transfers and total data size stored. This is configured per zone, the IXFRs are served to the hosts that are allowed to perform zone transfers. And if TSIG is configured, signed with the same key. The content is stored to file if a zonefile is configured for the zone, in the zonefile.ixfr and zonefile.ixfr.2, .. files. They contain readable text format. The number of IXFRs is num.rixfr in statistics output, also per zone if per zone statistics are enabled. If offline, nsd-checkzone -i can create ixfr files. NSD already supports requesting IXFRs, this addition allows NSD to serve IXFR transfers to clients. NSD stops responding with NOTIMPL to IXFR requests, also for zones that do not have IXFR enabled. The clients gets a full zone reply or a status reply if the serial is up to date. - set version to 4.5.0 for feature change. - Tag for 4.5.0rc1 release. It became the 4.5.0 release on 13 May 2022. 14 April 2022: Wouter - Update cirrus script FreeBSD version. 25 March 2022: Wouter - Fix spelling error in comment in svcbparam_lookup_key. 2 March 2022: Wouter - Fix code analyzer zero divide warning. - Fix code analyzer large value with assertion. - Fix another code analyzer zero divide warning. - Fix code analyzer warning about uninitialized temp storage in loop. 10 February 2022: Wouter - Tag for 4.4.0rc1 release. This became 4.4.0 release on 17 Feb 2022, the code repository continues with version 4.4.1. 9 February 2022: Wouter - Fix unit tests for nds-control-setup exit code and the xfrd-tcp-max default. 7 February 2022: Wouter - Merge #207 Sync nsd-control-setup with unbound-control-setup to generate certificates with SANs. 28 January 2022: Wouter - Fix #206: build with --without-ssl fails. 27 January 2022: Wouter - current code branch continues as version 4.4.0, because of added feature. 26 January 2022: Wouter - Merge #193: Lower memory usage of the XFRD process by default. Instead of preallocating all elements, they are allocated when used. There are options for managing the memory usage, defaults are the same as before. xfrd-tcp-max sets the number of sockets for tcp connections that xfrd can make to download zone contents. And xfrd-tcp-pipeline the number of simultaneous transfers over the same connection. 12 January 2022: Wouter - Fix to document nsd-checkzone -p in the man page for nsd-checkzone. 7 January 2022: Wouter - Fix to change file mode before changing file owner for the nsd-control unix socket file. 3 January 2022: Wouter - Merge #204 from jonathangray: correct some spelling mistakes. 15 December 2021: Wouter - Fix #200: nsd-checkzone succeeds even with incorrect serial in SOA record. 2 December 2021: Wouter - Fix socket_partitioning unit test for FreeBSD. - Fix SVCB test to work around older dig with drill. - Fix unit test to not syslog setlogin failures. 1 December 2021: Wouter - Set up for branch for 4.3.9 release. This became release 4.3.9 on 9 Dec 2021 and included the changes until the SVCB fix on 2 dec 2021, but not the setlogin fix. The main branch continues as 4.3.10. - Fix unit tests for new answer-cookie default. 30 November 2021: Wouter - Fix to remove git tracking and ci information from release tarballs. 3 November 2021: Wouter - Fix #198: nsd-control reconfig core dump. 12 October 2021: Wouter - Tag for 4.3.8 release, from 4.3.8rc2. The main branch continues with version 4.3.9 in development. 7 October 2021: Wouter - Set default for answer-cookie to no. Because in server deployments with mixed server software, a default of yes causes issues. - Tag for 4.3.8rc2, includes the new answer-cookie default. 4 October 2021: Wouter - Tag for 4.3.8rc1. 29 September 2021: Wouter - Fix unit tests for svcb and xot to not touch the default zonelistfile. - Fix unit test for xot tertiary config for zonelistfile default. - Fix unit test for dns-cookies for no unshare, and allow-query for no IPv6 loopback. - Fix unit test allow query to check for IPv6. 22 September 2021: Wouter - Fix #194: Incorrect NSEC3 response for SOA query below delegation point. 13 September 2021: Wouter - Fix compile failure with openssl 1.0.2. 3 September 2021: Wouter - Fix not reachable annotation in radix_find_prefix_node. 31 August 2021: Willem - Fix #191: dname_parse_wire() returns fqdn wireformat length. 26 August 2021: Wouter - Fix #190: NSD returns 3 NSEC3 records for NODATA response. 23 August 2021: Wouter - Fix #189: nsd 4.3.7 crash answer_delegation: Assertion `query->delegation_rrset' failed. 17 August 2021: Wouter - Fix #188: NSD fails to build against openssl 1.1 on CentOS 7. - Fix sed script in ssldir split handling. 13 August 2021: Wouter - Merge #187: Support using system-wide crypto policies. 10 August 2021: Wouter - Merge #185 by cesarkuroiwa: Mutual TLS. - Fixes for #185: Document client-cert, client-key and client-key-pw in the man page. Fix yacc semicolon. Fix unused variable warning. Use strlcpy instead of strncpy. Fix spelling error in error printout. 2 August 2021: Wouter - Quieter tpkg/do-tests shell script with -q flag. - For #184: Note that all zones can be targeted by some nsd-control commands in the man page. 30 July 2021: Wouter - Move acx_nlnetlabs.m4 to version 41, with lib64 openssl dir check. - Fix to compile with OpenSSL 3.0.0beta2. - Fix configure detection of SSL_CTX_set_security_level. - Fix deprecated functions use from openssl 3.0.0beta2. 23 July 2021: Wouter - Fix free on shutdown of XoT SSL context. 22 July 2021: Wouter - tag 4.3.7 release, with the fixes between rc1 and this release. - main branch continues for 4.3.8. 20 July 2021: Wouter - Fix typo in xfrd-tcp.c. 15 July 2021: Wouter - tag for 4.3.7rc1. - Fix compile of cookies on FreeBSD without IPv6. - Fix for loop initial declaration for nonc99 compiler. 14 July 2021: Wouter - Fix truncate test for EDNS COOKIE making one less RR is added. - Attempt to fix gcc11 warning. 13 July 2021: Willem - Fixes for child server processes getting out of sync with the dnstap-collector process 13 July 2021: Willem - Interoperable DNS Cookies support as per RFC7873 and RFC9018 9 July 2021: Willem - Client side DNS Zone Transfer-over-TLS (XoT) support as per draft-ietf-dprive-xfr-over-tls 29 June 2021: Willem - Fix #168: Buffer overflow in the dname_to_string() function 14 June 2021: Wouter - Update configure nonblocking test to use host. 25 May 2021: Wouter - Fix #179: log notice and server-count. 21 May 2021: Wouter - Test code has -q option for quiet output. 17 May 2021: Wouter - Update the ACX_CHECK_NONBLOCKING_BROKEN test for the configure script. 7 May 2021: Wouter - Fix #176: please review Loglevel on missing zonefile. 6 May 2021: Wouter - Fix #174: NS Records below delegation are not ignored (nsd-checkzone also does not raise any issue). 4 May 2021: Wouter - Fix SVCB sort call sizeof to be the size of the elements sorted. 29 April 2021: Tom - Implement Syntax of SVCB and HTTPS RR type as per draft-ietf-dnsop-svcb-https 13 April 2021: Wouter - Fix for #128: Skip over sendmmsg invalid argument when port is zero. - Fix #171: Invalid negative response (NSEC3) after IXFR. - Fix to make nsec3_chain_find_prev return NULL if one nsec3 left. - remove debug settings from unit test. 9 April 2021: Wouter - Fix for #170: Fix build warnings when IPv6 is disabled. - Fix #170: Disabled IPv6 and DNSTAP enabled triggers a build error. 30 March 2021: Wouter - Fix configure failure for enable systemd because of autoconf. - This became release 4.3.6, the repository continues for 4.3.7 in development. 29 March 2021: Wouter - Note unlisted changes in RELNOTES and prepare for 4.3.6rc1 tag. 29 March 2021: Willem - Per zone Access Control List for queries with an allow-query: option. 24 March 2021: Wouter - Update acx_nlnetlabs.m4 to version 38, fix deprecation test. - Fix configure to use header checks with compile. - Fix warning about unused function log_addr. 18 March 2021: Tom - Add Extended DNS Errors RFC8914 15 March 2021: Wouter - Fix double config.h include in configlexer.c - Fix to remove configyyrename from makedist.sh and also update the flex and bison rules there to add the "c_" prefix. 13 March 2021: Willem - Fix #154: TXT with parentheses fails in 4.3.5. - Align parsing of TXT elements with how bind does it. - A -p option to nsd-checkzone to print a successfully read zone. 12 March 2021: Wouter - Fix that wildcard is printed as a star instead of escaped, in logs and in written zone files. - Fix unit test for wildcard printout change. 11 March 2021: Wouter - Fix #163: A TSIG noncompliance with RFC 2845. 9 March 2021: Willem - Enable configuring a control-interface by interface name. 19 February 2021: Wouter - Fix segfault on high verbosity for TLS channels with dnstap log local address. 18 February 2021: Wouter - Fix #146 with #147: DNSTAP log the local address of the server with the dnstap logs. 16 February 2021: Wouter - Man page documentation for dnstap options. 8 February 2021: Wouter - Fix AF_LOCAL compile error for Solaris. - Fix ifaddrs compile error for Solaris. - Fix ifaddrs.h compile error for Solaris. 4 February 2021: Wouter - Merge PR #153 from fobser: Repair -fno-common linker errors automatically. - Fix uninitialized access of log_buf in error printout on apply ixfr. 26 January 2021: Wouter - Prevent a few more yacc clashes. 19 January 2021: Wouter - Set branch ready for 4.3.5 release. Tag for 4.3.5rc1. Became the 4.3.5 release on 26 january 2021. This branch continues with 4.3.6 in development. 15 January 2021: Wouter - Fix #152: '*' in Rdata causes the return code to be NOERROR instead of NX. - Add config.guess and config.sub to .gitignore for autoconf 2.70. - Fix #150: TXT record validation difference with BIND. - Fixup TXT record validation fix for escaped quotes. - Fixup TXT record validation fix for escaped backslashes. - Fixup escape character parse for quoted strings. 11 January 2021: Wouter - Fix #151: DNAME not applied more than once to resolve the query. - Fix dname test for #148. - For #151: fix to not produce loops in output. 5 January 2021: Wouter - Fix configure.ac for autoconf 2.70. 4 January 2021: Wouter - Fix #148: CNAME need not be followed after a synthesized CNAME for a CNAME query. 11 December 2020: Wouter - Fix that nsd-control has timeout when connection is down. - remove windows socket ifdefs from nsd-control. 3 December 2020: Wouter - For #145: Fix that service of remaining TCP and TLS connections does not allow new queries to be made, the connection is closed. Only existing queries and zone transfers are answered, new ones are rejected by a close of the channel. 30 November 2020: Wouter - Fix #144: fix better. 27 November 2020: Wouter - Fix #144: Typo fix in nsd.conf.5.in. 26 November 2020: Wouter - Fix #143: xfrd no hysteresis with NOT IMPLEMENTED rcode. 24 November 2020: Wouter - Merge PR #141: ZONEMD RR type. - tag for 4.3.4rc1. This became 4.3.4 release on 1 dec 2020. The code repo continues for 4.3.5 in development. 23 November 2020: Wouter - Fix #142: NODATA answers missin SOA in authority section after CNAME chain. - Fix for CVE-2020-28935 : Fix that symlink does not interfere with chown of pidfile. - fix writepid for retvalue 0. 9 November 2020: Wouter - Fix #138: NSD returns non-EDNS answer when QUESTION is empty. - Fix to check nscount in previous fix for EDNS in formerr response when there is no question. 28 October 2020: Wouter - Remove unused init_cfg_parse routine from configlexer. 20 October 2020: Wouter - Fix to add missing closest encloser NSEC3 for wildcard nodata type DS answer. 14 October 2020: Wouter - Fix #134: IPV4_MINIMAL_RESPONSE_SIZE vs EDNS_MAX_MESSAGE_LEN. 13 October 2020: Wouter - Fix missing parenthesis on size of fix to init buffer. 12 October 2020: Wouter - Fix #127: two minor `-Wcast-qual` cleanups - Fix #126: minor header hygiene - Fix #125: include config.h in compat/setproctitle.c and fix prototype of `setproctitle` - Fix #133: fix 0-init of local ( stack ) buffer. 8 October 2020: Wouter - tag for 4.3.3 release - current repository contains 4.3.4 in development. - Fix #129: ambiguous use of errno, in log message if sendmmsg fails. - Fix #128: Fix that the invalid port number is logged for sendmmsg failed: Invalid argument. 1 October 2020: Wouter - tag for 4.3.3rc1 release. 30 September 2020: Wouter - Updated date in nsd -v output. - Fixup bug013_truncate, checkconf and cutest_qroot tests for new default EDNS size. 29 September 2020: Willem - Follow DNS flag day 2020 advice and set default EDNS message size to 1232. 4 September 2020: Wouter - Remove unused space from LIBS on link line. 3 September 2020: Wouter - Merge PR #121: Increase log level of recreated database from WARNING to ERR. 1 September 2020: Wouter - Fix #119: fix compile warnings from new gcc. - Fix #119: warn when trying to parse a directory. 27 August 2020: Wouter - Merged PR #113 with fixes. Instead of listing an IP-address to listen on, an interface name can be specified in nsd.conf, with ip-address: eth0. The IP-addresses for that interface are then used. 26 August 2020: Wouter - Add xstrdup for PR #113. - Tidy up code like in PR #113. - Import code from PR #113. - Fix for unknown EVP_MAC_CTX_free function in openssl 3.0.0 tsig code. 24 August 2020: Wouter - Fix that configure checks for EVP_sha256 to detect openssl, because HMAC_CTX_new is deprecated in 3.0.0. - Port TSIG code for openssl 3.0.0-alpha6. - Sync acx_nlnetlabs.m4 with the unbound repo. - Review fixes for tsig, defensive free and zero. 4 August 2020: Wouter - Merge #117: mini_event.h (4.3.2 and 4.3.1) on OpenBSD cannot find fd_set - patch. 23 July 2020: Wouter - Merge #115 from millert: Fix strlcpy() usage. From OpenBSD. 15 July 2020: Wouter - Fix make install with --with-pidfile="". 14 July 2020: Wouter - Tag for 4.3.2 release. Master branch contains the next version in development, 4.3.3. 7 July 2020: Wouter - Tag for 4.3.2rc1. 6 July 2020: Wouter - Fix compile includes for xfr-inspect tool on FreeBSD. - Add tpkg/run_vm.sh that runs test when in a virtual machine. - Merge #112 from jaredmauch: log old and new serials when NSD rejects an IXFR due to an old serial number. - Fix bug034 test for vm test changes. 22 June 2020: Wouter - Remove errno reset behaviour from sendmmsg and recvmmsg replacement functions. - Fix unit test for different nsd-control-setup -h exit code. 19 June 2020: Wouter - Merge #108 from Nomis: Make the max-retry-time description clearer. - Retry when udp send buffer is full to wait until buffer space is available. 18 June 2020: Wouter - Do not log EAGAIN errors for sendmmsg, to stop log spam on OpenBSD. 17 June 2020: Wouter - Fix #107: nsd -v shows configure line, openssl version and libevent version. 27 May 2020: Wouter - Fix unlink of pidfile warning if not possible due to permissions, nsd can display the message at high verbosity levels. - Update contrib/nsd.service for chown of nsd.log and /var/log in ReadWritePaths. - Removed contrib/nsd.service, example is too complicated and not useful. 15 May 2020: Wouter - Merge PR#102 from and0x000: add missing default in documentation for drop-updates. - Fix checkconf test for log-only-syslog option. 14 May 2020: Wouter - Document default value for tcp-timeout. 13 May 2020: Jeroen - Fix #99: Fix copying of socket properties with reuseport enabled. 24 April 2020: Wouter - Fix #97: EDNS unknown version: query not in response. 21 April 2020: Wouter - Fix #96: log-only-syslog: yes sets to only use syslog, fixes that the default configuration and systemd results in duplicate log messages. 20 April 2020: Wouter - Fix #95: Removed make test check because tpkg not included in release tarballs. - Fix unused parameter compile warnings. 16 April 2020: Wouter - Tag for 4.3.1 release and track 4.3.2 release in code repository. - note sha256 digest algo use in makedist.sh. - Fix for posix shell syntax for trap in nsd-control-setup. - Fix to omit the listen-on lines from log at startup, unless verbose. - Fix uninitialised values for bindtodevice option at startup with reuseport and multiple interfaces. 8 April 2020: Wouter - Tag for 4.3.1rc2. 7 April 2020: Wouter - Merge PR #91 by gearnode: nsd-control-setup recreate certificates. The '-r' option recreates certificates. Without it it creates them if they do not exist, and does not modify them otherwise. 6 April 2020: Wouter - Merge PR #90 by phicoh: O_CLOEXEC should be FD_CLOEXEC. - Merge PR #92 by tonysgi: Fix typo. 2 April 2020: Wouter - Tag for 4.3.1rc1. 1 April 2020: Wouter - Fix for whitespace in minimal responses test for FreeBSD. 25 March 2020: Wouter - Merge PR #86 from noloader: Use precious variables for GREP, EGREP, SED, AWK, LEX and YACC. - For PR #86: Fix that programs loaded after CFLAGS and stuff is set, specifically the compiler, so that it can work if it needs special flags from that. Fix that lex only needs to support -i if actually defined, otherwise the output included in the source tarball can be used. - Merge PR #72 from noloader: Increase Travis testing coverage 23 March 2020: Wouter - Fix unterminated ifdef in nsd.h. - Fix unknown u_long in util.c for Issue #80 . 20 March 2020: Wouter - Merge PR #83 from noloader: Fix GNU HURD sched_setaffinity compile. - Fix #82: print error when system does not have setaffinity. - Fix #80: NetBSD and implicit declaration of reallocarray. - Fix for #80: Fix reallocarray test to define before include. - Fix for #80: Define alternatives for IFNAMSIZ if it does not exist. 19 March 2020: Wouter - Fix #76: cpuid typedef for Hurd, DragonflyBSD compile. - Fix #75: configure test for sched_setaffinity, and use cpuset_setaffinity otherwise. Also test for presence of sysconf. - Fix #74: GNU Hurd fix cast from pointer to integer of different size. - Fix for #74, #75: cpuset test for header contents and provide code. - Fix #78: Fix SO_SETFIB error on FreeBSD. 18 March 2020: Wouter - Fix #70: error: 'fd_set' undeclared. - Fix #71: error: 'for' loop initial declaration used outside C99 mode. - Fix to move declarations out of for loops in event test too. - Fix to move declarations out of for loops in popen3 test too. - Another fix to move declaration out of for loop for event test. - Fix to move declarations out of for loops in cutest regex display. 17 March 2020: Wouter - tag for 4.3.0 release and master branch has version 4.3.1. 10 March 2020: Wouter - repository has version number 4.3.0. Tag for 4.3.0rc1. 3 March 2020: Wouter - Fix that the retry wait does not exceed one day for zone transfers. 27 February 2020: Wouter - Fix warning on FreeBSD about pointer size cast. 26 February 2020: Wouter - Fixup fix of reuseport TCP for server close of sockets not used by it. And the unit test skips when the necessary debug output is not enabled. 25 February 2020: Wouter - Fix event unit test, signal has to be registered with signal_add, event_add not for every backend for signals. The event_initialized is not possible for every backend, so event_added variable. The agent write event fires after a timeout, instead of on event write so that it does not trigger a sigpipe event when the handlers stop. Timeout shorted to 0.1 second. event_get_fd was not implemented, so used ev_fd. Debug output printfs added to see what happens. - Fix checkconf test for new drop-updates config option. - Fix errors with reuseport and TCP file descriptors, it was closing them for server-1 in server-2 and server-3.. 7 February 2020: Jeroen - Add feature to drop queries with opcode UPDATE. 6 February 2020: Jeroen - Support SO_BINDTODEVICE on Linux. Specify bindtodevice: yes to bind sockets directly to the network interface. - Support SO_SETFIB on FreeBSD. Add setfib= after an ip-address option to use the specified FIB for that socket. - Require user to add servers= after an ip-address option to specify the servers that must listen on that socket. 6 February 2020: Wouter - Merge PR#60: Minor portability fixes from michaelforney, with avoid pointer arithmetic on void* and avoid unnecessary VLA. 4 February 2020: Wouter - Merge PR#22: minimise-any: prefer polular and not large RRset, from Daisuke Higashi. - Fix responses for IXFR so that the authority section is not echoed in the response. 21 January 2020: Wouter - Fix leak in server bitset setup. 16 January 2020: Jeroen - Add zone resource record iterator for future zone-verification port. - Set FD_CLOEXEC on opened sockets. - Add popen3 implementation for future zone-verification port. - Add -r option to cutest so that a subset of tests can be run. 15 January 2020: Jeroen - Add feature to pin server proccesses to specific cpus. - Add feature to pin IP addresses to selected server processes. - Set process title to identify individual processes. 13 January 2020: Wouter - Merge pull request #59 from buddyns: add FreeBSD support for conf key ip-transparent. 10 January 2020: Wouter - Fix unreachable code in ssl set options code. - Fix bad shift in assertion code analyzer complaint. 6 January 2020: Wouter - Fix #56: Drop sparse TSIG signing support in NSD. Sign every axfr packet with TSIG, according to the latest draft-ietf-dnsop-rfc2845bis-06, Section 5.3.1. 12 December 2019: Wouter - Note that use-systemd is not necessary and ignored in man page. 11 December 2019: Wouter - Fix whitespace in nsd.conf.sample.in, patch from Paul Wouters. - use-systemd is ignored in nsd.conf, when NSD is compiled with libsystemd it always signals readiness, if possible. 9 December 2019: Wouter - Fix to define upper bounds on rr counts read from untrusted packet data. - Try different annotation for radix_find_prefix_node not reachable. - Separate acl_addr_match_range functions for ip4 and ip6, to please checkers. - Avoid unused variable warning in new match_range_v4 function. 6 December 2019: Wouter - Fix to define max number of EDNS records we are willing to spend time on. - Fix size of string len and capacity type cast in udbradtree. - Fix to protect rrcount in tsig_find_rr from overflow. - Annotate radix_find_prefix_node not reachable trail code. - Fix to protect rrcount in packet_find_notify_serial from overflow. - Fix to close socket on error in create_tcp_accept_sock. - Fix to log on failure to chmod for socket for remote control. - Fix to remove unneeded if in open of socket for remote control. - Fix to restore input parameter on call failure in create_dirs. - Please checker by terminating and initialising string read by remote control. - Fixup of random_generate negative modulo, from previous commit, and return srandom when random is used if no getrandom. 5 December 2019: Wouter - Fix fname null check of fname in namedb_read_zonefile. - Fix implicit cast of size in udb_radnode_array_grow. - Fix ignore of return value of ssl_printf in remote.c. - Fix unused check of fd in parent_handle_reload_command. - Fix to use getrandom() for randomness, if available. - Attempt to fix signedness of nscount lookup in ixfr query_process. - Fix identical branches for ssl_print of errors in remote.c. - Fix type cast bounds, signedness of opt_rdlen in edns_parse_record. - Fix to separate header and data lines in parse_zone_list_file. 3 December 2019: Wouter - Fix #52: do not log transient network full errors unless higher verbosity is set. - Fix checkconf test for new error output string. - tag for 4.2.4rc1 release. This became the 4.2.4 release, and the master branch continues with 4.2.5 in development. 27 November 2017 Jeroen - Fix regressions in configparser.y 22 November 2019: Wouter - Fix #48: Add make distclean that removes config.h made by configure. And add maintainer-clean that removes bison and flex output. 18 November 2019: Wouter - Detect fixed time memcmp for openssl 0.9.8 compatibility. - Detect EC_KEY_new_by_curve_name for openssl 0.9.8. - include limits.h for UINT_MAX. - If no recvmmsg, dont use msg_flags member, but errno for error, where our fallback function left it, msg_flags also does not exist on some systems. - Remove unused variable warning for portability. 14 November 2019: Wouter - Fix checkconf test with filenames that sort in the same order. - Tag for 4.2.3rc1. Branch master is 4.2.4 in development. 11 November 2019: Wouter - Fix #44: document that remote-control is a top-level nsd.conf attribute. - Fix compile on OSX. - Fix for #44: nicer top-level clause documentation. 22 October 2019: Jeroen - Number of different UDP handlers has been reduced to one. recvmmsg and sendmmsg implementations are now used on all platforms. Compatible implementations are in place for systems that lack the system calls. - Socket options are now set in designated functions for easy reuse. - Socket setup has been simplified for easy reuse. - Configuration parser is now aware of the context in which an option was specified. 21 October 2019: Wouter - For #21 add contrib/patch_for_s6_startup_and_other_service_supervisors.diff that adds support for readiness notification with READY_FD from Cameron Nemo. 17 October 2019: Jeroen - Fix #40: Merge small fixes for confine-to-zone by Greg Bock. 15 October 2019: Jeroen - For #39: Merge confine-to-zone feature contributes by Greg Bock. 26 September 2019: Wouter - Fix #38: log address and failure reason with tls handshake errors, squelches (the same as unbound) some unless high verbosity is used. - Fixup clang analysis warning in xfrd_parse_received_xfr_packet master dereference. 25 September 2019: Wouter - The nsd.conf includes are sorted ascending, for include statements with a '*' from glob. 16 September 2019: Wouter - Fixup warnings during --disable-ipv6 compile. - Fixup unit test executable to run without IPv6. 4 September 2019: Wouter - Fix #35: excessive logging of ixfr failures, it stops the log when fallback to axfr is possible. log is enabled at high verbosity. 2 September 2019: Wouter - For #21: pidfile "" allows to run NSD without a pidfile, for startup management tools like daemontools. 28 August 2019: Wouter - In tests check for tls test tool availability. 19 August 2019: Wouter - Tag for 4.2.2 release. Git master contains 4.2.3 in development. 13 August 2019: Wouter - Fix error message for out of zone data to have more information. - Tag for 4.2.2rc2. 12 August 2019: Wouter - Fix #33: Fix segfault in service of remaining streams on exit. 6 August 2019: Wouter - Tag for 4.2.2rc1. 5 August 2019: Wouter - PR #31: nsd-control: Add missing stdio header. - PR #32: tsig: Fix compilation without HAVE_SSL. - Cleanup tls context on xfrd exit. 31 July 2019: Wouter - Fix #29: SSHFP check NULL pointer dereference. - Fix #30: SSHFP check failure due to missing domain name. - Fix to timeval_add in minievent for remaining second in microseconds. 22 July 2019: Wouter - Set timeout for refetch immediately, only spread load when there are retries. 19 July 2019: Wouter - Set no renegotiation on the SSL context to stop client session renegotiation. 18 July 2019: Wouter - Fix #25: NSD doesn't refresh zones after extended downtime, it refreshes the old zones, with a random delay of a couple of seconds to spread the load. - Fix so that expired zones stay expired when server is down a long time. 17 July 2019: Wouter - Fix that NSD warns for wrong length of the hash in SSHFP records. 15 July 2019: Wouter - PR #23: Fix typo in nsd.conf man-page. 4 July 2019: Wouter - Set version to 4.2.2 in development. - clean memory on exit of nsd-checkzone for memory debug. - Fix #20: CVE-2019-13207 Stack-based Buffer Overflow in the dname_concatenate() function. Reported by Frederic Cambus. It causes the zone parser to crash on a malformed zone file, with assertions enabled, an assertion catches it. - Fix #19: Out-of-bounds read caused by improper validation of array index. Reported by Frederic Cambus. The zone parser fails on type SIG because of mismatched definition with RRSIG. 2 July 2019: Wouter - Tag for 4.2.1rc1 27 June 2019: Wouter - Fix unit test for added options and no dot after zone updated log message. - Fix compile without accept4. 21 June 2019: Wouter - Omit remaining tcp processing if the list is empty. - Fix output of nsd-checkconf -h. 20 June 2019: Wouter - Initialize event structures before event_set, to stop uninitialized values from setting event library lists and assertions, that would sometimes also show after event_del. - Added num.tls and num.tls6 stat counters. - PR #12: send-buffer-size, receive-buffer-size, tcp-reject-overflow options for nsd.conf, from Jeroen Koekkoek. - Do not use symbol from libc, instead use own replacement, if not available, for accept4. - Fix #14, tcp connections have 1/10 to be active and have to work every second, and then they get time to complete during a reload, this is a process that lingers with the old version during a version update. 19 June 2019: Wouter - Fix tls handshake event callback function mistake, reported by Mykhailo Danylenko. 18 June 2019: Wouter - Fix #15: crash in SSL library, initialize variables for TCP access when TLS is configured. 14 June 2019: Wouter - Fix to init event not pointer, in reassignment. 12 June 2019: Wouter - Fix to init event structure for reassignment. 11 June 2019: Wouter - NSD 4.2.0 release. Current development is 4.2.1. - Fixup of RELNOTES, corrected RFC reference for 4892. - Fix #13: Stray dot at the end of some log entries, removes dot after updated serial number in log entry. - Fix TLS cipher selection, the previous was redundant, prefers CHACHA20-POLY1305 over AESGCM and was not as readable as it could be. - Consolidate server tls context create and remote control context create, with hardening for the remote control tls context too. 6 June 2019: Wouter - NSD 4.2.0rc1 tag. 4 June 2019: Wouter - Fix unit test for outgoing interface to use random port numbers for the outgoing interface config. 29 May 2019: Wouter - Fix to guard _OPENBSD_SOURCE from redefinition. 28 May 2019: Wouter - Fix to define _OPENBSD_SOURCE to get reallocarray on NetBSD. 16 May 2019: Wouter - Fix #10: Fix memory leaks caused by duplicate rr and include instructions. 6 May 2019: Wouter - Note CII best practices badge for NSD on the README.md. 2 May 2019: Wouter - Fix .gitignore for unit test generated files. - Fix checkconf unit test for hide-identity and tls. 1 May 2019: Wouter - Fix makedist.sh for use with git. - Nicer output on travis for clang analysis. - Add .gitignore file to exclude built files from version tracking. - Add README.md file in repository with compile instructions. - Fix .gitignore for dnstap files and aclocal temp. - Add aclocal to README.md for pkgconfig for some configure options. 25 April 2019: Wouter - Add tls.tpkg unit test for DNS over TLS functionality. 18 April 2019: Wouter - Fix to avoid buffer alloc with global buffer in tls write handler. - Fix to initialize event structure when accepting TCP connection. - Use travis for build check, initial unit test and clang analysis. - Disable SSLv2,3,TLSv1.0,1.1 if TLS1.2 is available in libssl. - Disable weak ciphers, enable CIPHER_SERVER_PREFERENCE. - further setup ssl ctx after the keys are loaded, for ECDH. - TLS OCSP stapling support, enabled with tls-service-ocsp: filename, patch from Andreas Schulze. 17 April 2019: Wouter - Fix to share openssl init code, and perform it once. 16 April 2019: Andreas via Sara - Patch to add support for TCP Fast Open - Patch to add support for tls service on a specified tls port 16 April 2019: Wouter - Fix #4249: The option hide-identity: yes stops NSD from responding with the hostname for chaos class queries. Implements the RFC4829 security considerations. - Remove starttls, this signalling method was not standardized. - Remove TO bit, this signalling method was not standardized. - Remove unused first_query and tls_ok states. - Remove sign-compare warning in tls packet send code. - Fix spelling in comment and log printout. - Fix potential uninitialized variable. - Fix documentation for DNS over TLS, and set default port 853. - Fix to add missing comment. - Fix that the TLS handshake routine sets the correct event to continue when done. - Fix that TLS renegotiation calls the read and write routines again with the same parameters when the desired event has been satisfied. - Fix that TCP Fastopen has better error message and supports OSX. - Fix log for fastopen with verbosity. - Squelch TLS handshake failure log until verbosity 3. - Add per-zone statistics for TLS queries, and dnstap for TLS queries, and rcode and TCflag statistics for TCP and TLS queries. 25 March 2019: Wouter - Print IP address when bind socket fails with error. 21 March 2019: Wouter - Fix spelling error in release notes. - Fix to delete unused zparser.default_apex member. 19 March 2019: Wouter - tag 4.1.27rc1. This became 4.1.27 on 25 March 2019 and trunk has 4.1.28 in development. 18 March 2019: Wouter - Fix unit test bug013_truncate for new truncation with EDNS size, it is one RR smaller for the truncated response in the test. 14 March 2019: Wouter - Fixed radtree_insert memory leak. - Fixed access recycled variable. 11 March 2019: Wouter - Fix #6: nsd-control-setup: Change validity time to a shorter period (<2038). - Fix unused definition in header remote.h. - Fix #4236: IPV4_MINIMAL_RESPONSE_SIZE=1480 is slightly too big. - Fix #4235: IP_PMTUDISC_OMIT on IPv4/UDP sockets. 18 February 2019: Wouter - Fix to remove unused code. 15 February 2019: Wouter - tentative robustness, delete stats items from list twice if needed. 14 February 2019: Wouter - Fix #4: setusercontext() is in libutil on NetBSD, and also include login_cap.h only if it exists. - Fix #4215: fixup for state update for TSIG information in server processes, nicer printout for tsig_print, tsig_print without arguments and no leaks. - nicer logging for update_tsig. 1 February 2019: Wouter - Fix for tsig assoc_tsig command on acl with nokey elements. 29 January 2019: Wouter - Fix #4215: on-the-fly change of TSIG keys with patch from Igor, adds nsd-control print_tsig, update_tsig, add_tsig, assoc_tsig and del_tsig. These changes are gone after reload, edit the config file (or a file included from it) to make changes that last after restart. - documentation for tsig nsd-control options. 24 January 2019: Wouter - Deny ANY with only one RR in response, by default. Patch from Daisuke Higashi. The deny-any statement in nsd.conf sets ANY queries over UDP to be further moved to TCP as well. Also no additional section processig for type ANY, reducing the response size. - assertions for clang analysis. 10 December 2018: Wouter - Fix for FreeBSD port with dnstap enabled. 6 December 2018: Wouter - Fix to reduce region_log_stats if condition, this removes a debug statement. 5 December 2018: Wouter - Fix #4213: disable-ipv6 and dnstap compile error. 3 December 2018: Wouter - Note that the content_list member is unused; and could be removed if the database format is modified or updated. - Fix that dnstap logs CQ and CR like BIND does. - Revert that, it looks wrong, AQ and AR are for the authoritative. 29 November 2018: Wouter - Tag for 4.1.26rc1. Which became 4.1.26 on 4 dec 2018. Trunk has 4.1.27 in development. - Fix clang analysis warning on null in closest encloser for wildcard denial nsec. - Fix clang analysis warnings. 27 November 2018: Wouter - Fix parsezone failure in 4194 fix. 26 November 2018: Wouter - Fix to not set GLOB_NOSORT so the nsd.conf include: files are sorted and in a predictable order. - Added nsd-control changezone. nsd-control changezone name pattern allows the change of a zone pattern option without downtime for the zone, in one operation. - Fix #3433: document that reconfig does not change per-zone stats. 20 November 2018: Wouter - Fix #4205: enable-recvmmsg in mixed IPv4/IPv6 environment fails. This sets the msg_hdr.msg_namelen correctly after receipt. 19 November 2018: Wouter - Support SO_REUSEPORT_LB in FreeBSD 12 with the reuseport: yes option in nsd.conf. - Fix #4202: nsd-control delzone incorrect exit code on error. - Tab style fix to use tab for 8 spaces, from Xiaobo Liu. 25 October 2018: Wouter - Adjust dnstap socket path for chroot. 22 October 2018: Wouter - Fix #4194: Zone file parser derailed by non-FQDN names in RHS of DNSSEC RRs. - Fix some more, neater code and checks for domain length limit. - check that the dnstap socket file can be opened and exists, print error if not. 4 October 2018: Wouter - dnstap work, the dnstap.proto is a copy of the file from Unbound, also dnstap.m4 configure include file. - dnstap collector: free eventbase and memclean nicer. - dnstap collector: send data and read it in collector. - dnstap/dnstap.c and .h from Unbound's contribution from Farsight Security, added to then adapt it for dnstap logging in NSD. - dnstap.c with auth query and auth response, and called from the collector. - dnstap work, config nsd.conf parse. - dnstap example config. 25 September 2018: Wouter - NSD 4.1.25 released, trunk has 4.1.26 in development. 18 September 2018: Wouter - tag for NSD 4.1.25rc1. 17 September 2018: Wouter - Fix #4156: Fix systemd service manager state change notification 14 September 2018: Wouter - Remove unused if clause during server service startup. 13 September 2018: Wouter - Fix typo in clang analysis test. - Annotate exit functions with noreturn. - nsd-control prints neater errors for file failures. 12 September 2018: Wouter - clang analysis test. 11 September 2018: Wouter - Fix to combine the same error function into one, from Xiaobo Liu. - Fix initialisation in remote.c. - please clang analyzer and fix parse of IPSECKEY with bad gateway. - Fix unit test code for clang analyzer. - Fix nsd-checkconf fail on bad zone name. 10 September 2018: Wouter - Fix coding style in nsd.c 7 September 2018: Wouter - append_trailing_slash has one implementation and is not repeated differently. 4 September 2018: Wouter - Fix codingstyle in nsd-checkconf.c in patch from Sharp Liu. 15 August 2018: Wouter - Fix use_systemd typo/leftover in remote.c. 13 August 2018: Wouter - tag for 4.1.24 release. - trunk is 4.1.25 in development. - Fix that nsec3 precompile deletion happens before the RRs of the zone are deleted. - Fix printout of accepted remote control connection for unix sockets. 6 August 2018: Wouter - tag for 4.1.24rc1 release. 30 July 2018: Wouter - Tag for NSD 4.1.23 release, trunk is 4.1.24, includes fix NSD time sensitive TSIG compare vulnerability. - Fix checkconf test for use-systemd option. 25 July 2018: Wouter - #4133: Fix that when IXFR contains a zone with broken NSEC3PARAM chain, NSD leniently attempts to find a working NSEC3PARAM. 23 July 2018: Wouter - Remove socket activation from systemd code, it was reported as not useful to enable. The readiness signalling is still there, and can be enabled with use-systemd: yes. - Only call sd_notify from systemd when use-systemd is yes. 6 July 2018: Wouter - RFC8162 support, for record type SMIMEA. - Fix that type CAA (and URI) in the zone file can contain dots when not in quotes. 26 June 2018: Wouter - configure --enable-systemd (needs pkg-config and libsystemd) can be used to then use-systemd: yes in nsd.conf and use socket activation and readiness signalling with systemd. 19 June 2018: Wouter - #4106: Fix that stats printed from nsd-control are recast from unsigned long to unsigned (remote.c). 14 June 2018: Wouter - Fix that first control-interface determines if TLS is used. Warn when IP address interfaces are used without TLS. 12 June 2018: Wouter - #4102: control interface via local socket. configure it with control-interface: "/path/nsd.ctl" The path has to start with a / to separate it from an IP address. The local socket does not use SSL, but unencrypted traffic, use file and containing directory permissions to restrict access. 6 June 2018: Wouter - Patch to fix openwrt for mac os build darwin detection in configure. 4 June 2018: Wouter - tag for 4.1.22rc1. Became 4.1.22 on 11 June, trunk is 4.1.23 in development from this point. 31 May 2018: Wouter - Fix to use same condition for nsec3 hash allocation and free. 23 May 2018: Wouter - Use accept4 to speed up answer of TCP queries, on Linux and FreeBSD and OpenBSD. 22 May 2018: Wouter - Fix nsec3 hash of parent and child co-hosted nsec3 enabled zones. 15 May 2018: Wouter - Fix memory free in unit test. 14 May 2018: Wouter - Tag for 4.1.21 release. - trunk has 4.1.22 in development. - refuse-any sends truncation (+TC) in reply to ANY queries over UDP, and allows TCP queries like normal. 7 May 2018: Wouter - Tag for 4.1.21rc1 release. 4 May 2018: Wouter - Fix #4093: Release notes not using 2018. 3 May 2018: Wouter - Fix buffer size warnings from compiler on filename lengths. 26 April 2018: Wouter - lower memory usage for tcp connections, so tcp-count can be higher. - Fix checkconf test for refuse-any option. 3 April 2018: Wouter - refuse-any nsd.conf option that refuses queries of type ANY. 5 March 2018: Wouter - Fix #3562: explain build error when flex missing. 20 February 2018: Wouter - For more clang warnings - Fix spelling error in xfr-inspect. 19 February 2018: Wouter - Fix for clang analysis complaints. 15 February 2018: Wouter - --enable-memclean cleans up memory for use with memory checkers, eg. valgrind. - Fix unused variable warnings from clang analyzer. 14 February 2018: Wouter - updated RELNOTES for upcoming release. - tag 4.1.20rc1, became release on 20 feb, trunk has 4.1.21 in development. 9 February 2018: Wouter - make depend: updated the make dependencies in the Makefile. 8 February 2018: Wouter - Fix memory leak when rehashing nsec3 after axfr or zonefile read, in the selectively allocated precompiled nsec3 hashes. 6 February 2018: Wouter - Fix memory leak in zone file read of unknown rr formatted RRs. 11 December 2017: Wouter - Add test for support of -Wno-address-of-packed-member for --enable-packed. - tag for release 4.1.19 - trunk has 4.1.20 in development. 8 December 2017: Wouter - tag for 4.1.19rc1 7 December 2017: Wouter - Fixup lexer warning for gcc 4.2. 6 December 2017: Wouter - Fix 3392: Fix regression in 4.1.18 for notify lists with ip4 and ip6 targets. 5 December 2017: Wouter - Fix spelling error in xfr-inspect. 1 December 2017: Wouter - Fix warnings emitted by clang for --enable-packed. Alignment is not a problem for x86_64, don't enable packed when the platform requires aligned access. 30 November 2017: Wouter - tag for 4.1.18 release. - trunk has 4.1.19 in development. - ignore fallthrough compiler warning in flex EOF rule. 27 November 2017: Wouter - Fix crash for DS query when parent and child zones both configured in nsd.conf and parent zone has not loaded properly. - tag for 4.1.18rc2. 16 November 2017: Wouter - tag for 4.1.18rc1. 14 November 2017: Wouter - Fix #2871: Increase number of sockets for xfrd transfers. 6 November 2017: Wouter - Set usage counts in namedb tree to uint32 to save memory. - Fix up debug content from nsec3 collision printout work. 2 November 2016: Wouter - make ip-transparent option work on OpenBSD. 11 October 2016: Wouter - Fix #1567: Change crit to err log level for gettimeofday failure. Add defines for compile without syslog. 9 October 2016: Wouter - Fix collision printout of nsec3 to print name, hash and reverse. 2 October 2016: Wouter - nsd-control zonestatus prints wait time between attempts, for zones that are in that waiting time. 19 September 2016: Wouter - merges feature branch branches/alloced_prehashes into trunk. 18 September 2016: Wouter - Fix #1446: A corrupted zone file "propagates" to good ones. 14 September 2016: Wouter - Fix layout in xfrd.c. 6 September 2017: Willem - Save memory by selectively allocate precompiled nsec3 hashes 29 August 2016: Wouter - With --enable-packed save memory, at expense of unaligned reads. - Fix writev compile warning on FreeBSD. 25 July 2016: Wouter - NSD sends up to 16 notifies simultaneously for up to 64 zones, to increase rate of notification for large master configurations. 24 July 2016: Wouter - Fix gcc 7.1.1 warnings. 17 July 2016: Wouter - Trunk has 4.1.18 - xfr-inspect is part of source dir, but not made or installed by default. - retry timeout between sending notifies dropped from 15 to 3 sec. 13 July 2016: Wouter - tag 4.1.17rc1, and that became the 4.1.17 release on 21 July 2017. 29 June 2016: Wouter - make depend. 26 June 2016: Wouter - Fix text format of deletes for CDS and CDNSKEY, single 0 to represent empty base64 or hex string. 23 June 2016: Wouter - Fix potential null pointer in nsec3 adjustment tree. 15 June 2016: Wouter - xfr-inspect debug tool prints out xfr contents of files in tmp. 6 June 2016: Wouter - Fix #1272: use writev to put tcp length field with data for outgoing zone transfer requests. 16 May 2016: Wouter - zone parser parses type AVC (it has TXT format). 25 April 2016: Wouter - 4.1.16 release tag. - trunk contains 4.1.17 in development. 11 April 2016: Wouter - 4.1.16 rc1 tag for release. - minor manpage fix. 5 April 2016: Wouter - Patch for expire state in multi-master when masters includes broken master. 27 March 2016: Wouter - Fix 1243: Option to make NSD emit really minimal responses, minimal-responses: yes in nsd.conf. - but they give additional information for priming queries (type NS). 6 March 2016: Wouter - Fix 1228: OpenSSL include is not guarded with HAVE_SSL 28 February 2016: Wouter - Printout serial error with hint it may be too big. 20 February 2016: Wouter - Fix missing _t to _type conversion for disable-radix-tree option. 15 February 2016: Wouter - zone parser can parse acronyms for algorithms ED25519 and ED448. 13 February 2016: Wouter - Calculate new udb index after growing the array, fix from Chaofeng Liu. 7 February 2016: Wouter - tag for 4.1.15 rc1. Which became 4.1.15 on 16 Feb. Trunk 4.1.16. 19 January 2016: Wouter - Fix to rename _t typedefs because POSIX reserves them. 3 January 2016: Wouter - Fix #1195: Fix so that NSD fails on non-compliant values for Serial. 14 December 2016: Wouter - Squelch zone transfer error address family not supported by protocol at low verbosity levels. 13 December 2016: Wouter - Fix nsd-control and ipv6 only. 8 December 2016: Wouter - tag 4.1.14 - trunk contains 4.1.15 in development. 1 December 2016: Wouter - Fix restart of zone transfers when new config becomes available. - tag 4.1.14rc1 25 October 2016: Wouter - Fix #1132 for SERVFAIL zones perform backoff, and remembers the timeout on next startup. - Save backoff timeout into xfrd.state file, this file has a higher version number now. Old files are skipped silently (causes refresh) and created as new files upon exit. - Set number of rounds to 1; NSD will try every master once, then wait for timeout or notify. - Fix axfr fallback for rounds to 1. 20 October 2016: Wouter - suppress compile warning in lex files. 18 October 2016: Wouter - Robust fix against missing master in tcp_open for xfrd. - More in depth fix for the previous. - Fix wildcards in include: config statements with chroot enabled. 27 September 2016: Wouter - NSD 4.1.13 tag. - trunk has 4.1.14 in development. - Fix null memcpy for radixtree with single link element. 19 September 2016: Wouter - Review comments Ralph: wrapped long lines and nicer example conf. 16 September 2016: Wouter - NSD 4.1.13rc1 tag. 15 September 2016: Wouter - Test for openssl init_crypto and init_ssl functions. 14 September 2016: Ralph - Fix OPENSSL_INIT_ADD_ALL_DIGESTS compatibility check 13 September 2016: Wouter - Fix double const in dname_const() function. - Silenced flex-generated sign-unsigned warning print with gcc diagnostic pragma. 8 September 2016: Wouter - more extensible edns option handling. 2 September 2016: Wouter - Release of 4.1.12; trunk is 4.1.13 and the patch for 4.1.12 (that does not contain the other changes to the trunk) is folded into the trunk. - Fix #827: fix compile with openssl 1.1.0 with api=1.1.0. 25 August 2016: Wouter - Fix multimaster for not tried full zone transfer for a expired zone. - Explain --disable-radix tree uses some more CPU. 22 August 2016: Wouter - Fix README spelling error of BSD license (reported by Joerg Jung). 19 August 2016: Wouter - for type SRV add A/AAAA to the additional section (if possible), just like we already do for type MX. 17 August 2016: Wouter - Add robustness against unallocated data in nsec3 trees. 16 August 2016: Wouter - configure --disable-radix-tree for about 15% lower memory usage. 12 August 2016: Wouter - Fix #817: xfrd update failed loop. 9 August 2016: Wouter - Can config key algorithms with the digest name, eg. 'sha256'. - default tsig algorithm is sha256. - Fix typo in log output, 'transfered' -> 'transferred'. - Fix compile warnings about signcompare in minmax retrytime. 8 August 2016: Wouter - Support syntax of RR type OPENPGPKEY from RFC 7929. 5 August 2016: Wouter - multi-master-check: yes can be used to check all masters for the last version, using the higher version from the configured masters, from Manabu Sonoda. - small fixups on patch. And fix spacing and remove configure flag. - Fix #812: make depend fails after distribution. 2 August 2016: Wouter - Fix unused result warnings from write and strtol. 1 August 2016: Wouter - Tag 4.1.11rc1. - Fix nsec3 missing for nsec3 signed parent and child for DS at zonecut. - Tag 4.1.11rc2. - trunk is 4.1.12 in development. 8 July 2016: Wouter - Note down tracking numbers for issue JVN#63359718 JPCERT#91251865. 5 July 2016: Wouter - Fix #790: size-limit-xfr can stop NSD from downloading infinite zone transfer data size, from Toshifumi Sakaguchi. 27 June 2016: Wouter - Set default for min-refresh-time and min-retry-time to 0. Behaves just like before, but has a configurable option in nsd.conf. - Fix #783: Trying to run a root server without having configured it silently gives wrong answers. 16 June 2016: Wouter - When tcp is more than half full, use short timeout for tcp session. - Patch for {max,min}-{refresh,retry}-time from YAMAGUCHI Takanori. - man page entries for max-refresh-time patch. 15 June 2016: Wouter - Fix build without IPv6, patch from Zdenek Kaspar. 14 June 2016: Wouter - release 4.1.10 and tag for that. - trunk has 4.1.11 in development. 7 June 2016: Wouter - Fix NSEC3 ent fix to use closest encloser, not wildcard denial. 2 June 2016: Wouter - Fix for NSEC3 with zone signed without exact match for empty nonterminals, the answer for that domain gets wildcard denial. - #772 Document that recvmmsg has IPv6 problems on some linux kernels. - tag for 4.1.10rc1. 31 May 2016: Wouter - print notice that nsd is starting before taking off. 20 May 2016: Wouter - Updated fix for nonterminal nsec3 answers. 19 May 2016: Wouter - Fix empty nonterminal nsec3 cover answers. 12 May 2016: Wouter - NSD includes AAAA before A for queries over IPV6 (in delegations). And TC is set if no glue can be provided with a delegation because of packet size. 19 April 2016: Wouter - Fix #755: NSD spins after a zone update and a lot of TCP queries. 7 April 2016: Wouter - If set without nsd.db print "" as the default in the man pages. 4 April 2016: Wouter - Fix #751: NSD fails to occlude names below a DNAME. 24 March 2016: Wouter - Fix for openssl 1.1.0, HMAC_CTX size not exported from openssl. 21 March 2016: Wouter - Update acx_nlnetlabs.m4 to version 33 with HMAC_Update test. - acx_nlnetlabs.m4 to v34, with -ldl -pthread test for libcrypto. 15 March 2016: Wouter - ip-freebind: yesno option in nsd.conf sets IP_FREEBIND socket option for Linux, binds to interfaces and addresses that are down. - Change the nsd.db file version because of nanosecond precision fix. - 4.1.9 release with the nsd.db file version fix (but not freebind), trunk contains 4.1.10 in development. 10 March 2016: Wouter - Tag 4.1.8 - Trunk contains 4.1.9 in development. 2 March 2016: Wouter - Tag 4.1.8rc1 1 March 2016: Wouter - #744: Fix that NSD replies for configured but unloaded zone with SERVFAIL, not REFUSED. 16 February 2016: Wouter - RR type CSYNC (RFC7477) syntax is supported. 29 January 2016: Wouter - #739: zonefile changes when mtime is small are detected on reload, if filesystem supports precision mtime values. 19 January 2016: Wouter - Fix #736: segfault during zone transfer. 08 January 2016: Wouter - Define _DEFAULT_SOURCE with _BSD_SOURCE for recent Linuxes. 05 January 2016: Wouter - #732: tcp-mss, outgoing-tcp-mss options for nsd.conf, patch from Daisuke Higashi. 04 January 2016: Wouter - Updated acx_nlnetlabs to version 32. 11 December 2015: Wouter - Fix flto check for OSX clang. 10 December 2015: Wouter - 4.1.7 release - trunk has 4.1.8 in development. - take advantage of arc4random_uniform if available, patch from Loganaden Velvindron. 3 December 2015: Wouter - tag for 4.1.7rc1 prerelease. 2 December 2015: Wouter - configure --enable-ratelimit-default-is-off with --enable-ratelimit to set the default ratelimit to disabled but available in nsd.conf. - Document that ratelimit qps and slip are updated in reconfig. - version: "string" option to set chaos version query reply string. - Fix up defaults in manpage. 1 December 2015: Wouter - Explain rrl-slip better in documentation. 30 November 2015: Wouter - Fix TCP responses when REUSEPORT is in use by turning it off. - reuseport: no is the default, because the feature is not troublefree. - Document default in manpage for rrl-slip, ip4 and 6 prefixlength. 24 November 2015: Wouter - Fix zonec ttl mismatch printout to include more information. 18 November 2015: Wouter - RELNOTES more descriptive. - newer acx_nlnetlabs.m4. - spelling fixes from Igor Sobrado Delgado. 17 November 2015: Wouter - Fix #721: Fix wrong error code (FORMERR) returned for unknown opcode. NOTIMP expected. 16 November 2015: Wouter - Allocate less memory for TSIG digest. 6 November 2015: Wouter - Fixup for newer acx_nlnetlabs.m4, test for openssl version after testing for libdl need. 5 November 2015: Wouter - newer acx_nlnetlabs.m4, does not needlessly link with -ldl. 30 October 2015: Wouter - Fix tpkg tests for portability. 29 October 2015: Wouter - patch from Doug Hogan for SSL_OP_NO_SSLvx options. - updated contrib/nsd.spec, from Bálint Szigeti. - support configure --with-dbfile="" for nodb mode by default, where there is no binary database, but nsd reads and writes zonefiles. 27 October 2015: Wouter - portability fixes. 26 October 2015: Wouter - Init pfd for handlers added during handler-event-walk. 23 October 2015: Wouter - Fix many interfaces and zones updates from nsd parent event loop. 22 October 2015: Wouter - 4.1.6 release tag. - trunk contain 4.1.7 in development. 20 October 2015: Wouter - 4.1.6rc2 tag created. 19 October 2015: Wouter - Fix compile of zonec error message on FreeBSD. 15 October 2015: Wouter - 4.1.6rc1 tag created. 13 October 2015: Wouter - 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. - fixup file descriptor fixup nicer. - print failed token for config syntax error or parse error. 12 October 2015: Wouter - Fix #711: Document that debug-mode yes is used for staying attached to the supervisor console. - Document verbosity 3 prints more information. 30 September 2015: Wouter - makedist.sh print on pgp signature creation. 28 September 2015: Wouter - Fix typo in zonec.c inside error message. 24 September 2015: Wouter - Fix #701: Fix that AD=1 set in a BADVERS response. 21 September 2015: Wouter - Fix #706: default port 53 not opened on ip4 because of getaddrinfo hints initialisation failure. - 4.1.5 release tag - trunk contains 4.1.6 in development. 9 September 2015: Wouter - 4.1.4 release tag created. - trunk contains 4.1.5 in development. 31 August 2015: Wouter - 4.1.4rc1 tag created. 28 August 2015: Wouter - Fix #698 formatting errors and typos in nsd.8.in. - Add --enable-pie and --enable-relro-now options. 18 August 2015: Wouter - Admitted axfrs are logged at verbosity 1. Refused at verbosity 2. 17 August 2015: Wouter - Fixed checkconf test for reuseport setting. 14 August 2015: Wouter - SO_REUSEPORT does not work on FreeBSD. Enabled by default on Linux, not enabled by default on other OSes. 5 August 2015: Wouter - Fix that notify from nsd-control contains soa serial. 3 August 2015: Wouter - squelch SO_REUSEPORT failure on verbosity less than 3. 31 July 2015: Wouter - removed hardcoded interface limit, --with-max-ips removed. - SO_REUSEPORT support. 16 July 2015: Wouter - Fix #618: documented need to list ip-addresses separately in nsd.conf if there are multiple, because the source address of replies can otherwise go wrong. 10 July 2015: Wouter - 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. 2 July 2015: Wouter - Fix NSID response for short edns sizes. 23 June 2015: Wouter - Trunk contains 4.1.4 in development. 4 June 2015: Wouter - Tag 4.1.3rc1 - improve nsd-control usage text. (23 june - added to 4.1.3) - RFC7553 RR Type URI support. 2 June 2015: Wouter - Fix redefined macro lex warning for freebsd flex. 29 May 2015: Wouter - Fix that formerrors are ratelimited. 19 May 2015: Wouter - max-interfaces raised to 32. 18 May 2015: Wouter - removed unused defines for unofficial tsig-hmac algorithm codes. The TSIG algorithm is identified by name in the config file. 14 May 2015: Wouter - hmac sha224, sha384 and sha512 support, patch from David Gwynne. 23 April 2015: Wouter - Fix crash in zone parser for relative dname after error in origin. - Test for zone parser failures 21 April 2015: Wouter - nsd-control addzones and delzones read list of zones from stdin. - Fix task and zonestat files to be stored in a subdirectory in tmp to stop privilege elevation. - printout names for successful addition and removal with bulk command. 20 April 2015: Wouter - Fix #665: when removing subdomain, nsd does not reparse parent zone. 14 April 2015: Wouter - trunk contains 4.1.3(upcoming). 7 April 2015: Wouter - Tag 4.1.2rc2. 2 April 2015: Wouter - Made log message more consistent, changed 'axfr refused' log message to be more consistent with other messages. Also notify refused. - verbosity 2 logs axfr refused and notify refused. verbosity 1 contains less log messages. 31 March 2015: Wouter - Tag 4.1.2rc1. 24 March 2015: Wouter - Fix #654: Fix contradiction in notify logging verbosity level. - Incoming notifies have serial number logged (at verbosity 1). - Fix #655: Fix contradiction in verbosity for zone transfers. 17 March 2015: Wouter - Use reallocarray for integer overflow protection, patch submitted by Loganaden Velvindron. - Fix allocation integer overflow checks. 13 March 2015: Wouter - Fix buffer overflow in config parse of domain name, reported by John Van de Meulebrouck Brendgard. 12 March 2015: Wouter - Updated default keylength in nsd-control-setup to 3k. 10 March 2015: Wouter - Fix use after free after zonefile syntax error followed by ttl or origin directive, reported by John Van de Meulebrouck Brendgard. - Fix syntax error followed by too many TXT elements parse crash reported by John Van de Meulebrouck Brendgard. 9 March 2015: Wouter - Fix origin directive from unused old value and subdomain parser failure, reported by John Van de Meulebrouck Brendgard. 2 March 2015: Wouter - Fix b64pton out of bounds error on invalid zonefile input reported by John Van de Meulebrouck Brendgard. 20 February 2015: Wouter - Fix segfault on double origin in zone reader (thanks John Van de Meulebrouck Brendgard). 19 February 2015: Wouter - Remove dead code domain_table_iterate. - Fix segfault in zone reader on invalid input reported by John Van de Meulebrouck Brendgard. 5 February 2015: Wouter - Fix #642: Change 'zone read with no errors' to '.. with success'. Patch from Benedikt Heine. 3 February 2015: Wouter - Tag 4.1.1 release - Trunk is 4.1.2 in development. - Remove some duplicate header includes (from Brad Smith). - Fix tcp waiting list for zone transfers where the bind and connect calls fail. 29 January 2015: Wouter - Fix zonesdir chroot error message. 28 January 2015: Wouter - correct some hyphen-used-as-minus-sign (from Andreas Schulze) in man pages. 27 January 2015: Wouter - Tag 4.1.1rc1 21 January 2015: Wouter - Synthesize CNAMEs with same TTL as DNAME. 12 January 2015: Wouter - Fix casts for ctype functions (from Todd Miller). - nsd-checkconf -f prints out full name of pidfile (with dir). 9 January 2015: Wouter - Fix bug#637: fix that nsd.db grows limitlessly, an off by one on one megabyte free chunks, created during AXFRs of large zones, that caused the one megabyte chunk to be leaked. - Fix udb-inspect for one megabyte chunks, counts and statistics. 6 January 2015: Wouter - Fix spinning NSD with lots of failing transfers, due to pointer comparison using void pointer subtraction (from Otto Moerbeek). 5 January 2015: Wouter - Patch nsd_munin_ from Philip Paeps to use type ABSOLUTE. 4 Nov 2014: Wouter - Document zonestat config, and nsd-checkconf access. 3 Nov 2014: Wouter - Fix that failure to add tcp to tcp base does not leak the socket. 27 Oct 2014: Wouter - Disabled use of SSLv3 in nsd-control. - zonestats are cleared (or not, with stats_noreset). 22 Oct 2014: Wouter - Test for wildcard fix (from 3.2). 16 Oct 2014: Wouter - Fixes for wildcard addition and deletion, speedup for some cases. 15 Oct 2014: Wouter - Fix that queries for noname CH TXT are REFUSED instead of nodata. 14 Oct 2014: Wouter - per zone statistics with --enable-zone-stats, configure with zonestats: "zonestatidentifier", zones with the same id are added. 10 Oct 2014: Wouter - Fix #616: retry xfer for zones with no content after command. - Fix char used as array index warnings on NetBSD. 8 Oct 2014: Wouter - Fix "xfrd_handle_ipc: bad mode" log errors when compiled with --disable-bind8-stats. 18 Sep 2014: Wouter - Fix that expired zones stay expired after a server restart. 15 Sep 2014: Wouter - RFC 7344: CDS and CDNSKEY (read in). 4 Sep 2014: Wouter - Tag 4.1.0. - trunk is 4.1.1 in development. - fix manpage for nsd-checkzone to have version and date. 29 Aug 2014: Wouter - Fix install of the nsd-checkconf man page. 28 Aug 2014: Wouter - Tag 4.1.0rc1 25 Aug 2014: Wouter - Increased default --with-max-ips from 8 to 16, this increases the number of interfaces you can specify in nsd.conf to listen to. 19 Aug 2014: Wouter - Remove .LP after .SH in man pages. 7 Aug 2014: Wouter - Fix for process swap of main and reload, reload failure from the pipe is acted on, and reload fail not cause nsd to shutdown, also ignore sigchlds from the servermain in reload, that would cause EINTR to break file reads. - trunk has version 4.1. 5 Aug 2014: Wouter - Fix #600: document that provide-xfr provides AXFR and not IXFR. - remove program group fix, because it is not needed. - Fix rising-load-average or memory-leaks in OSes (Linux since 2.6), that keep track of all past process parents, or leak memory for them. Fix makes it so there is no very deep string of process parents. The reload process is now the process parent of servermain. That makes signals for children arrive at the reload, and servermain has to use closed pipes to detect that children have exited. 1 Aug 2014: Wouter - Set program group on main process and its child processes, and kill them on a reload. 20 July 2014: Wouter - Fix endian.h include for OpenBSD. 15 July 2014: Wouter - Fix -O3 compile flag to -O2 to avoid miscompilations. - Allow user to override the -g -O2 CFLAGS in ./configure. 11 July 2014: Wouter - fix strptime implicit declaration error on OpenBSD. 9 July 2014: Wouter - removed unnecessary arc4random_uniform. 8 July 2014: Matthijs - fake-rfc2553 patch (thanks Benjamin Baier). 8 July 2014: Wouter - wait and reap processes that are not part of the process group. 7 July 2014: Wouter - Code review fixup from NSD3. 30 Jun 2014: Wouter - Fix #590: rrl log does not print wildcard as a star but escaped. - Fix #591: rrl log messages at verbosity level 1. (If that does not work for everyone, we need rrl-log: yesno option). 27 Jun 2014: Wouter - Fixup rr-test test so that it does not fail on the #553 string. 17 Jun 2014: Matthijs - Fix #587: Default value for statistics is 0. - Remove the shift-reduce conflicts from the bug#553 fix. 5 Jun 2014: Wouter - Fix roundrobin cornercase for truncated packets. - round-robin: yesno in nsd.conf enabled round robin rotation. 28 May 2014: Wouter - Fix #585: yylex_destroy missing, cannot compile on RHEL 5.x. - Fix #583: Round-robin for records in the Answer section. 22 May 2014: Wouter - Fix zonefile parse with no whitespace before semicolon comments. 16 May 2014: Wouter - xfrd reaps children on a timer as well, similar to server_parent. 8 May 2014: Wouter - Fix #564: nsd-checkzone tool to check zonefile correctness. 7 May 2014: Wouter - Fix #577: makefile incorrectly installed manpages from srcdir. 30 April 2014: Wouter - Fix that xfrd reaps all children on every eventloop, because some exited reloads may attach here and need reaping, also if the signal is lost. 23 April 2014: Wouter - Fix progress printout for very large zones (numeric overflow). 10 April 2014: Wouter - Fix write_socket return value check in server.c (Thanks Brad Smith, Mark Kettenis). 8 April 2014: Wouter - nsd-control addzone reports if zone already exists. 7 April 2014: Wouter - Fix #571: unused variable and incompatible pointer warnings when compiled on a system without INET6. 27 March 2014: Wouter - Fix delete or rename of a lot of zones and make it take a non-enormous time. Database compaction is deferred. - Speed up deletion of zone contents a lot, (56s to 1s), speeds up delete, rename and AXFR for zones. Defer emptynonterminal checks. - Better example config in nsd.conf manual page. - log-time-ascii option, default yes, with readable timestamp in log. 25 March 2014: Wouter - nsd shuts down during init process if given signal. - shorter logging for zone transfer fail rcodes. 24 March 2014: Wouter - include: "foo/nsd.d/*.conf" works, wildcard glob on includes. - Fix print filename of encompassing config file on read failure. 21 March 2014: Wouter - Fix bug in nodatabase mode with ixfrs that change nsec3param (Thanks Anand Buddhdev). - Changed maxbackoff for no-content secondary zones from 4h to 24h. - nocontent zones are checked on startup, but continue backoff from stored xfrd.state values. 19 March 2014: Wouter - made database: "" set the 3600 default for zonefileswrite only if it is also at its default, so that user settings override. - Unit test for zonefiles-write. - Write xfrd.state for nodb mode again. Disable xfrd.state with xfrdfile: "" in config. Does not check slave zone if state is same as last time on startup. - Fixed shutdown message sporadically not printed on exit. - Documented zonefile %s syntax in nsd.conf man page. - Fix manpage to put colon after zonefiles check and write. - Change from 'Zone" to "zone" with ".. serial .. is updated" log message. 18 March 2014: Wouter - unit test for nodb mode. - Speed up zone write (.nl zonefile 30% faster). The memory alloc-dealloc in print_rr has been moved to print_rrs. - (from 3.2), fix for #553 and for other TXT string syntax. - in nodb mode, xfrd.state is not written out, because the zones are refreshed upon next startup anyway, so keeping timers and state is unnecessary. - zonefiles-write option in nsd.conf, enabled when database is "". The server writes changed zonefiles to disk every hour. 17 March 2014: Wouter - Speed up zone parsing (.nl reads 40% faster). The rrtype_from_string routine is called often, optimised it. 14 March 2014: Wouter - tag 4.0.3 - trunk has 4.0.4 in development. - database: "" starts without mmap of database. Less memory is used, zones are read from text zonefile. 13 March 2014: Wouter - Fix nsd.db unclean close check. Previous databases are considered unclean by the code and are created anew. - Adds nsd.db larger than 400Tb check for sanity. Also test if filesize as documented in the file is correct. - nsd waits for tasks to complete on stop, prevents nsd.db corruption. - fix to not delete tmpdir too early in shutdown process. 12 March 2014: Wouter - tag 4.0.2 - trunk has 4.0.3 in development. - disabled udb checking functionality that made it very slow, this was enabled when enable-checking was turned on. 27 February 2014: Wouter - tag 4.0.2rc1 26 February 2014: Wouter - Fix that NSD will delete and recreate not-clean-closed databases. 20 February 2014: Wouter - Fix from 3.2: make SOA RDATA comparisons in XFR more lenient (only check serial). 18 February 2014: Wouter - Fix leak of zone name after zonefile read. - Fix malloc too large that would be leaked in the radix tree. 14 February 2014: Wouter - configure change for easier compile on Minix. 10 February 2014: Wouter - Fix #552: zonefile loads on nsd-control reconfig when the name of the file has changed. 7 February 2014: Wouter - Fix #551: change Regent to Copyright holder in the LICENSE, to match the definition on opensource.org for the BSD License. 3 February 2014: Wouter - Disabled recvmmsg and sendmmsg usage by default because kernel versions have implementation issues: ipv6 ignored, security issues. - Detect libevent2 install automatically by configure, and use event2 header files if necessary. - Fixup link with lib/event2 subdir. 30 January 2014: Wouter - Fix expired zones to give SERVFAIL, also when parent zone loaded. 27 January 2014: Wouter - tag 4.0.1. - trunk is 4.0.2 in development. - rcode REFUSED for queries to non-hosted zones. - documented nsd-control zonestatus output in nsd-control manpage. - remove mention of nsdc from nsd-checkconf manpage. 21 January 2014: Wouter - tag 4.0.1rc2 20 January 2014: Wouter - Fix #546: output format errors in nsd_munin_ (Thanks Tom Hendrikx). 17 January 2014: Wouter - Fix type CAA. - Fix type EUI48. - nsid can be set with "ascii_somestring" in ascii. - Fix printout of high-chars in TXT on NetBSD. 16 January 2014: Wouter - Unit test for WKS failure. 15 January 2014: Wouter - tag 4.0.1rc1 13 January 2014: Wouter - Check if configure in srcdir collides with outofdir build. 10 January 2014: Wouter - Fix that chroot is removed from zonefile names (for absolute names). 9 January 2014: Wouter - Fix that bad IXFR updates do not result in double SOA records, and that an AXFR is started (attempted) when the zone state seems to be inconsistent with the master's zone state. 8 January 2014: Matthijs - Bugfix #542: Match RRSIG TTL with SOA TTL in negative response. 7 January 2014: Wouter - Fix xfrd when zone transfer TCP contains zero length packets. - Fix for NSEC3 zones where parent zone is co-hosted, also NSEC3, because AXFRs overwrote nsec3 administration in the child zone. 2 January 2014: Wouter - Log ip address for sendto and sendmmsg failures. 4 December 2013: Matthijs - Support for CAA RRtype (RFC 6844). 26 November 2013: Wouter - Fix segfaults after read of zones with rr type WKS from zonefile. - Seed PRNG for openssl at start of daemon, fixes SSL connection issue. 25 November 2013: Wouter - (same as in 3.2.16): fix wildcard cname to nxdomain repeated rrset. 11 November 2013: Wouter - Fix bug#534: IXFR query loop over UDP for zones that are unchanged. 11 November 2013: Matthijs - EUI48 and EUI64 is now RFC 7043 5 November 2013: Wouter - Accept interface: as an alternative for ip-address: for consistency with unbound.conf syntax. 29 October 2013: Wouter - tag for 4.0.0 release. - trunk has 4.0.1 in development, for bug fixes. 24 October 2013: Wouter - Fixup zone change code. - tag 4.0.0rc3. 21 October 2013: Matthijs - Initialize xfrd zone when changing zone from master to slave and delete xfrd zone when changing zone from slave to master. 14 October 2013: Wouter - tag 4.0.0rc2. 14 October 2013: Matthijs - Additional log messages with reason why RR to be deleted cannot be found. 14 October 2013: Wouter - Fix for zone transfer that has different-cased RRSIG signer names or NSEC next-owner names. 9 October 2013: Wouter - tsig errors on incoming tsig print key name and source IP of query. 8 October 2013: Wouter - Update documentation for nsd -d option. 7 October 2013: Wouter - Fix mini_event ev_once flag to be prettier (review comments Yuri). - tag 4.0.0rc1 recreated. 4 October 2013: Wouter - Fix bug where if you do not have flex, and then install flex, it would not make without a re-untar of the source. 3 October 2013: Wouter - Review changes from Matthijs. - doc/README updated, 'nsdc' is now removed. 1 October 2013: Wouter - Review commits from Matthijs. - doc/UPGRADING updated, review Yuri. 30 September 2013: Wouter - tag 4.0.0rc1 - updated doc/RELNOTES 19 September 2013: Wouter - configure --disable-recvmmsg for compat with older Linux kernels, by default it autodetects support in the kernel on the buildmachine. 20 Aug 2013: Wouter - Fix time at 2038, uint32s changed to time_t, support 64bit time_t. 19 Aug 2013: Wouter - Fix use of 32bit time, for 2038, thanks to Theo de Raadt for patch. 13 Aug 2013: Wouter - Bugfix#518 Incorrect RRL prefix length option names in nsd.conf man page from Ville Mattila. 9 Aug 2013: Wouter - Fix that xfrd, and nsd-control, does not stop responding when reload errors out. The pid is sent like it should by server_main. - Fix that EOF in quoted string error does not cause reload to exit. - Fixup errors from the stack code checker. 6 Aug 2013: Wouter - Removed use of random when arc4random is available. Thus, random and srandom are then not linked with the executable. 16 Jul 2013: Wouter - Fix segfault with no logfile and chroot (Thanks Patrik Lundin). 15 Jul 2013: Wouter - beta 5 tag. - trunk has beta6 named in configure. 9 Jul 2013: Wouter - unlink xfr file if transfer is stopped, timeouted or interrupted. And unlink xfr file in progress when the zone is deleted. 8 Jul 2013: Wouter - Increase tcpbacklog default to 256 (silently capped to 128 on BSD). For remote control keep it at 16, it has less TCP load. It does not actually increase TCP performance (some except), but reduces connection loss when there is a spike in TCP connections. 5 Jul 2013: Wouter - nsd-mem stores temp files in current dir because /tmp is too small. - printout pct parsed, read, nsec3 and written every 100.000 elements and after 5 seconds. For big zones. 3 Jul 2013: Wouter - region-allocator has list of large allocations, so delete is in O(1). - recursive readroutine for speedup of nsd.db reads (30%). - udb-inspect prints type summary of nodes in nsd.db. 28 Jun 2013: Matthijs - Update tmp serial in xfr checking. 28 Jun 2013: Wouter - nsd.db 12% smaller, no nsec3 hash storage. Also ups udb version because of the format change. printout udb write complete for debug. - Fix warning in labellength 0 code. 27 Jun 2013: Matthijs - Better XFR checking, fallback to AXFR (if allowed) if three malformed XFR packets have been seen. - zonec: Don't crash on domain names with label length 0. 25 Jun 2013: Matthijs - Rename --enable-eui-rrtypes to --enable-draft-rrtypes. 25 Jun 2013: Wouter - acx_nlnetlabs.m4 update, --disable-flto. 20 Jun 2013: Matthijs - Use IPV6 minimum MTU settings with TCP to reduce failures that are caused by delays in learning working PMTU when communicating through a tunnel. - Improved RRL logging: also print triggering query src addr and qtype (thanks Klaus Darilion). - Merge some minor stuff from NSD3.2 18 Jun 2013: Matthijs - Add rrl-slip config option (thanks Stephane Bortzmeyer). - Add rrl-ipv{4,6}-prefix-length config option. - Bug #496: Support for EUI48 and EUI64 RR types. 14 Jun 2013: Wouter - Optimizations: -O3 if possible (user can override CFLAGS), udp buffers are set to 1m by default (if socket options exist), use recvmmsg and sendmmsg, or only recvmmsg, or recvfrom. 11 Jun 2013: Wouter - Fix memory leak in zone parser for txt record (since the large number of txt subsections fix). - Fix zone parser allocations to be in db region. - nsd-mem prints advice 5 Jun 2013: Wouter - Fix segfault on repeated reconfigs, double free of zone apex name. 4 Jun 2013: Wouter - Remove duplicate zlfile variable from options structure. 30 May 2013: Wouter - Fix nsd-mem for printout of values above 4G. 16 May 2013: Wouter - Patch from Lukas Wunner that makes chroot more consistent. Make all paths absolute with the chrootdir in front, or use an absolute zonesdir with other patsh relative to that. 3 May 2013: Wouter - Fix race on exit of nsd, for restarts, so that the pidfile-pid process waits until port53 has been closed before exiting. - update acx_nlnetlabs.m4 to v23, sleep w32 fix. 29 April 2013: Wouter - Remove unused pointer and fixup chroot include for trail slash. 26 April 2013: Wouter - Patch from Lukas Wunner that makes nsd.conf include files work inside chroot/etc environments on repattern and reconfig. 25 April 2013: Matthijs - New config option "ip-transparent:", to bind to non local addresses (thanks Arjen Zonneveld). - RRtypes ASFDB, RP, RT should not compress dnames (thanks Peter van Dijk). 19 April 2013: Wouter - own snprintf, fix use of snprintf return value (in debug print). 18 April 2013: Wouter - fix bug #491: pick program name (0th argument) as syslog identity. 9 April 2013: Wouter - Bug #494: Exit with return code 1 if socket code fails. (from 3.2) - Fix B64_NTOP replacement definitions in configure.ac. 26 March 2013: Wouter - update lookup3.c with better endianness detection. 25 March 2013: Wouter - faster nsec3 updates. - Fixup contrib/bug390.patch for 4.0.0b4. - remove leak of nsec3. - allocate radixtree in region for small (5%) total savings and about 15% savings in the radixtree itself (due to many small alloc savings in region). 22 March 2013: Wouter - use less memory for non-nsec3, nsec3tree. 18 March 2013: Wouter - update nsd-mem with pretty printout and RRL count. 14 March 2013: Wouter - Fix memory statistics in nsd_munin_. 8 March 2013: Wouter - nsd-mem tool initial commit. 7 March 2013: Wouter - notify information is logged at correct verbosity level, 1. 5 March 2013: Matthijs - Add hash to rrl bucket 5 March 2013: Wouter - Fixup the growth and shrinkage of nsd.db. This should use less calls to remap and change the file and mmap size. 15 February 2013: Wouter - Fix compile on bigendian netbsd alpha. - Fixup tests for older dig (check if +noedns option is supported) 11 February 2013: Matthijs - Fix outgoing-interface: Don't fail if family is IPv6 but only IPv4 outgoing-interface is set, or vice versa. 11 February 2013: Wouter - fix tcp zonetransfer pipeline lookup function. - remove compiler warning for memset from tsig read. 7 February 2013: Wouter - detect endianness in lookup3 on BSD, patch from Brad Smith. - nsd-control verbosity prints out verbosity level without argument. - nsd-control status prints out ratelimit if ratelimit is enabled. 5 February 2013: Wouter - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify. - beta4 4 February 2013: Wouter - Fix AXFR of NSEC3 slave zone. 1 February 2013: Wouter - Less printout of 'bad transfer'. 31 January 2013: Wouter - Fix that nsec3 zones are precompiled when read from udb. This caused assertion failures. - Fix is_apex flag for zones read from udb. 29 January 2013: Matthijs - RRL documented in nsd.conf.sample 29 January 2013: Wouter - printout log less verbosely, not every axfr packet. - remove printout of "bad transfer" to the log for notimpl. - fixup tests for new netstat and new netcat. 25 January 2013: Wouter - fix gcc warning, do not use uninit value for rng init. - fix zonefiles-check: entry in nsd.conf - remove -fwhole-program gcc flag usage. We cannot reliably detect if it works without failure. 23 January 2013: Wouter - beta3 22 January 2013: Wouter - Fix time calculation of zone transfer. - log ip address with tcp failure. 21 January 2013: Wouter - Improve tabs in sample nsd.conf for different tabsizes. - Fix segv if xfrdir does not exit. - create xfrdir on make install (does not remove on make uninstall, because this could be /tmp). - do not leave task files in /tmp if nsd fails to startup because of file permissions. - do-ip4 and do-ip6 nsd.conf options just like unbound. - fixed testset for dig9 default with edns. 18 January 2013: Wouter - Fix configure for gentoo gcc and headers. - List libevent in README. - Tabs and spaces nicer in nsd.conf.sample. - Fix spurious assertion failure for some rrl blocks. 16 January 2013: Wouter - Added zonefiles-check option, default yes, check mtimes of zone files on sighup and startup (from Robin Hack). 15 January 2013: Wouter - documented that the _implicit_ pattern names are used internally. 10 January 2013: Wouter - updated RELNOTES. - applied patch from Robin Hack to remove double pid file truncation. - repattern is called reconfig (because most config options are picked up, except for superuser options (chroot, logfile, port)). - document that the zonefile attribute can be empty. 9 January 2013: Wouter - 4.0.0b2 is beta2 version tag. 8 January 2013: Matthijs - Merge changes from 3.2.15 with trunk: * Update docs: CREDITS, NEW-CFG-OPTION, REQUIREMENTS, RELNOTES, TODO * Update dname_test.tpkg test. * TSIG init only fails if no digests at all can be found. * Remove unused tsig_get_algorithm_by_id code (was used by nsd-xfer). * Fix some fd leaks. * Bug #485: Fallback to DEFAULT_TTL if MSB is set. * Fix RCODE when xNAME loop final answer not exist to NXDOMAIN. 8 January 2013: Wouter - Fix make outside of source directory. 7 January 2013: Wouter - fixed uninit variable for empty zone axfr request - fixed alloc of acl options for config zones so they can be deleted. - fixed that pattern name is copied, so that patterns stay the same. - repattern also rereads the zones in the config file and applies that to the running server. 21 December 2012: Wouter - --with-logfile sets the logfile inside the example documentation. - Fixed addzone and delzone inside chroot (thanks Will Pressly). 19 December 2012: Wouter - Fixup for libevent-2.1.2. 18 December 2012: Wouter - makedist makes sha256 for tarballs. - nsd-control start runs an absolute path to start sbin/nsd. 17 December 2012: Wouter - Fix for use with libev (no use of event.ev_flags). 12 December 2012: Wouter - 4.0.0b1 is beta1 version. 11 December 2012: Matthijs - Better ILNP RR parsing (thanks Stephane Bortzmeyer). 11 December 2012: Wouter - fix libevent=no signals on Solaris. - Fix handle of activated zones from timeout event. - contrib/nsd_munin_ updated with memory lookup for BSD. 10 December 2012: Wouter - implement --with-libevent=no. 10 December 2012: Matthijs - Bug #483: Better error messages for TSIG errors. - RFC 2845: If BADKEY or BADSIG, RCODE should be NOTAUTH. Also, continue TSIG verification if NOTAUTH. 7 December 2012: Wouter - stable pidfile, xfrd is process leader and forks server-parent. 5 December 2012: Wouter - NSD4_imp_6 tag. - trunk has imp_7 implementation. 4 December 2012: Wouter - NSD-RRL documented in manpage. 3 December 2012: Wouter - Fixup exit of server-child while notifies are incoming. 28 November 2012: Wouter - RRL implements classification type RRSIG. 26 November 2012: Wouter - Fix to make nsd.udb portable between 32bit and 64bit machines. - Fix to make udb mmap work for FreeBSD8 when it grows significantly. 23 November 2012: Wouter - Fix compiler warnings and fix blocking pipes. - default tcp-count set to 100. 21 November 2012: Wouter - Implement rrl log of unblock for collision. - imported TLSA and ILNP support from NSD3. 19 November 2012: Wouter - Fix bug 480: libevent use when tcp-count is hit caused hang (in NSD4). 9 November 2012: Wouter - Log when NSD-RRL stops a stream from being blocked. 8 November 2012: Willem - Fix AXFR. Loop through the zone to transfer only. 2 November 2012: Wouter - Fix bug 478: declaration after statement (for gcc 2.95). 1 November 2012: Wouter - Fix default settings for RRL. 30 October 2012: Wouter - review fixup of RRL SLIP response. - RRL uses dev/random at start, nonRRL does not. 26 October 2012: Wouter - nsd-control repattern also changes rrl-ratelimit and whitelist limit. 17 October 2012: Wouter - Fix alignment problem in zone transfer pipeline code. - Fix random generator generating negative. - Fix udb radtree strspace creation bug. 15 October 2012: Wouter - Fix activated zone does not interrupt transfer. - Log of connection failure for zone transfer is neater. 12 October 2012: Wouter - Fix invalid time argument in nsd control (for OpenBSD). 11 October 2012: Wouter - Fix build on OpenBSD (Thanks Oliver Peter). - tpkg for RRL. 10 October 2012: Wouter - implement nsd-checkconf option use of rrl-whitelist. 9 October 2012: Wouter - with --enable-ratelimit you enable ratelimiting, with verbosity 2 it logs what is ratelimited for operational inspection. - unit test for rrl. - rrl uses mmap to save state across reloads. - rrl enum and u16 flags (dnskey type). - rrl whitelist and config. 8 October 2012: Wouter - Sync with unbound lookup3, has raninit value. 5 October 2012: Wouter - fix bug with event loop in zone transfer pipeline. - close xfrd_sock_p in server_child because otherwise due to use of kqueue, it gets a broken pipe when that process exits (on FreeBSD). 4 October 2012: Wouter - Fixup no use of internals ev_flags of libevent. 1 October 2012: Wouter - fix xfrd tcp skip. 21 September 2012: Wouter - tzset before chroot for correct timezone (from Camiel Dobbelaar). - pipeline support for AXFR and IXFR tcp queries. 11 September 2012: Wouter - writev support for TCP. 28 August 2012: Wouter - TXT records with components longer than 255 fail to parse, but without segfault, it continues processing with non NULL value. 27 August 2012: Wouter - libevent in server_child. 21 August 2012: Matthijs - Fix bug#464: Conditionally define MAXHOSTNAMELEN 20 August 2012: Wouter - Fix hang on exit in xfrd. - optimized socket counts for zone transfer speed. 13 August 2012: Wouter - Fix xfrd libevent events. 10 August 2012: Wouter - libevent in xfrd. 26 July 2012: Yuri - Prioritize notify sender for requesting XFR. (thanks Ilya Bakulin) 19 July 2012: Willem - Fix for VU#624931 CVE-2012-2978: NSD denial of service vulnerability from non-standard DNS packet from any host on the internet. http://www.nlnetlabs.nl/downloads/CVE-2012-2978.txt 18 July 2012: Wouter - Fix bug#460: man page correction - identity. 9 July 2012: Wouter - delete temporary transfer files on exit of xfrd and reload. - when tasks are applied, reload checks if it must exit between tasks, so that it can quickly exit when NSD is told to quit. - fix bug in apply_xfr that must use an udb_ptr because it shifts when new allocations are made. 6 July 2012: Wouter - add xfrdir: "/tmp" option and configure --with-xfrdir="/tmp". The nsd.task files and a subdirectory for zone transfers are created there. 2 July 2012: Wouter - fix checkconf unit test and add test for backwards compatibility for difffile: "x" statement. 29 June 2012: Wouter - Implemented /tmp/nsd.xfr.xxx/ to replace ixfr.db. So that nsdc patch is no longer needed. 8 June 2012: Wouter - Fix tpkg test cutest_qroot and rr-test for printout of algorithms as numbers, and copy of DO flag to the answer. - pick up fd fix from 3_2 branch: Some more fd >= 0 to fd != -1 fixes 31 May 2012: Matthijs - Sync with 3.2 branch 24 February 2012: Wouter - Fix for qtype ANY for a wildcard domain in NSEC signed zone. 9 February 2012: Wouter - Update acxnlnetlabs.m4 version 21, fixed MEMCMP_BROKEN #undef line. 23 January 2012: Wouter - remove clang security warning about %n in format string. 20 January 2012: Wouter - Fix bug #430: segfault when MAX_INTERFACES set to more than 65K. - Fix configure for OpenIndiana sunos 5.11, acx_nlnetlabs.m4 update. 12 January 2012: Matthijs - Fix bug #421: truncate pidfile on shutdown, before unlink. 10 January 2012: Wouter - removed unused variables. 10 November 2011: Wouter - acxnlnetlabs.m4 updated to version 16, better lto check (a.out drop). 3 November 2011: Wouter - fflush zonelistfile after zone add or delete. 1 November 2011: Wouter - Fix -flto detection for llvm compiler on Lion. 10 October 2011: Matthijs - Don't clear the AA bit if there is an authoritative CNAME in the answer section (as shown in RFC 1034, Section 6.2.7, 2nd example). 10 October 2011: Wouter - squelch EPIPE when writing AXFR, enable with verbosity 2. 26 September 2011: (Matthijs, from NSD3_2 branch) - Copy the DO bit to the response. - Don't return SERVFAIL on a domain that looks like a NSEC3 domain but is actually a empty non-terminal. 19 August 2011: Wouter - Fix segfault if no logfile is used. 5 August 2011: Wouter - Fix make from repeating action already taken. - Fix compile without openssl. 3 August 2011: Wouter - silence 'Broken pipe' messages in log (visible with verbosity 2). - fix makedist.sh for removal of patch, notify, xfer. new nsd-control. - tag 4.0.0-imp-5 created. - trunk is 4.0.0-imp-6 under development. - added nsd_munin_ script for statistics monitoring to contrib. 2 August 2011: Wouter - fix compile on Ubuntu 11.04 systems, detects cc system header issue. 1 August 2011: Wouter - fix checkconf test for remote control options. - fix warning on Ubuntu 10.04, fix autoconf 2.68 warning on NetBSD. 29 July 2011: Wouter - zones with no zonefile are not written to text (assumes you can get AXFR and IXFR for the contents). They are stored in nsd.db. - test for repattern. 28 July 2011: Wouter - nsd-control repattern reads TSIG and pattern configuration. 25 July 2011: Wouter - fixed tests for removed tools from nsd, with replacements. replaced nsd-patch with nsd-control write. replaced nsd-notify with ldns-notify. replaced nsd-xfer with dig -t axfr. - fix for xfrd restart if crashed. xfrd knows if a reload is active at that time so it cannot start another one at the same time. New shortsoa track for start that does not use taskdb in use by reload. taskdb in use by crashed xfrd is recreated, in case it is corrupt. This keeps the nsd.db intact, keeps reload running with its updated and keeps service from the server processes active. 22 July 2011: Wouter - added contrib/nsd.init (nsdc.sh that only does start,stop). - removed nsdc.sh, nsd-xfer, nsd-notify, nsd-patch. for rc.d: contrib/nsd.init, or platform specific init script. nsd-xfer: see nsd-control transfer, or force_transfer. nsd-notify: see nsd-control notify. nsd-patch: see (cron job to) nsd-control write. 21 July 2011: Wouter - nsd-control notify, transfer and force_transfer. - fix for bug in write and reload zone option. - nsd-control zonestatus command. 20 July 2011: Wouter - reload can be given optional zone argument. - nsd-control reopen_logfile. - nsd-control write changed zonefiles. 18 July 2011: Wouter - Fix xfrd activation of zones to not break running zone transfers. 13 July 2011: Wouter - fix that signal causes stats to be printed to log. - fix stats without remotecontrol. - ignore notify and soainfo for deleted zone, if due to race they arrive after the deletion. - tpkg test for nsd-control, addzone and delzone 5 July 2011: Wouter - fix link to ssl with FreeBSD make. 1 July 2011: Wouter - fix optimize compile to link with ssl. 29 June 2011: Wouter - nsd-control delzone zone. Removes zone from zonelist. - stats includes number of zones. - RAXFR stat, which has not worked since NSD 1.2.4, reinstated. - print more memory statistics, for xfrd and config. 28 June 2011: Wouter - nsd-control addzone zone pattern. Adds new zone, slave or master. 27 June 2011: Wouter - nsd-control stats and stats_noreset (if enabled at compile time). nsd does not print statistics to logfile if period is 0. 23 June 2011: Wouter - -flto check supports clang compiler. 22 June 2011: Wouter - remote control, config, client, setup and status command. - reload nsd-control command. - stop nsd-control command. - verbosity nsd-control command. 14 June 2011: Wouter - Fix to have no authority NS set processing for CNAMEs. 9 June 2011: Wouter - fix bug that relptrs have to be initialized with rel_ptr_init() when created and zeroed with rptr_zero before deletion. - tag 4.0.0-imp4 created - trunk is 4.0.0-imp5 under development. 8 June 2011: Wouter - nsd reads the zonelist file on start. - updated acx_nlnetlabs.m4 to version 11. - configure checks size of off_t and increase region-allocator alignment to 8 if it is 64bit and alignment at 4. - fixed bug where not all references were removed before mmap was synced to another process. 7 June 2011: Wouter - code to add and remove zonelist entries, and unit test. 6 June 2011: Wouter - fix unit tests for mmap with TODO and removal of -f in nsd-patch. - zone expiry is communicated via the mmap, and not via the pipes, simplifying the code significantly as well as making a large number of zones more feasible. 1 June 2011: Wouter - mmap used for parent-xfrd communication of tasks and task results. SIGHUP is sent to xfrd so it can become a task in the normal workflow. This can process about 4500 zones per second (this was with lots of debug prints per zone, in debug compile). The mmaps are file-backed with /tmp/ files. They are removed on a clean exit. - nsd.db and tmp mmaps are created with mode 0600 for safety. - updated flag removed, nsd-patch always in -f force mode (-f removed) and writes all zones always. Its role is taken over by task results. 30 May 2011: Wouter - Fix Makefile for U in environment, since wrong U is more common than deansification necessity. 27 May 2011: Wouter - xfrd is forked before the database is read in, thus it does not consume the memory of the database. It can be reforked on a crash, which is like the current case. Difffile is cleaned by main process and the soa serials are all sent via pipe instead of via forkmem. 24 May 2011: Wouter - implemented patterns in the nsd.conf file. they can be instantiated with include-pattern: x. existing zone definitions keep working (backwards compatible), such zones really have an implicit pattern and cannot_delete flag set. - work on zonelist read and storage. 20 May 2011: Wouter - from NSD_3_2 branch the fix: bug if the zonefile is changed for a secondary but stored transfers are applied, and stop ixfr to empty. The zone is flagged with error, and the good zone is still in nsd.db for NSD4. 17 May 2011: Wouter - unit test for code coverage on nsec3 ixfr. - tag 4.0.0-imp3 created - trunk is 4.0.0-imp4 under development. 13 May 2011: Matthijs - Fix bug #381 - Binary escaped and transfers. 13 May 2011: Wouter - Unit test nsec3 salt change and fix for sanity check of nsec3 chain. pretty prints the nsec3 parameters if verbose. 12 May 2011: Wouter - more unit test for nsec3 precompile changes. - unit test for salt change, rehash in udb fix, remove last NSEC3 from chain works, NSEC3PARAM RR fixed up if RR added or removed from NSEC3PARAM RRset, hashtrees cleared properly, precompile clear more thorough (not dependant on nsec3_conditions). 11 May 2011: Wouter - fixes for nsec3 precompile code: precompile for empty nonterminals created when an RR is added. If SOA removed, precompile stays coherent even though domain_find_zone no longer returns correct zone. 21 April 2011: Wouter - unit test and fixes in nsec3 precompile code. 20 April 2011: Wouter - incremental NSEC3 precompile. 14 April 2011: Wouter - remove chnum. Added numlist sorted by domain.number. domains that are not used are removed. 13 April 2011: Wouter - Fix is_existing flag for ENT when domain that has a shared ENT is deleted by IXFR. - zonec can parse strings with RR in it. - unit test for namedb. 8 April 2011: Wouter - porting complete. - tag 4.0.0-imp2 created - trunk is version 4.0.0-imp3. 7 April 2011: Wouter - ported to sunos 4.1.4, the unit test works (udb, radtree in mmap). 6 April 2011: Wouter - UDB_CHECK is enabled if --enable-checking is used. Because it checks the pointer-administration lists it slows down. - udb-inspect has feature -l that lists zones (and RRs) in nsd.db. - fix memory leak by zonec; the region_cleanup triggers too late. - set listen TCP_BACKLOG to 16 by default, it avoids connect reset by peer in 1000-zones transfer on an ultra10, thus for many-zones. - default xfrd-reload-timeout to 1 second. 5 April 2011: Wouter - Fix uninitialised value in xfrd nsd_soa, the rdata_count. - Unit test for update of the nsd.db with new contents. - Fix array bounds check in radtree-search function. 4 April 2011: Wouter - removed zonec from tests. fix unknown_rr test, enable ipseckey test. increased timeouts on tests that are hard on the filesystem. - Fixed IPSECKEY printout by nsd-patch. 30 March 2011: Wouter - nsd edits nsd.db for IXFR and AXFR messages. since xfrd already checks zone transfers completely for syntax those errors cannot happen, if they do (memory, disk error) the file is left dirty, to be recreated on the next start (and the process dies). 29 March 2011: Wouter - nsd recreates nsd.db if it has not been closed properly or is corrupted (bad header or wrong file format). 28 March 2011: Wouter - NSD without zonec. NSD loads zonefiles on start. NSD stores NSEC3hashes on disk. 25 March 2011: Wouter - Fix bug #365, you can set NSDC_ZONEC_VERBOSE and NSDC_PATCH_STYLE in the environment where nsdc runs. - Fix bug #375, typos in nsd.conf.5. - First step of bug #369: RRSIG DNSKEY sets zone to be treated DNSSEC. - Fix bug #302, nsd accepts XFR but refuses to re-read the slave zone. - NSD4 work: removed zonec, nsdc patch does not write text files for slave zones (as if option is always to binary, this capability returns later), nsdc patch deletes the ixfr.db. kill-HUP rereads zone files that have changed. 24 March 2011: Wouter - compile fixes for BSD. preserve RRset order. 23 March 2011: Wouter - udbzone, store and read zone data in the random-access udb format. 21 March 2011: Wouter - udbradtree works. udb-inspect tool can print radtree details. 16 March 2011: Matthijs - undo fix bug#325: messes up dname compression 14 March 2011: Wouter - udb code added. uses lookup3 from unbound (public domain). - unit test for radix tree in cutest. - unit test for udb in cutest. - udb-inspect tool to printout internals of udb files. for debug, not installed or built by default. - removed --disable-radixtree option. 11 March 2011: Wouter - Removed precompile features, speed gain took too much memory. - domain number to size_t. 9 March 2011: Wouter - DNAME synthesis of CNAME. Uses TTL of the DNAME record. - nsec3 and wildcard code. No additional section for wildcards. Also CNAME and DNAME replies contain only that record (and synth CNAME), the chain is not followed. 8 March 2011: Wouter - precompile work: class ANY gets AA flag, SOA and type-NS processing, just like BIND (9.6) and it simplifies processing for NSD. other than compression difference (precompile compresses smaller), there are no differences in a 49000 query testset against the root, without EDNS. 7 March 2011: Wouter - check chown value and report high verbosity its error. 3 March 2011: Matthijs - fix #bug352: fix hardcoded paths in manpages. 2 March 2011: Matthijs - fix #bug354: make realclean cleans too much - added make devclean for cleaning up autoconf and automake stuff - Fix hardcoded paths in nsd.conf.sample and nsd.conf.5 24 February 2011: Matthijs - fix #bug350: refused notifies should log client ip. 2 March 2011: Wouter - Fix AXFR service with radix tree. - cutest for speed of answer encoding, and format of answers for root. 1 March 2011: Wouter - after merge, remove double -I. from makefile. - radixtree is default. Nicer makefile and no warnings from unused flex functions. 1 March 2011: Wouter - merge with trunk r3181: 24 February 2011: Matthijs - fix #bug350: refused notifies should log client ip. 24 February 2011: Wouter - fix bug#362: outgoing-interface and v4 vs. v6 leads to spurious warning messages. - fix bug#363: nsd-checkconf -v does not print outgoing-interface ok. - fix that nsd-checkconf -o outgoing-interface omits NOKEY. 23 February 2011: Wouter - fix for bug#357, make xfrd quit with many zones. 23 February 2011: Wouter - Merge trunk r3151. 22 February 2011: Matthijs - Patch Jakob Schlyter (setusercontext before chroot). 18 February 2011: Wouter - overhaul of testset, with port uniqueness and fast start and stop. 11 February 2011: Wouter - added test case to do with bug357. 24 January 2011: Matthijs - Patch Tom Hendrikx (only errors to stderr when doing nsdc patch). 17 February 2011: Wouter - Fix leak of compressiontable when the domain table increases in size. - added test case to do with bug357. 10 February 2011: Wouter - Merged with trunk r3115 changes: 20 January 2011: Wouter - Fix on shutdown, then getaddrinfo acquired data uses freeaddrinfo. 19 January 2011: Wouter - Bug #348: no -I/usr and -L/usr for libcrypto in /usr. 5 January 2011: Matthijs - Fix nsdc update and nsdc notify - Force outgoing interface to be a single range acl - Update documentation about acl options - Code review - Fix nsdc so it can use hmac-sha* tsigs - Bug #347: NSEC3 nodata QTYPE=DS not at delegation mismatch 4 January 2011: Yuri - Doc spelling error, bug#345 15 December 2010: Wouter - fix race condition when nsd is stopped while a reload is in progress, often when rc.d does nsdc patch; nsdc stop in sequence. reload is now signalled to stop too. 10 December 2010: Matthijs - fix bug#306: applied documentation patch - fix bug#253: now also for QTYPE=DS. 12 October 2010: Wouter - Fix compilation on SunOS4. 24 September 2010: Matthijs - Bug #328: nsd-checkconf overrun 1 September 2010: Yuri - Support for huge TXT records. 23 Aug 2010: Wouter - fix bug#325: remove stale files from cvs from repo. 16 Aug 2010: Yuri - zonec, MAXRDATALEN check was off by one. 9 Aug 2010: Matthijs - nsdc return 1 outside function, should be exit 1 - Bug #320: arc4random 2 Aug 2010: Matthijs - Bump to 3.2.7. 21 July 2010: Wouter - NUM_RECV_PER_SELECT 100 implemented, configure check if kernel supports this. 17 January 2011: Matthijs - Bump to 3.2.8. 5 January 2011: Matthijs - Fix nsdc update and nsdc notify - Force outgoing interface to be a single range acl - Update documentation about acl options - Code review - Fix nsdc so it can use hmac-sha* tsigs - Bug #347: NSEC3 nodata QTYPE=DS not at delegation mismatch 20 July 2010: Wouter - Branched from trunk. Added radix tree. - use -fwhole-program if gcc supports it. 19 July 2010: Matthijs - fix bug#314, NSEC next field now correctly escapes spaces. Also fixes label overflow issue. - Put back HAVE_SSL. - Code reviews. - Add donor text. 6 July 2010: Wouter - Compiles on Minix 3.1.7; checks ss_family, suseconds_t, some warning fixes. Needs socketpair to work, e.g. http://wiki.minix3.org/en/SummerOfCode2010/UnixDomainSockets. 2 July 2010: Wouter - Put back CHECK_SSL in configure (removed with disable-tsig). 17 June 2010: Matthijs - Expand command line option '-a' and config option 'ip-address:' with port number. - Removed --disable-nsid, --disable-dnssec, --disable-tsig 14 April 2010: Matthijs - Bump to 3.2.6. 14 April 2010: Matthijs - uintptr_t fallback value to void* - Backwards compatibility for MAP_ANONYMOUS - Tag 3.2.5. 31 March 2010: Matthijs - Commit b64_pton optimalized compat code (Martin Svec). - Commit (experimental) mmap-alloc-namedb patch (Martin Svec). - Commit parse-token-leaks patch (Martin Svec). 27 March 2010: Wouter - fix bug#303: misspelled error message. 19 March 2010: Wouter - documented nsid: "hex string" setting in nsd.conf.sample. 24 February 2010: Matthijs - nsid: option - Enable NSID support by default - --with-chroot configure option - Less stupid chroot error handling 15 February 2010: Matthijs - Skip memory cleanup to speed up reload (Martin Svec) 1 February 2010: Wouter - compat code for memcmp unsigned comparisons. 21 January 2010: Wouter - fixup debug sprintf to snprintf. 21 January 2010: Matthijs - Secure string functions, including compat code for strlcat. - Randomness utility function - Prepare for default chroot 6 January 2010: Wouter - check write errors when marking commit failed when difffile is broken. 6 January 2010: Matthijs - Move to 3.2.5 23 December 2009: Matthijs - Store new options in nsd structure. 22 December 2009: Matthijs - New options 'ipv4-edns-size:' and 'ipv6-edns-size'. - Bug 276 - Bug 286 - Bug 288 21 December 2009: Matthijs - New option 'tcp-query-count:'. - New option 'tcp-timeout:' and configure option '--with-tcp-timeout'. - New zone option 'notify-retry:'. 11 December 2009: Wouter - Disable UDP IPv4 DF flag on Linux/FreeBSD/AIX with socket option. 20 November 2009: Matthijs - NSID bugfix: NSD did not recognize NSID in the query. 9 September 2009: Matthijs - DLV support 18 August 2009: Matthijs - Bug 269. - Typo: logincap.h -> login_cap.h 12 August 2009: Matthijs - Maintainers feedback 10 August 2009: Matthijs - Code review. - Also send errors to /dev/null in controlled_stop. - chown nsd.db 7 August 2009: Matthijs - Bug 266: don't have strptime build error 28 July 2009: Matthijs - Bug 263: make TSIG algorithms comparison case insensitive. 23 July 2009: Matthijs - Patch Paul Wouters for NSD using hardcoded name. 13 July 2009: Matthijs - Bug 236: allow RRs before the SOA RR. - Bug 253: No need for NS RRset in authority section, when returning final answer for QTYPE=DNSKEY. 29 June 2009: Wouter - patch for use of Linux IPV6_MTU option, so that on linux the default EDNS UDP size advertised becomes 4096 over IPv6. It fragments the packets using the IPv6 minimum MTU. 19 May 2009: Matthijs - Clean up configure script (install hickup) - Bug 249: Remove unnecessary LLONG_MIN and LLONG_MAX code. - Replace strtoll code with own strtoserial function. - Move up to 3.2.3. 11 May 2009: Matthijs - Add Off-by-one test 6 May 2009: Matthijs - Small fix in SO_REUSEADDR warning log message. - Off-by-one bugfix (thanks Ilja van Sprundel, IOActive) 29 April 2009: Matthijs - A more ensured do_stop (useful fo nsdc restart). 2 February 2009: Matthijs - Bugfix #234. - Bugfix #235. - Reset 'error occurred' after notifying an error occurred at the $TTL or $ORIGIN directive (Otherwise, the whole zone is skipped because the error is reset after reading the SOA). 2 February 2009: Matthijs - Bugfix: return BADVERS when EDNS version > 0, instead of 0x1. 19 January 2009: Matthijs - Bug 230: nsd-*: use stdout for non-error output (instead of stderr). - Don't do strptime test when cross compiling. 17 January 2009: Jelte - Fix file rotation when no logfile but chroot. 8 January 2009: Matthijs - New nsd-patch option -o dbfile (set output.db) - update nsdc to deal with the new nsd-patch options - strptime compat fix 6 January 2009: Matthijs - New nsd-patch option -s (skip writing zonefiles) - Removed some region_create memchecks (not needed) 5 January 2009: Matthijs - Bug 218 - Bug 222 - Replace SHA256_DIGEST_LENGTH with nicer HAVE_EVP_SHA256 10 December 2008: Matthijs - Bugfix: better error message when ixfr.db cannot be read 18 November 2008: Matthijs - chown logfile, don't do file rotation if logfile is outside absolute and outside chroot. 17 November 2008: Matthijs - File rotation for nsd.log when owned by nsd (+ tpkg test). - Only AXFR fallback if master responded NOTIMPL or FORMATERR on IXFR request. - allow-axfr-fallback option. 7 November 2008: Matthijs - Bugfix: don't fclose if logfile == NULL. 30 October 2008: Matthijs - Allow escape characters in literal dnames - Fix typo in zonec manpage - Some fixes from code review 20 October 2008: Matthijs - Redo bugfix literal domain names in rdata (code adjustment) - Added tests for case sensitive dns names and "Bug #162" - Adjust nsd-patch to new ixfr.db format 14 October 2008: Matthijs - Only SO_LINGER when outgoing port is set - Reset diff_skip when a new difffile is created (parts in the difffile now have a timestamp). - Undo bugfix literal domain names in rdata (code adjustment) - Split up dname_parse to parse literal dnames and normalized dnames. 3 October 2008: Matthijs - setsockopt SO_LINGER, for portability outgoing-interface (BSD/Solaris) 1 October 2008: Matthijs - Configure the source ip-address for notifies by the master and zone transfer requests by the slave in nsd.conf. - Previously added source hostname/ip and port configuration for nsd-notify and nsd-xfer - Finetuned nsdc for nsdc notify and nsdc update 29 September 2008: Matthijs - Bugfix: only normalize domain names in rdatas when rrtype is listed in RFC 4034, section 6.2: Canonical RR Form. - Update TODO list 25 September 2008: Matthijs - Fix bug where hmac-sha256 was in algorithm table, but could not be retrieved by name or id. - Additional arguments for nsd-notify and nsd-xfer: set outgoing hostname/ip-address and source port. - Additional TODO entry: optimize code in nsd-* programs. 8 September 2008: Matthijs - RFC 4635, bugfix #130: support for hmac-sha1 and hmac-sha256 tsig algorithms. - modify and add tpkg tests for hmac-sha1 algorithms. 2 September 2008: Matthijs - AXFR fallback when IXFR/UDP failed on all masters - Bugfix: strip off chroot value in corner cases - Additional debug and verbose log messages 29 August 2008: Matthijs - IXFR allow UDP option 26 August 2008: Matthijs - Code layout, additional comments and documentation typo fixes - IXFR over TCP, no longer UDP 17 July 2008: Matthijs - Make the maximum number of interfaces configurable. - Write pidfile *after* successful server initialization, instead of writing, and unlink if fail. 16 July 2008: Matthijs - Set upcoming release to 3.1.1 - Wouter: fixed memory leaks that happened on error, mostly on zone transfer errors. 11 July 2008: Matthijs - Avoid race condition in nsdc: let nsd server update pidfile before closing old parent process. 8 July 2008: Jelte - Fixed NSEC3 memory leak in the case NSEC3 is not needed. 7 July 2008: Matthijs - Bugfix #191 9 June 2008: Matthijs - When comparing RRs, do not compare TTL values (since the same record with different TTL values are considered equal). - Fixup some more unaligned memory access that could occur when reading ixfr.db. 19 May 2008: Matthijs - Do not always log tcp read errors, only when real error or high verbosity 28 April 2008: Matthijs - Bugfix #172 (misleading error from zonec) 27 March 2008: Matthijs - Port some branch modifications to trunk 28 February 2008: Matthijs - Do not answer nsec3 wildcard information when DO bit is not set 19 February 2008: Matthijs - Fixed strptime bug (for MacOS Leopard) 22 January 2008: Matthijs - Add configuration for chkconfig to control nsd service (bug 164) 15 January 2008: Matthijs - Fixed bug 157 where nsd would return FORMERR if edns query is received with version set to zero and rdlen is larger than zero. 8 January 2008: Wouter - no warning about optout records. also no warning about missing nsec3 records. - check for hash(apex)==nsec3 with SOA bit was done in duplicate. - removed old commented out code - using SOA bit in NSEC3 typemap to detect parameters - using nonhashed NSEC3 to prove qtype=NSEC3 nxdomains - prints for debugging. - nicer comment on nsec3_lookup. 7 January 2008: Wouter - Fixup nsec3 tests, they need zonesdir: "." in conf files. The tests pass. - configure default is --enable-nsec3. Disabling this will save 20% more memory (for very large zones). Moved tests to test on commit. - set RRTYPE numbers for NSEC3=50, NSEC3PARAM=51. - fixup checkconf test - updated parser lexer gives syntax error on some garbage instead of parse error. Parselexer is updated for new options (hide-version, verbosity). - removed highrange rrtype code. fixup cutest for that. - speedup of prehash code. - skip nonexistent domains (operator.example.com). - skip only-nsec3 domains (that could be 2x speedup) - skip glue nameserver domains (for TLD with 2 glue per delegation this is a 3x speedup). - skip the prehash_domain for delegation points, which saves another 2/3 hash operations, 3x speedup. - printout how long nsec3 prepare took (verbosity >= 1). 3 December 2007: Matthijs - Fixup bug where data related files are looked up in the wrong directory when chrooted with chrootdir ending with a slash. 26 November 2007: Matthijs - Fixup bug start nsd while already running: do not initialize server, since it is already running. 15 November 2007: Matthijs - Changed man pages format from mdoc to mansun, to support the Solaris OS. - Better logging for nsd-notify (show 'broken' zone) 13 November 2007: Wouter - CREDITS and RELNOTES now in utf-8. 12 November 2007: Matthijs - Changed man pages according to bug 162. 30 October 2007: Wouter - Fixup for skip after unknown deleted IXFR RR, otherwise processing would continue at the wrong spot in the packet and process the IXFR as if it were malformed. - added unit test for this in long (needs ldns-testns, updated it). - added unit test for rollback of malformed zone transfers. Fixup for it, and fixup in ldns-testns to be randomport and copy id for hex packets. 29 October 2007: Wouter - Fixup bug where malformed IXFR replies cause partial processing in reload (or nsd-patch or nsd-startup). One result is multiple SOA records in zone apex. Fixup rolls back the zone transfer, and waits for NSD to try to load again. 26 October 2008: Wouter - small fix in descriptive text in sample config for debug-mode. 9 October 2007: Mark - Change default location of: nsd.db, ixfr.db & xfrd.state to /var/db/nsd. 5 October 2007: Wouter - Fixup manual page entry for allow AXFR to anyone. 3 August 2007: Mark - Report source and zone for denied AXFR attempts. 25 July 2007: Wouter - bind2nsd to 0.5.0, fixup of includes, key{} handling. 19 July 2007: Wouter - bind2nsd to 0.4.8, fixup of include bug. 18 July 2007: Wouter - added contrib for bind2nsd, Al Stone provided an abridged version that neatly fits for contrib. 17 July 2007: Wouter - fixup commithooks. 16 July 2007: Wouter - Added reference to http://bind2nsd.sourceforge.net/ to contrib/README. 3 July 2007: Mark - Zone compiler now gives more sane error message when out of diskspace. - Fixed a call to drill in tpkg that made a test check bind instead of nsd. 2 July 2007: Mark - Remove last traces of mmap usage. - Some cleanups in tpkg. 24 April 2007: Mark - Added "hide-version" configuration setting. Enabling this feature stops NSD from answering to CHAOS class version requests. 19 April 2007: Wouter - Compiled on minix 3.1.3 and make some adjustments to ease porting. ECONNABORTED is checked for. sys/select.h included in nsd-notify. SO_REUSEADDR failure is not fatal. PF_INET compat code added. If you compile yourself; strptime and socketpair need compat code. 13 April 2007: Wouter - Minor tweak to nsec3.c, more elegant handling of malformed nsec3 records from a zone transfer. 10 April 2007: Wouter - Fixup ignored return value in region-allocator. Now returns a NULL memory allocation failure and leaves region in a consistent state. 20 March 2007: Wouter - Released 3.0.5. - (for 3.0.6) -O2 test for Alpha moved to saner position. 16 March 2007: Wouter - port configure to AIX, removed warning on ALIGNMENT in region code. defined _ALL_SOURCE to get recent C definitions on AIX. - improved nsec3.h comments. 22 February 2007: Wouter - Zonesdir default is now /etc/nsd. So that the invocation directory is not used to dump files into. The user can change the zonesdir by editing the config file. The directory is created by install, if not an error is printed. - updated tpkg tests to use current dir for testing. - tcp connections that drop do not spam the log file. Unless verbosity is set high. 19 February 2007: Wouter - Fix empty line printed with warning on 'force zone transfer'. 15 February 2007: Wouter - Check for EPROTO definition to compile on FreeBSD4/Alpha. 13 February 2007: Mark - Debug flag (-d) behavior changed. Nsd now also forks children when run in debug mode. - Added verbosity mode (-V ) for extra operational logging. 8 January 2007: Wouter - README text on interface configuration added. 2 January 2007: Wouter - Fixup accept() that could block due to already closed connection. Made listen() nonblocking, ignores errcodes that indicate closed tcp. 29 January 2007: Mark - Handle the new CERT RDATA types defined in RFC 4398 (submitted by Mans Nilsson). - Change nsd-notify retry timer from linear into exponential backoff (submitted by Mans Nilsson). - Due to a small bug in a comparison statement, zonec would fail on the parsing of unknown CERT types. This got triggered by the first bugfix today, as that one shouldn't have been discovered in the first place. Took the opportunity to sanitize two other comparison statements related to strtol(). 24 January 2007: Wouter - Tentative change to set UDP sockets nonblocking. Perhaps it helps Howard. 19 January 2007: Wouter - NSEC3 work. prehash printed only once with time taken to prepare. - prints are now only in DEBUG mode (except errors). - rr descriptor counts for NSEC3 updated, has an extra field flags. - now NSEC3PARAMs with flags!=0 are ignored, as per draft-09. - Fixed where only first NSEC3PARAM was properly detected. - Added tpkg in manual (because you need to compile with nsec3) that performs the test queries from draft-09 and checks them. - Made tpkg to test NSEC3 parameter detection. NSD will skip any NSEC3PARAMs that don't work until the first working one is found. Also, this means unknown hash algorithms are simply ignored. A zone that uses exclusively unknown hash algorithms for NSEC3 will give errors on loading (or after zone transfer) but NSD will load and serve the zone (but no NSEC3s are returned). - added tpkg in manual to test parent side DS answers. These follow a different code path than child side DS. - Will allow NSEC3s(and signatures) below a DNAME. - A query for an NSEC3 ownername will lead to DNAME redirection as if the NSEC3 did not exist. - Test package in manual that tests NSEC3 and DNAME in the apex. - Changed NSEC3 memory requirements from 5 pointers per domain name to 3 pointers and 2 bits. - Added jumpstart for nsec3 search, will greatly speed up optout zone nxdomains. At the cost of one ptr per domain name. The speedup also speeds up the nsec3 prepare stage. 18 January 2007: Wouter - Created 3.0.4 release tag. - 3.0.5 number in trunk. - add nsd.spec patch from Farkas Levente to contrib. - NSEC3 new wireformat and presentation format from draft-09. 11 January 2007: Wouter - The message 'server .. closed cmd channel' is now priority INFO. This to reduce the 'error' amount in the logs. - On error in a tcp request, set to retry next instead of waiting for the tcp timeout. 9 January 2007: Wouter - TSIG acl matching changed so that NOKEY allow-notify entries match only queries without a tsig. Otherwise NSD would crash. This only affects servers that have allow-notify: ip NOKEY and someone sends a TSIG signed notify from that ip. - test package for that. - Fix for reply to notify messages with ANCOUNT wrong. The ack to notify messages that passed the ACL, and had a SOA in the answer section of the query, included wrong RR counts in the header. - test package for notify reply wireformat. 8 January 2007: Wouter - ipc_send_blocked will not lead to busy waiting on it, but will block in select, until SOA_END comes by. - server_main sends SOA_END if reload crashes, to xfrd. So that xfrd can set ipc_blocked=0 and can_send_reload=1; and thus resume service, assuming that the crash was a temporary condition. This will lead to trying every reload-timeout seconds to reload if it is a permanent condition. Which is more obvious to the operator. - put the error "error: diff: RR ns.kiev.ua. already exists" in debug mode only. Zone transfers with this error are liberally accepted, and we should not spam the logfile. - empty zones will not be retried forever every 10 seconds, but exponential backoff to a max of every 4 hours. The exact value is randomised to spread out attempts. 5 January 2007: Wouter - Fixed --zonesdir= for configure. The value did not get used as a default value. Now it is used as a default value. If a default value is set for zonesdir, you can go to a 'no value specified' by giving the empty string, zonesdir: "" in nsd.config. - Fixed checkconf.tpkg for this change. nsd-checkconf will output zonesdir: "" as this is the default for --zonesdir. 2 January 2007: Wouter - Added contrib script from Stephane Bortzmeyer to convert NSD 2 to NSD 3 config files. Converts secondary zones and TSIG keys. - Made config conversion script skip empty lines. - Made config conversion script convert primary zones (and notify). - Nsdc control script will exit with 'nsd startup failed.' if nsd fails to start (due to bad config file for example). 15 December 2006: Wouter - Removed dlopen() checks from configure.ac, NSD3 no longer has dynamic plugin support (since 3.0.0). - added .rpm spec file to contrib. - Updated README to remove reference to buildzones script. 12 December 2006: Wouter - Added missing include to ipc.c to compile on SunOS. - Cast to avoid signed/unsigned comparison in compat/inet_ntop.c. 11 December 2006: Wouter - Added test to check for CNAME and other data error by zonec. Currently NSEC, NSEC3, RRSIG, SIG, NXT are allowed next to CNAME. - Fixup unaligned memory access that could occur when reading ixfr.db with a partial transfer inside. - RR type WKS (well known service) was not printed correctly, htons() was forgotten when calling getservbyport. - NSD does not complain about not being able to read the db CRC when all that happens is the file became longer or shorter. 8 December 2006: Wouter - Moved down max XFRD UDP sockets for zone transfer queries to 100 down from 300. This makes the total socket max at 200, so it fits easily under 256 ulimit (a common default). 7 December 2006: Wouter - Improved error message to help operator. - created 3.0.3 svn tag. - default of zonesdir corrected (no directory is default). 4 December 2006: Wouter - updated test packages. Moved 213_large from manual to long. size_0, source_port_0 made more working (needs root permission). 1 December 2006: Wouter - Moved xfrd ipc and reload handlers to front of event handler lists for a 10% speedup in xfrd. - Fixed so that NSD no longer interrupts zone transfers when a notify comes in for that zone. Added package to test it. - Fixed warning on Solaris 10. 30 November 2006: Wouter - Test for fallback in getaddrinfo more portable. Ported to FreeBSD 6.1 without inet6. - New quit sync had a problem with blocking in dispatch. Fixed. - reload will retry quit_sync if nothing happens. - parent tries to empty the pipes before closing them on quitsync. - xfrd does not send reload when previous reload request busy. - netio will only deliver the number of bits from select and then stop. Optimisation. 29 November 2006: Wouter - Fixed getaddrinfo error message to be more descriptive. - Fallback to ip4 also if getaddrinfo fails for ip6. - instead of EAI_ADDRFAMILY uses EAI_FAMILY which is portable to FreeBSD. - signed/unsigned warning fix for FD_SETSIZE comparison. - Lots of debug statements and new quit sync feature, where the server children are synced with. So as not to lose buffers. 28 November 2006: Wouter - Debugging 10k zones transfer, set so that zones waiting for a socket do not get timeouts. - Debug change so that an event is only returned to one handler by netio. Reversed this. Netio will not deliver events you do not listen to, and since xfrd first listens to write then read, it will not have problems with stale events (for the fd from the previous select) because these are always read, while it needs a write. Re-Reversed it: netio will deliver events only once. This is easier to understand for the poor hapless developer. - Need to set notify_current for notify on waiting list. Fixed. 27 November 2006: Wouter - Debugging 10k zones transfer, noticed that it is possible for netio to give a callback for an event that you were not listening to. Now no longer does that. 16 November 2006: Wouter - Bug #153: now checks for FD_SETSIZE when adding fd to select fdset. - Easy overview of socket allocation for xfrd in xfrd.h - Upped the default xfrd socket limits a bit. - Log message that the TCP connection limit is reach is now only in -L 2 logging. It is spammy. - updated dependencies. - Added test for notify-socketcount, and removed unused files from bug153 test package. - Notify udp sockets are also capped at a max number. The rest has to wait in a queue. 15 November 2006: Wouter - Fixed bug #152: identity keyword in nsd.conf did not work. What happened was that the hostname() from the computer was overriding the nsd.conf identity. Fixed now. If commandline is given that is used. Else nsd.conf entry is used. Else hostname() detected from computer is used. Else default string "unidentified" is used. 14 November 2006: Wouter - Fixed bug where NSD tries to create 10000 udp sockets, when starting with 10000 secondary zones. Limited to 50 at a time. The XFRD_MAX_UDP constant controls this. 3 November 2006: Wouter - Created tags/NSD_3_0_2_REL. 2 November 2006: Wouter - Added pdf for differences.tex for ease of use. - Updated text in readme on memory usage. 24 October 2006: Wouter - Recycle rrset memory after doing special processing on the deleted rrset data. - log message clearer for 'duplicate xfr part' to 'discarding partial xfr part'. - if you have a server that has IXFR turned off but sends a TC flag for IXFR queries, xfrd will retry to TCP. This makes the use of 'AXFR' flag in nsd.conf file not needed in certain cases. - Be thrifty and save up the memory that was lost at end of chunks in the recycle bin. Saved 1.3Mb on 170(rrs)/220(total) Mb dataset. 23 October 2006: Wouter - Added checks for out of memory in reload (diff file). And it exits if so neatly. 13 October 2006: Wouter - Bug #149: Wrong text for NOTAUTH error code. When notify is not authorised REFUSED error code returned instead. 4 October 2006: Wouter - More fixes from Koh-ichi Ito (kohi@iri.co.jp now), for bug #146, his bash does not do $(( )), so nsdc.sh has to use test of course. 29 September 2006: Wouter - recyclebin works, added a test that uses it (about 3 Mb goes through the recyclebin). This resolves bug #147. - Made -L 1 logging is little less verbose (-L 2 gets it all). - added search path for openssl on Solaris 10 (/usr/sfw). 28 September 2006: Wouter - Removed unused global variable current_region, and routines for it in region-allocator.c and .h. - Added recycle option to regions. It will keep track of small objects in a recycle bin. Large objects are deallocated. No calls to recycle yet, unit test it first. - added unit test for region recycle. 27 September 2006: Wouter - Further suggestion from Koh-ichi Ito, I've set opt->xfrdfile to XFRDFILE in options_create. So opt->xfrdfile and opt->difffile are never NULL. This simplifies code elsewhere. And also handles chroot case (+=l) for default values. - Fix for bug #145. The skip file position in the diff file was used inconsistently - one part of the code skipped to before the 'IXFR' type code and another part skipped to after that. Now all skip to before the type code. This bug only happens if your diff file is like: zone1_part1, zone2_part_1, zone1_part2, zone1_commit, zone2_part2, zone2_commit. The skip over zone1_part1 failed. - tpkg test in long dir that tests for the bugfix. Takes a long time and uses ldns-testns feature to wait partway through an AXFR. - removed debug log of strerror on diff read failure, when the errno was already output to the logfile (resulting in a nonsense error). 26 September 2006: Wouter - NSD compiles on Solaris 10 with the sun cc compiler. Added a define for _STDC_C99 for that. - Checked that the patch for solaris for bug 143 indeed fixes the bug. - Fixed bug #146 reported by Koh-ichi Ito: when chrooted nsd failed to write xfrdfile/difffile. 18 September 2006: Wouter - no queries for NSEC3, RRSIG, ANY succeed for nsec3 only domains. 15 September 2006: Wouter - Fixed LOC parsing of integer overflow causing maximum values. Added to test and backported fix to 2.3.6. - NSEC3 qtype queries get noerror/nodata or nxdomain answers. You can query for NSEC3PARAM. - warnings for printf format on maxOS (sizet needs cast to int). 13 September 2006: Wouter - added fsync to AF_UNIX sockets to write last command (QUIT) before closing them. - sent explicit QUIT command to xfrd on final shutdown of the server. 12 September 2006: Wouter - Bug #144: LOC defaults for unspecified values wrong. Error in zonec. Set defaults. Also fixed parser if LOC has no minutes or seconds. - Also fixed rounding error in seconds 0.001 decimal. - Test tpkg for bug 144. 11 September 2006: Wouter - nsdc now more portable in use of 'which'. Does not only look at exit code but also checks for '^no ' string. - nsd-patch does a chdir to zonesdir for relative difffile or dbfile path names. - nsdc handles zonesdir: for relative pidfile, dbfile, difffile pathnames. 7 September 2006: Wouter - bumped version to 3.0.2. - Nice configuration error when you had the wrong zone name in the nsd.conf file. Zonec will give an error already. - When you start a secondary zone without a zone file, you get a much nicer error message, warning you of the zone transfer. - Credits for prerelease testers; Thanks guys! 6 September 2006: Wouter - Fixed nsd-patch so that it writes the SOA at the start of the file. - test tpkg that tests for the bug, has multiple rrsets at zone apex and does nsd-patch followed by zonec. Previous tests did not catch this: they used nsd-xfer to test zone contents, or only checked the zone-file after nsd-patch. - version number bumped to 3.0.1. - svn tag 3_0_1 made. 5 September 2006: Wouter - differences file improvements. - created 3.0.0 release in svn tags. 4 September 2006: Wouter - From suggestions by Bin Zhang: - nsdc restart does not fail if nsd was not running. - fixes to man pages, wrong locations for files. - NSEC3-PARAM has no optout bit in presentation format. - NSEC3PARAM spelling. - differences in latex format (needs nlnetlabs housestyle). 31 August 2006: Wouter - Fix for tsig size still set when data is null ptr. - Fix configure for NetBSD (1.6 - 2.0) to find struct timespec. - DIFFERENCES file completion. 30 August 2006: Wouter - Print error nicely when nonblocking connect fails on systems in a portable way. - doc/UPGRADING document to assist NSD 2 to 3 upgrades. - updates of error print - ignore EINPROGRESS if we check too early. - wait for select writable before testing for connect error. - echo "" >&2 is not as portable as we would like, removed from nsdc. - fixed debug print of a null ptr. - fixed bug where query for CNAME that points to unserved zone caused nullptr exception on empty zone ptr. Now original zone is restored after CNAME-pointed data is added to the packet. Test in dname.tpkg. Reported by Kai. - fixed stack corruption when ipv6 disabled. 29 August 2006: Wouter - NSEC3 made it so it can handle the case where the NSEC3 RRSET with the SOA bit on does not have the RR with the soa bit set as the first RR. - Handle NSEC3-PARAM type. Checks to see if any of them work: zone apex hashed exists, with NSEC3 type, and RR that has the same parameters and the SOA bit set. - in presentation format of NSEC3, NSEC3-PARAM reversed hash, optout. - update to the DIFFERENCES file, bind 9.3.2 vs NSD 3 and NSD 2 and 3 comparisons are completed. 28 August 2006: Wouter - echo messages in nsdc made clearer. nsdc notify and nsdc update only send notify messages to slaves / localhost to force transfers. - initial NSEC3-PARAM type code entry. parsed, ignored. 25 August 2006: Wouter - disabled make test target as tests are not shipped. - performed prerelease static snapshot. - updates to the DIFFERENCES document. 24 August 2006: Wouter - Fix bug 141 port from 2.3.6, copies behaviour from bind 9.3.2. - Added a test for bug 141. - Bug141: save the opcode from the query. 23 August 2006: Wouter - Fixed % by 0 exception in the bugfix #139. - Fixed RFC 4035 says CD flag SHOULD be cleared on authoritative responses, now NSD clears the CD flag. This is bug #140. RFC 4035 could be confusing on this, as it states 'all servers MUST copy the CD bit' more than once, but then makes clear only recursive servers are meant with that statement. - Differences document updates for bind 9.3.2 and nsd 3. 22 August 2006: Wouter - version number to 3.0.0 in preparation for release. - Bug #139: resync stats to whole period. Fixed. 21 August 2006: Wouter - check for error in ftruncate call. - replaced fwrite call with write_data call from util that does error checking. 15 August 2006: Wouter - removed unused struct nsd.named8_stats variable. - Bug #138: nsd aborts trying to bind all interfaces if ip6 is not enabled, instead it will fallback to ip4. 14 August 2006: Wouter - Added test for rollback of an IXFR transfer by xfrd. - Added test for reload timeout in xfrd, the reload does happen after a while, but not immediately. - Test that makes xfrd connect to ip6 address. - Test that overloads the number of tcp connections in xfrd, simulating a slow master, so that zones have to queue up to get it. - code coverage is now 2514 of 10636 uncovered. Still a lot uncovered. - ixfr queries return NOT_IMPL errors. 11 August 2006: Wouter - srandom to init random() in xfrd based on PID and time. - improved usage() information to be more helpful, and with version. - in makedist.sh, flex and bison called like in Makefile. - test for tcp underrun and overrun of the buffer. 10 August 2006: Wouter - added more tests to increase code coverage of testset. - moved acl parsing code from configparser.c to options.c to help unit testing. - nsd-checkconf echod wrong difffile filename with -v. - nsd-patch can now be used with -f to force printing of all RRs. - TYPE_NULL crashed NSD when it printed it, arg was ZF_DNAME, now ZF_UNKNOWN. - unknown rr test was faulty on input, the length was in nibbles not in octets, but rfc specifies octets for unknown rrs. NSD does not look at the length, and prints the length correctly. - added type NXT to the rr-test for weird RRs. - added printing test to rr-test, ipseckey and unknown-rr tests. checks if NSD prints the same RR on output as it read in. - put -x option for nsd-patch in usage(). - test that kills an nsd child server and checks that it is restarted. 9 August 2006: Wouter - tested nsdc functionality, make install and make uninstall. - set O_NONBLOCKING on xfrd tcp sockets before the connect call, because the handshaking can take very long too. - difffile and xfrdfile set via configure, to absolute pathnames, so that chroot checks work for them. - updated tpkgs, they need to set relative paths now for difffile. - gcov says 2821 of 10617 total code lines are not covered. compiled with --coverage, not -O2, ran tpkg/* and long/testplan*. counted grep '#####:' *.gcov | wc and grep '^ *[0-9]*:' *.gcov | wc. - cleaned up the log functions, NSD no longer spams the syslog with debug messages. The standard NSD debug util is used, -F -1 -L 2 for a compile configured with --enable-checking will enable them again. Errors are logged, as is the automated reload of a new serial. - tpkgs for bug077 and bug107 were silently failing to test properly. 8 August 2006: Wouter - fixes for checkconf test, more portable. - removed items from TODO that have been tested. for multihomed servers you have to bind to each interface explicitly to get outgoing ip-address the same as query destination ip-address. Forks and if-existing are tested and ok in testplan tests. close_all_sockets is called by child, if tcponly, so leave it. - user name check is hard portably with shell scripts, and packaging could set a default user that does not exist on a machine. - empty nodes (nonterminals) give no nxdomain any more (todo item done). - removed (old) from TODO. - removed contrib/buildzones.pl, it is outdated. 7 August 2006: Wouter - Made the tests a little more portable. - fixed mempcy unable to handle unaligned memory addresses on Solaris, used memmove instead of memcpy in zonec LOC conversion code. - another unaligned memory access, when storing off_t pointer in difffile.c, used memmove. 4 August 2006: Wouter - nsd will start if diff file is corrupt, with a log message. It ignores the bad data. - tpkg files do not override PATH, svnhook sets it. So user can set path to utilities on the system to run the tests. - running testset on DecAlpha discovered uninitialised variable in NSD. Fixed. - Jakob Schlyter asked for building nsd3 in an obj dir, i.e. mkdir obj; cd obj; ../configure && make. Fixed up makefile for that. - and bug137.tpkg for separate obj dir building. 3 August 2006: Wouter - more tests in mesh test. - changed test packages to put nsd log to test result "/dev/stdout". - test packages more portable - use default 'dig' location. also, path is appended to, instead of replaced. 2 August 2006: Wouter - Region can be customised for detailed memory handling. Especially if you set large_object_size=0, chunk_size=0, the region will perform individual allocs, and 'save memory'. The region still keeps tracks of allocations so that at region_free time all memory is released. - tsig.region removed, it was not used after attaching a cleanup at creation. tsig creation uses custom region settings. - xfrd inits the tsig records with memory saving settings, so the regions alloced for tsig take up about 60 + 4*8 bytes. - new custom region for query region - to make chunksize larger there. The chunksize for the query region is important, if all allocations for a query fit in it, no mallocs are needed. - TSIG other_data field size according to RFC 2845 is 0 or 6. In tsig implementation put a maximum to the field of 16, otherwise a formerror results. - query with IXFR appended SOA not formerror. IXFR queries not reach the handler in axfr.c for IXFR queries. - removed annoying debug message of added tsig key. - added test that starts 7 servers in a mesh and lets them fight out what zones to transfer and serve. - xfrd logic bug: if notified a slave would not see the renewal of its current zone. 1 August 2006: Wouter - Test for remove domains with IXFR. - Fix for empty nonterminals and IXFR deletes. - Test for timeouts, including expiry, and expiry and zone updates. - Test for axfr refused authorisation. - Test for deadlock in ipc. 31 July 2006: Wouter - Test plan ixfr test in tpkg/long directory. - IXFR with many packets tested (one RR per packet). 28 July 2006: Wouter - tentative change, that preserves ordering of rrtypes for a domain. - fix for serial rollover (old_serial + 2**31), now works, is seen as new serial and rolled over to new. - serial numbers, and time values, printed as unsigned to logfile. - set so that if info is provided by operator, refreshing state not expired is used. - forgot to * a pointer to boolean, is_ixfr in the difffile reader. This fixes the testplan_ixfr test 1. 27 July 2006: Wouter - fixup desc of tsig xfer test, remove debug from xfr_huge. - fixed compressed dname tables cleanup, to set ptr to NULL. - initialised xfrd_listener.fd to -1. - fixed difffile handling of very short AXFRs, with no data. 26 July 2006: Wouter - Updated the requirements with comments from Olaf. - README discourages use of experimental nsec3 rr a bit more. - typo in DNAME code, used original qname instead of CNAME adapted qname variable. - added IPSECKEY RR type, RFC 4025. - tpkg test with sample ipseckey rrs. - wireformat for IPSECKEY depends on the value of a rdata atom, added WF_IPSECGATEWAY to handle that. - DHCID type, data is encoded in one binary/b64 blob. 25 July 2006: Wouter - max number of tries for nsd-notify is 15, so that the total time for sending is about 75 seconds. - forward port of fixes for bug 105 and 135 in nsdc. forward port of test for bug 105. - fixed nasty bug with configure --prefix=<...> where config.h was wrong. Now double evaluate the shell expansion on the defines. 5 July 2006: Wouter - helped in README with gnu make; need to make clean so that botched attempts by make to create the lexer files do not stay around. - removed %zd, replaced by casts to int. - updated REQUIREMENTS file, the sections on RR types, on what algorithm NSD follows and on which RFCs are supported are updated. 3 July 2006: Wouter - 'make depend' target in makefile. (updates both Makefile.in and Makefile, so it works for users and for svn). - doc minor update. 2 July 2006: Wouter - TESTPLAN, README, bugzilla-bugs docs updated. - NSD for BIND users update. 29 June 2006: Wouter - removed --zonesfile nsd.zones configure option. - doc/README updated for 3.0. - doc update. NSD_FOR_BIND_USERS document. - moved from -Ds to the config.h header, cleaner compilation output. - use autoconfs built in large file support enabler. 28 June 2006: Wouter - nsdc neater, checks for BLOCKED ips more strictly. - nsd -d also disables xfrd forking, and thus all reloads and secondary zone treatment. Stated so in manual page. - fixup, apart from ip4 need to allow ip6 in example.conf line showing how to allow access for everyone to axfr. 27 June 2006: Wouter - Fixed read in server.c to be a blocking read for sure, even if ipc is not blocking on the OS. - nsd-notify tries to send notify 5 times, then exits with error. - nsd-checkconf can lookup key secrets by name from a config file. - difffile option is always set in options struct with default or config value. - nsd-patch uses dnames to compare zone names (for trailing .). - nsdc updated to work with config file. 26 June 2006: Wouter - Nicer check in autoconf for struct timespec type. - NSEC3 next hashed ownername is a length byte followed by data. - nsd-checkconf more quiet, clearer error message. - NSEC3 does not complain about glue records without nsec3. - nsdc work (did start, stop, running, rebuild, restart, reload, stats). 21 June 2006: Wouter - nsid commandline parsed using hex_pton routine. - unit test for hex_pton. - added include stdlib, needed for free() on sunos4. - fixup of disable-ipv6 compilation. - memmove compat implementation (created fresh). - yy_set_bol() for old flex compat define. - compat implementation from openssh4.3p2 for strlcpy, inet_aton, and inet_ntop routines. - changed ctime_r usage to ctime() call, nsd is not threaded. - compiles on SunOS4/gcc-2.95. - debug statements go to the log_msg route instead of the fprintf route, so they will get to a nice logfile even if we forked away, with xfrd. logfile=/dev/stderr gives old way. - minor changes to cutest to make unit test compile on SunOS4/gcc-2.95, it checks out fine there. 20 June 2006: Wouter - updated configure to disable -O2 on platforms where gcc does not like it (such as dec-alpha). - nsd-notify used recvfrom and passed addrinfo.ai_addrlen which is a size_t, but recfrom needs a socklen_t*. On dec alpha these types differ in size (size_t is 64bit, socklen_t is 32bit). Therefore, used a wrapper variable to pass to recvfrom. - changed long int to time_t in nsd-patch.c to please compiler on dec alpha. - dec alpha complains if statements are in front of variable definitions. Fixed code for some mixups on this. - Fixup cutest for dec alpha. Code, lowercase filename, %lf->%f. - cutest fixup uses (size_t) cast and %zx to print ptrs (for debug). - for SunOS4 configure detects ssize_t and struct timespec. - removed usage of fpos_t, instead using fseeko/ftello for 64bit. - configure will define fseeko/ftello with fseek/ftell if unavailable. - added missing include from buffer.c (stdlib for free()). - defines for snprintf and vsnprintf in config.h if needed. - configlexer flex is called more cleanly with -t to write stdout. - missing include from configparser, stdlib for atoi. - config.h provide inet_pton define if it is not available. - fixup of INET6 defines, where sockaddr_storage is used outside of INET6 defines, in xfrd-tcp. - edns_init_nsid was not defined in edns.h. - added compat/fake-rfc2553.c and h from openssh 4.3p2. That has a BSD license as well. They replace getaddrinfo() (and friends) when those are missing. 19 June 2006: Wouter - updated the tpkg/manual tests for NSD 3 config files. Some need root privileges to run (using hping), they all pass. - also the tpkg/long test bug_sighup. - nsec3 code will warn at prehash time for missing exact nsec3 records. So faulty signed zones are more easily spotted. - fixed NSEC3 and CNAME/DNAME chains, it will disprove the new qname. - removed for() look in CNAME processing, only first CNAME is processed now. - zonec will error on a zone with multiple CNAMEs for one name. 16 June 2006: Wouter - Swapped read and write ops in xfrd_handle_ipc, so that a read of a signal from main can stop further writes. - xfrd will complete its last message before shutting down the ipc writes and then acknowledge the reload-sync. This resolves the race where half of ipc messages caused bad modes from the main. 15 June 2006: Wouter - In preparation of notify send overhaul, moved the notify send code to xfrd-notify.c and h files. - created cleaner split of notify send and xfr code. Still in the xfr process, because it is a convenient location. - fixed bug where notify sending would read from wrong fd. - send master zone notifies. Does not skips master zone SOA INFO updates. - fixed bug where port number acls did not match. - fixed bug where tsig keys are checked for twice, but not error_code. - fixed notify send retry counting. - added test tpkg for notifies from nsd master to nsd slave. - nsd-checkconf flags if you set allow-notify without request-xfr. 14 June 2006: Wouter - fixed crash bug when dnssec/NSEC enabled and query DNAME target did not exist. 13 June 2006: Wouter - created doc subdirectory for documentation. - removed unused DIFF FILE MAGIC string. 12 June 2006: Wouter - dname_test tpkg with very extensive DNAME testing. - moved sizes of zone_name buffers to 3072 - for escaped names. - nsd-patch has a debug option to list the contents of the difffile/ixfr.db/transfer patch log in a journal fashion. You can then manually inspect the contents. 9 June 2006: Wouter - after a reload NSD will report the memory churn: number of bytes of memory wasted by the zone transfer code. 8 June 2006: Wouter - When zone is re-chosen after a CNAME/DNAME no SERVFAIL is set, noerror is returned instead. - zonec will error on multiple DNAMEs for the same name. - zonec will error on DNAME and CNAME together. - improved loop log message. 7 June 2006: Wouter - after DNAME the closest_match is set correctly for another DNAME. - in case of a loop returns gracefully instead of crash. - nsec3 checks if it is enabled for the zone for wildcards. - NSD will give referrals for zone cuts encountered after a CNAME or a DNAME. This also fixed various subtle stuff with CNAME/DNAME and TYPE_DS at zone cuts. It basically re-determines the zone to use after the CNAME/DNAME. 6 June 2066: Wouter - zonec checks for data below a DNAME, and will not create the db, as per rfc 2672. Tpkg test to make sure such a zone is not loaded. - updated rr-test tpkg so it has no data below a DNAME. - DNAME synthesis of CNAME records, including compression for cname. - included cname creation in dname test. - preallocate the extra temporary domain_type structures. - too many temp domains returns OK packet so that the resolver will recurse and ask us again with the last name in the chain. - fixed bug introduced in preallocation on temp domain numbering. 2 June 2006: Wouter - dname_replace function that does DNAME replace and unit tests. - added error codes from DNSUPD rfc2136 to constants in dns.h. - in query.c added DNAME following code. - fixed bug 134: hints[i] in nsd.c to hints[0]. - added tpkg small test for DNAME. - tpkg to test bug 134 (starts 100 processes). 1 June 2006: Wouter - tsig test with NSD master and NSD slave server. Tsig AXFR transfer. nsd-xfer used to test slave zone contents. - fixed bug where buffer_flip() is done before appending tsig rr. - version printed at start of nsd in logfile. - xfrd prints name of tsig key used during transfer in commit comments so it appears in the log file and in zonefile after nsd-patch. - prints RRs from diff file only if debug level >= 1. - scalable transfer test xfr_gig added, you can set the size to try in the .pre file. Now set very small. 31 May 2006: Wouter - xfrd check for failed updates. It compares the time it wrote the commit to disk with the time of the last reload command. Failed updates are restarted like the zone is notified of the soa. It also catches reloads that have been lost (reload cmd while reload is running, or a crashed reload process, for example). - when reload is issued, times at that second are put back one second, so that after a reload all the zones that should have been loaded have a time from before the reload. - if a reload crashes, NSD will continue with the old database, xfrd is not informed, since it cannot fix that. - nsd-checkconf strdups arg strings before writing to it. - tsig error replies contain error data, but no signature. also crashproof, badly formatted tsigs get a format error. - tsig error print knows about DNS rcodes in tsig error field. - added tpkg tests for tsig. - tpkg test for nsd-xfer with TSIG from nsd. - small stuff with makedist.sh, CREDITS, Features, make test. 30 May 2006: Wouter - tsig pre-allocs the rr_region, not at runtime, tsig_create_record(). - redid some region work for tsig. Now has another temporary region for the context data. User is only aware of the region passed at start that exists for the lifetime of the struct. During TSIG checks no more mallocs are done, only region_free_all and region allocs (of small size). - checkconf, port is stored as a string. - tsig now keeps a max_digest_size for giving reserved space. - AXFR does tsig every 96 packets (and first and last packet). - tsig signing works for all queries. SOA queries, ... If you configured the key in the config file, you can use that key for any query for any zone. Except for NOTIFY and AXFR queries; those are only allowed for the zone (and source ip address) which are configured in the config. - cleaner compile with tsig disabled. - fixed unknown key error reply in tsig. 29 May 2006: Wouter - The nonblocking write routines disable silently if they have nothing to do. - put xfrd read/write state routines (almost 500 lines of code) into xfrd-disk.c file. - little readme blurb on xfrd state file for the operator. - put ipc code in its own file for ease of reading. - removed --disable-axfr, you can control this via acls. With no provide-xfr: statements, a zone will not do axfr. 25 May 2006: Wouter - fixed reload sending; it checks for EAGAIN and EINTR. - reload sends parent quit command blocking to make sure of arrival. - send_children_quit in parent uses nonblocking writes and closes the pipe to signal the child to quit (even if the write does not come through, the closed pipe will cause the child to quit). - need_to_send_STATS flag in parent. - reload has its own ipc-listening handler in server_main. - nonblocking writes for server_main; this solved write-blocking race. - another race condition solved, if a process dies, half a read or write buffer could be left behind on another process. These are dropped. Now: * The server_main drops ipc from dead children. * The server_main drops ipc if xfrd dies. * The server_main drops xfrd(old) and all children ipc on reload. * The xfrd drops ipc to parent on a SOA_BEGIN from reload. So after reload, but parent and xfrd start with clean ipc buffers. 24 May 2006: Wouter - unit tests print progress while running to stderr. Included license of cutest with its source in svn repository. - stack type (for the IPC buffer of zone update dirty). And unit test. - only update zone-is_ok if needed to reduce memory copy on write. - split off conn_write() from xfrd tcp nonblocking write routines. - nonblocking writes for xfrd. 22 May 2006: Wouter - ported over minor nits from 2.3.5 NSD fixups. Cast to (void) unused function return values. - removed kill signal to children, superfluous due to quit cmd ipc. - moved is_ok for zones to the zone_type in namedb, not in the options, it is a runtime value not a config value. For zones that have no data, parent and children keep no state. 12 May 2006: Wouter - fixed up usage print for zonec to include -f option. - xfrd send notifies. - server no longer sends SOA INFO for master zones. - removed possible debug log print of a null string. 11 May 2006: Wouter - nsd.conf.sample shows defaults for ip4-only, ip6-only and debug-mode. - SOA_BEGIN message on start of reload sending soa info so that xfrd will not reply with expire-notifications and thus deadlock both on blocking writes (and no OS buffer on the pipes). 10 May 2006: Wouter - nsdc.sh is set +x after creation. - improved error message when zone in db has no config info. - support for broken nsec3 chains (if the one with the SOA bit is complete, it is OK for there to be other nsec3 chains with different parameters in the zone). 9 May 2006: Wouter - Fix for finding bad zone when populating SOA info on start. it would find a parent zone instead of the zone in question ( which is empty). - request-xfr: AXFR 10.0.0.153 keytouse syntax to interoperate with NSD machines. Will only send AXFR queries to the machine. - documented AXFR option in nsd.conf.5 manual page, and updated nsd-checkconf, nsd.conf.sample. - made 'skipping zone' log entry clearer (Sam Weiler asked). 8 May 2006: Wouter - updated zparser.y to handle empty nsec_seq lists. for empty nonterminals in NSEC3. - nicer without ambiguous grammar. 5 May 2006: Wouter - nsd-notify handles option -y key:secret to TSIG sign outgoing queries. - the acl checks now verify TSIG signatures on the query. - iterated_hash compiles with ssl disabled. - new ipc NSD_ZONE_STATE sent by xfrd to nsd process. notifies nsd of the state (ok or expired) of a zone. - reload process waits for the old server_main to exit to make sure there is no race condition listening to the NSD_ZONE_STATE messages generated when reload sends SOA_INFO to xfrd. - server_main and children all set zone_ok state in config options. also server_main so that newly forked children get the right state. - if a secondary zone is expired, NSD returns SERVFAIL. a transient error, so resolvers try again later. - SOA_END ipc message, sent by reload to xfrd, so it can repeat all zone states (which can have changed during reload). - zone_is_ok kept in config section so that state for zones without data is not lost. Those have no zone_type*. - secondary zones start in the expired state. - if expired zones are updated, then NSD gets the go ahead from xfrd after reload sends SOAINFO/SOAEND msg, so it is really updated in nsd memory. - fixed tpkg xfr_1 to have longer expiry times (from 0 and 3 seconds to 2000 and 3000 seconds), so the zone does not expire during the test anymore. 4 May 2006: Wouter - when a new lease is acquired xfrd_packet_newlease result is used. - if a zone is lost in nsd db, xfrd will update state to match. - IXFR can use TSIG in queries and verify responses. - Fixed memory leak in xfrd tsig handling. 3 May 2006: Wouter - forward of 2.3.4 RELNOTES into trunk. - debug log statements to track xfrd request rounds. - removed memleak from handle_passed_packet in xfrd. - faster find_zone in difffile.c. - nsd-patch writes commit log entries into zone file. - took some tsig.c enhancements from 3 branch, -> if key or algo changes during connection, return bad_key, -> debug statement neater. - nsd adds tsig keys to tsig keyring at startup. 2 May 2006: Wouter - ifdef inet6 back on ss_family usage in server.c. - nsd-checkconf ip6 ifdefs improved. - xfrd tries servers 3 rounds, then waits for next retry. 1 May 2006: Wouter - off_t used for 64bit fileio. - searches for smallest unused part and sets diff_skip to that. - doc comment near the region_free_all for every query about malloc speed. - null ptr in strcmp does not work on bsd, fixed nsd-checkconf. - made nsd.conf.sample.in so the sample gets prefix-corrected. - removed nsd.zones.sample. - makedist.sh added manual pages for nsd-xfer nsd-patch. - install/uninstall nsd-patch, nsd-checkconf and manpage. small update readme. 28 Apr 2006: Wouter - ixfr >64k in xfrd. - fixed length of new commit parts. - fixed multiple ipc reads in xfrd. - fixed multiple packet ixfr read in diff file. Miek: - Forward port fixes for nsd-xfer and nsd-notify 27 Apr 2006: Wouter: - nsec3 review fixes. - diff file format expanded for >64kb transfer support. - diff reader adjusted for >64kb. Jelte: - small non-null options check in nsd.c. Miek: - updated nsd-checkconf for zone parse shell script support. 25 Apr 2006: Wouter - Tests on NSEC3 code. Fixed that the unsecure delegations also have _ds_ parent nsec3 prehashes, so that they get proper NSEC3s. NSD will serve NSEC3s to prove 'opt-out' also if the opt-out bit is (erroneously) not set. - For the 05pre2 draft section 5.4.8.1. QTYPE is NSEC3, only NSEC3 RRsets at name. Fixed that RRSIGs present do not matter. And also the closest encloser proof in that case fixed. If wildcard exists below zone apex servfails (cannot disprove it and NSD cannot instantiate the wildcard at that point). 24 Apr 2006: Miek Miek: - forward port nsid (disabled by default) Wouter: - nsd-patch manual page. - minor MacOSX port fixes. - xfrd-reload-timeout: config option. - if you set the xfrd reload timeout to -1 it will not automatically reload after a transfer. User can reload. - reload timeout is a wait period after the reload is triggered. - more verbose acl logging. Validated acls are logged in detail. Invalid acls are only logged in debug mode, level >= 1. - log message when xfrd tcp connections max out. - if unknown NSEC3 hash type (not SHA-1), disable NSEC3. - xfrd randomizes the timeouts, within 10% of original, to spread out activity. Short timeouts < 10 seconds are not affected, and will give activity bursts (on startup for example). 21 Apr 2006: Wouter - put NSEC3 code in nsec3.c and nsec3.h. - iterated_hash only adds the salt if salt_len > 0. - added some assertions and cleanups to nsec3 code. - prehash also calcs the nsec3_last domain*. - dbaccess when reading in will set the rr_type.owner value. - changed namedb_find_zone to domain_find_zone, log msgs. - implemented logic from nsec draft 05-pre2 section 5.4.1 - 5.4.8. NSEC3 responses only happen for nsd compiled with --enable-nsec3 and for zones where an NSEC3 with the SOA bit set exists. - added prehash pointer to ds parent side cover for opt out. - removed dynamic plugins. Dynamic plugin support is an explicit non-requirement (under creeping featurism). - in domain table create root nsec3 ptrs are NULL. 20 Apr 2006: Wouter - Unittest of base 32 encoding. - unittest start for iterated hash. - fixed for ctrlc in debug mode. - delete zparser_conv_long, not used, not needed - nsd-xfer will display NSEC3 correctly. zonec parses. - improved usage() line from zonec, about -c none, must be -C. - base32 printed in lowercase (canonical format for DNS). - NSEC3 added prehash pointers to the namedb. - NSEC3 autodetects presence of NSEC3 in zone and parameters. 19 Apr 2006: Wouter - port fix base10 in zonec conv short from 2_2 branch to trunk. and conv byte, algo, certificate, long. - configure option to enable NSEC3 (--enable-nsec3) support. - from Ben Laurie's NSEC3 patch, loaned the parse code, base32 conversion code and iterated_hash. With some small modifications. The type rrdescriptors are indexed by value below SPF, and in rdata_wireformat_to_rdata_atoms BINARYWITHLENGTH checks for end of buffer. Also parser checks for '-' salt. Some layout (spaces after ,s). And NSEC3 define is used. strtol used for iterations is base 10. - moved rrtype descriptor table sanity check to unittest. 18 Apr 2006: Wouter - Fixed check for SOA IN, bad ntohs in the check. - minimum timeout also enforced for very low expire times. - report the actual used length of the sockaddr to sento for FreeBSD. 7 Apr 2006: Wouter - modified the kill_nsd tpkg so that it waits up to 10x5 secs for nsd to make the pid file, and it wait up to 10x5 secs for nsd to exit after the kill signal is given. - xfrd checks on startup if there is trailing garbage in the diff file, left there by a previous xfrd killed in action. It then snips off any partial parts, so service can resume. Also the difffile_skip pos is set before any partial record there. - first version of nsd-patch; reads db and ixfrs and updates zones. - moved print_rdata from nsd-xfer to rdata.h to share code. - moved print_rr from nsd-xfer to util.h to share code. 6 Apr 2006: Wouter - notify handler passes acl number that matches to xfrd. - xfrd keeps a next_master for a zone, and sets it after notify. when notified nsd will try to contact the master that sent the notify, if send from an address that is both in acl allow-notify and request-xfr. - xfrd closes its tcp and udp sockets on exit. - default names for diff file and xfrd state nicer. - fixed up kill nsd grep on ps. - fixed up race conditions in test script for kill nsd wait for pid file creation by nsd, and grep -v grep in check. - in nsd signal-flags inherited from the parent are zeroed when a server_child starts. Also the server_child switches back to NSD_RUN mode when a bad mode happens. - check if ixfrs start from the version in memory. - if IXFR/AXFR ends in a serial that is newer than the serial that was sent in an notify, update the notified serial. 5 Apr 2006: Wouter - added lowerbound for retry timeout. - added extra assertions to xfrd-tcp.c, saying that the waiting line for tcp connections must be empty if the counter is below max. - setup so that the first master tried is the first in acl list. - diff file skips OPT and TSIG RRs if they are put into the answer section. - if IXFR contains an RR to delete that does not exist, nothing happens. - update zone for NS, RRSIG also if multiple RRs in the rrset. - difffile: create zone struct also if domain exists already. - difffile: destroy temp region on error. - difffile: in delete_RR, create temp region outside of the routine, so no alloc region, destroy region for every deleted RR. - difffile: for IXFR: do not delete final SOA RR. - difffile: unknown parts in file is an error. - difffile: EOF on last packet is ignored w/o giving an error. 4 Apr 2006: Wouter - Addes EACCES to the netio dispatch error bailout. - Removed EACCESS (probably due to log_msg), error on close xfrd pipe is small, main process closes its end, and hopes for the best). - review: return on error condition in xfrd_tcp_open fixed. - review: expired when time >= expire_time, so it will not wait for the retry after expire until it will detect the expiredness. - removed duplicate lines from xfrd_handle_zone_timeout. - review: copy of uint32_t using memcpy to avoid unaligned memory accesses. - review: fd=-1 removed from set_refresh_now; only does timer. - on a tcp timeout it will retry immediately (instead of waiting another retry timeout). This means if you set refresh_now, it will interrupt a tcp-timer for a fresh retry with the next master. - put null in buffer for xfrd read state. - log msg uses string that exists instead of overwritten buffer. - read entry sets refresh depending on current time, and makes sure not to check soa contents if none provided. added explanatory comments. - EACCES back in check. - server_main first checks for terminated children, then select(). So when select is interrupted, by kill or quitting children, it will first see if it has to quit itself, before restarting the children. - destroy tempregion xfrd read on error. - check for serial existence in xfrd_handle_incoming_soa. - handle_incoming_soa uses set_timer_refresh routine. and can handle expire times < refresh times. - log msg for udp socket() error. - review: xfrd_parse_soa_info email parse uses correct buffer spot. - added a lowerbound to refresh interval (=1 second now). - upon receipt of a IXFR, if the serial is older than the notified serial, the zone stays refreshing (but the ixfr is saved). 3 Apr 2006: Wouter - Added buffer length check to internal ipc. - split out packet_read_query_section from the process_query_section routine (and moved to packet.c/h). - xfrd reads passed packet via ipc. - ported over fix to 2_2 on missing rr types by removing the duplicate RRtype array, and using rrtype_to_string. - xfrd handles notifies. immediately starts updating. - xfrd state file format fix. - removed libwrap stuff - superseded by acls. use provide-xfr: statements for your zone in the config file. updated README for this. - updated tpkg tests for axfr to use provide-xfr: 127.0.0.1 NOKEY - review: move var create to start of function (xfrd_init()). 31 Mar 2006: Wouter - zone type has a pointer to zone options. - nsd options has an rbtree to find zone options in. - nsd checks acl for incoming notifies and replies error or confirmation. - nicer layout in options.c. - updated makefile dependencies. - fixed sz for SOA_INFO ipc, which was too small. - notify is sent to server_main, server_main sends it to xfrd. 30 Mar 2006: Wouter - include: documented in manual page. - MAXINCLUDES define in one place (config.h). - configure checks for strptime in include files. - use %d instead of %zd (sparc5 machine does not get zd). - use region_strdup in configlexer. - added a check for EINVAL in dispatch - will abort on the error instead of busy hang. 29 Mar 2006: Wouter - \r for config lexer. (similar changes to zonelexer). - forward port of fix to 2_2 branch: short int in var_arg is promoted to int, according to B. Laurie. The same logic for %o, %d %x would hold for %u I think. - in XFRD, soa prim_ns and email domain names are kept in a max size buffer. - split up dname_parse into parse from string to wireformat and parse from wireformat to memoryformat, so both can be called. - split up dname_make_from_packet into reading the wireformat from the packet and the dname_make, so both can be called. - xfrd reads all soa info from incoming xfr packets. - xfrd will ignore TC bit on tcp channels. - nsd sends xfrd all soa info, including ttl and dnames. - config file now has an include: filename directive. 28 Mar 2006: Miek - forward port fixes for zone compiler and \r. svn:1926-1927 - add DO bit MASK and remove the !! construct 17 Mar 2006: Wouter - according to axfr-clarify, added comments that we check more leniently on further responses on a TCP stream. 16 Mar 2006: Wouter - Fixed up SOA INFO Send routines. Send from server works. - niced up xfrd state file. - Fixed up so that after a reload it will continue in diff file where it left off. - made send of SOA info use write_socket, in case of short writes. - redesigned xfrd_tcp_read to use the same code for ipc read. - no free()s before xfrd exit. - xfrd handles incoming SOA INFO ipc packets. - removed debug, updated zones get SOA INFO sent. 15 Mar 2006: Wouter - Fixed up domain table insert, it was being used in routines that originate from nsd-xfer that do not set compression numbers correctly. - memleak fix in difffile in case of error. - difffile processing works so that NSD can read an axfr saved into the nsd.diff file. (xfrd already request and save it there). - split off xfrd tcp handling into xfrd-tcp.c. - cleaned up send_udp in xfrd, and read_state. - removed xfrd tcp_send_blocking. - xfrd sets state from ok to refresh to expired based on timeout. - xfrd sets reload timeout. - Added zone updated to keep track of zones that are changed after a reload. These zones get their information notified to xfrd. - removed unused zprintrr declaration from zonec.h - nsd sends soa information to xfrd. 14 Mar 2006: Wouter - TODO updated - worked on reload ixfr. It will add/delete RRs and zones. - xfrd receive parse of xfr messages improved. writes commit. - server compressed_dname_offsets table is increased if reload creates extra names. - difffile will create zone and apex if not there (i.e. the zone is configured but no data file provided). - bit more verbose in error message for bad diff file. - Typo fix in sample config file. 13 Mar 2006: Wouter - configure sets fseek (fgetpos/fsetpos) to use 64 bit interface with _FILE_OFFSET_BITS=64. - nsd will skip loading the .db if the DB checksum is the same. - Miek added trace test and nsd kill test. - Wouter worked on diff file c. 10 Mar 2006: Wouter - Cleanup of UDP/TCP code in XFRD. - xfrd now has tcp max connections and managing. tcp read/write. - response TC on UDP ixfr, starts TCP. - sends correct ixfr and axfr queries, a bind server answers. - made packet_skip_dname() public. - sets read/write event flags for tcp fd right. 9 Mar 2006: Wouter - Removed header from DIFF file format. CRC not that important there, you have to check the packets anyway. - cutest rbtree removed unused clean_rbtree and always_fail routines. - xfrd timeout handler, more work. Checks expire. 8 Mar 2006: Wouter - xfrd sends UDP xfr request to master(s) with timeouts, and stores returned data on disk. - updated dependencies and declaration of write_soa_buffer. 7 Mar 2006: Wouter - Fixed printfs for size_t warnings on Mac OsX. 6 Mar 2006: nsd-team * Wouter: xfrd read and write work. Statefile is "nsd.xfst". * Wouter: nsd-checkconf checks dname parse of zone name:. * Wouter: updated difffile in parser.y, production in server: clause. * Wouter: zonec now takes -C for 'no config file' option. * Wouter: updated configyyrename.h for bison 1.875d on sparc. * Miek: zonec -h and nsd -h exit with exit code = 0. * Miek & Wouter: updated tpkgs to work again. * Wouter: xfrd read handle soas, handle soa_incoming part. * Wouter: moved compare_serial() from nsd-xfer to util.h. 4 Mar 2006: Wouter - xfrd zone and soa memory structure definitions. - xfrd init zones. - xfrd read and write state file code. - option for difffile: and xfrdfile: config lines. 3 Mar 2006: Wouter - Removed double kill after reload. Only socket cmd send. - Added code to handle race condition where xfrd is restarted during a successful reload. Afterwards, the new server_main only has the old xfrd pid, new xfrd is an orphan. Solution: when xfrd closes cmd channel (i.e. it quit) unexpectedly, send sighup to all processes in the group. This should quit the orphan & all children & reload the server_main, which will fork the children and xfrd again. 2 Mar 2006: Wouter - Added nsd-checkconf.8 to makedist.sh replace list. - DIFF file format updated. - removed tsigkey->server value, it was read in, but unused. - new function to add config file keys to tsig. - nsd-checkconf checks parsing of keys. - Updated sample key file with valid keys. - added first xfrd files. xfrd is started from server_main. xfrd listens to server and server to xfrd. xfrd is restarted if it dies unexpectedly. xfrd quits when server signals it. xfrd survives nsd reloads. - nsd_options no longer global variable. 1 Mar 2006: Wouter - Nicer text in nsd.8. - nsd.c prettier code in option handling. - zonec.c code prettier in option handling, also chdir bug removed. zonec uses the zone definitions in the config file. updated zonec.8 and usage(). - nsd also chdirs to the zonedir, otherwise nsd and zonec would try to read the database: file from different directories. .(it does the chdir before the chroot call.) - new calling syntax for zonec and nsd, because of new config file. - options added acl acceptance tests (no tsig yet). - added unit test for options.c - for acl tests. - zonec removed unused vars, nsd-checkconf print arguments. - nsd-checkconf.8 manual page. 28 Feb 2006: Wouter - checked in options.h and config parser code. - also nsd-checkconf that will test a config file .(and optionally show what was read). - default identity has a spelling error. - Small fix (typo in example) to config manual page. - Added ; to configparser.y to please bison 1.75 on bsd. - Will check for blocked addresses in outgoing acls. Also ranges. - Check configuration tpkg test added. Uses checkconf. - checkconf does extra semantic tests. i.e. enable absent features. - tcpcount and servercount cannot be negative. - updated nsd.conf.5 manpage for @port syntax. - changed config parser: allows empty server: part (defaults). - made nsd.conf.sample file. - put option to configure for CONFIG_FILE nsd.conf location. Note. Already nsdc.conf exists. Both exist now. - updated makefile dependencies (gcc -MM). - getopt optstring in nsd-checkconf updated ("v" only option). - Added config .o files to nsd and zonec. This compiles. - Added commandline option -c configfile to zonec and nsd. configure defaults < configfile < commandline options in importance. 24 Feb 2006: Wouter - Added compute_crc in util.h and unit tests for it. - in cutest.tpkg the number of unit tests was hardcoded in the tpkg package. Removed the dependency, cutest exit value indicates if any failures happened. - Added crc at end of NSD-database format. Unique per db. upped db version to 7 because of this. - Tested that crcs are big/little endian correct. - Added DIFF file spec - updated tpkg213 which compares md5 on a zonefile for new format. - added nsd.conf.5 manual page with a draft contents. 22 Feb 2006: nsd-team * Miek: Changed over to Cutest testing framework. * Miek: fixed typo in netio.h * Miek: fix syntax in rbtree.c put functions on multiple lines. * Miek: unit test tpkg for cutest. * Wouter: fixed ptr bug in rbtree unit test. 17 Feb 2006: Wouter - rbtree_delete is added and works. Unit tests are there too. - Changed tail recursion in rbtree_delete to while loop. - Tagged this version as NSD_3_signalsocket_solution. It is the stable 2_2 branch with cleanups, portable, and signalhandler solution by socket communication redesign. 15 Feb 2006: nsd-team * Wouter: Fixed server_child would wait for two kill signals before quit. * Miek: don't check for port==0 pkt, just try to send them. Forward Port of 2.3. * Wouter: Removed unused, not substituted, @nsdxfer@ from Makefile.in. 14 Feb 2006: Wouter - Added unit tests for rbtree. Extensive testing of all functions. - Added tpkg unit test. - configure tests for CUnit(optional lib for unit tests). Makefile cleanup so it works on non-gmake on freebsd. 13 Feb 2006: Wouter - Removed timespec_add(current_time) in server_main, the timeout was relative, not absolute. This fixes EINVAL on the timeout on freebsd. - Added check in configure for compiler flags. Used for -Wextra. - Added check in configure for va_list definition conflict between stdio and stdarg. This happens on DEC Alpha/Debian. - removed --enable-mmap configure option. There is no mmap support in the current codebase. - renamed local prev to next in domain_next() in namedb.h. - Removed heap.h. It was not used. Heap and rbtree are mingled anyway. - in netio.c, in dispatch, it would store the next pointer 'in case the handler removes itself'. But if the handler removes that next. Then it would fail. So stored the next in struct netio. This removes a potential bug. Netio_dispatch is not reentrant. Reentry would need a list of iterator* in struct netio. - Changed process_query() to server_process_query(). It is too similar to query_process(). 10 Feb 2006: nsd-team * Wouter: Improved configure.ac to detect pselect in sys/select. The check works on freebsd(yes) and fedoracore 3 and 4 (no). I hope it also works on Solaris. Also various other prototypes were implicit: chroot, strptime, ... These are also solved. * Wouter: Checked configure on sparc5(solaris). Added check for ctime_r in time.h (for tsig.c). This conf also works on freebsd/linux. * Wouter: Updated dependencies in makefile for plugin headers. These are included only when --enable-plugins is present. * Wouter: Added a send quit over socket to kill commands in server_main, These act when the fork children fails. If the kill fails, the socket command hopefully still works. * Wouter: Put reload code into a separate function. It communicates with a socket to the old parent, and sends it a quit command. This works and terminates the old nsd. Left in the kill as a double failsafe. If the reload process dies, then the parent closes the socket. * Wouter: Separated the signal mode from the socket-determined nsd->mode. Every signal function has a variable, so that multiple signals can arrive. Only the number of signals of the same type is lost, but not important for nsd. The signals are handled in turn by the run loop. This completes the coding to remove signal race conditions: - nsd uses sockets to communicate with its subprocesses(server,reload). - signal handler routine contains no lengthy system calls. - signals cannot overwrite a previous signal. * Wouter: fixed problem where nsd->mode and mode are different in server_main. Nsd would kill the children, but then restart them again. 09 Feb 2006: nsd-team * Wouter: Updated dependencies in Makefile (regenerated them with gcc -MM). * Wouter: Used splint on the source (with settings to reduce spam.) And came to the following changes: - In util.h, make it respect HAVE_CONFIG_H and HAVE_SYSLOG_H. Also it now defines fallback values for #defines in syslog h. - Added explicit cast to (unsigned int) in snprintf in dname.c, dname_to_string routine. * Wouter: Used extra warnings during gcc compile. -Wextra -Wall -pedantic -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement. Using -Wtraditional gives too many warnings. * Wouter: Found a problem with pselect. sys/select.h does not by default provide the pselect function definition. configure script is adjusted to test for this and enable _XOPEN_SOURCE=600 to get it. Found this using the gcc warnings. * Wouter: dname and rbtree test apps were in make clean target, but do not exist anymore. Removed from make clean target. * Wouter: in util log_file() the epoch time_t is passed to printf without an int cast. Found using extra gcc warnings. * Wouter: In server.c fixed some signed-unsigned comparisons using the extra gcc warnings. - in shutdown and int was used instead of size_t. - in server_main timeout(signed) was compared with unsigned. - unused variable in new handler functions. - in handle_child_command int i instead of size_t was used. - in zonec the process_rr routine was missing (void) as paramlist. * Wouter: Added -Wall and -Wextra when --enable-checking is enabled. * Miek: Ported over the big fat enable checking configure warning. * Wouter: fixed configure check for pselect on freebsd. 08 Feb 2006: nsd-team * Wouter: In server.c also sockets from unexpectedly dead childs are closed. * Wouter: in nsd.c and server.c cleaned out the signal handler, so that it only includes two switch/if statements and alters only the mode. No more calls to alarm(), waitpid(), write(), log_msg(). Instead the work is done in the runloop in server.c and sent by socket. Also the parent now waits for children. Parent restarts them. * Wouter: Fixup, the children will quit if the parent closes the command socket. If parent is killed, they will exit too. * Wouter: The server_main now listens to children command channels. Included timeout to check for terminated processes. Test says that new signal handler works, and child->parent comm. 07 Feb 2006: nsd-team * Miek: configure.ac version to 3.0.0 * Miek: looked at: buffer.{ch}, answer.{ch}, dns.{ch} those files don't have any changes, except for dns.{ch} for the explicit compression. * Miek: looked at: zlexer.lex and zparser.y; only changes there for the database changes. * Wouter: Changed buffer in write_pid from 16 bytes to 32 bytes, this makes 64 bit numbers fit in the buffer. * Wouter: Socket connection between parent and child nsds added. But sighandler now in worse shape. Need to close them. Remove kills. * Wouter: close the parent and child command channel sockets in shutdown(). nsd-4.12.0/doc/CREDITS0000644000175000017500000000460315002373054013565 0ustar mozziemozzieThe NSD was primarily developed by NLnet Labs on request from and close cooperation with RIPE NCC, as an alternative name server software to be run on the root name server RIPE NCC operates. Below is the NSD team in alphabetical order: Alexis Yushin, NLnet Labs - design and implementation for NSD 1.0.x and 1.1.x. Erik Rozendaal, NLnet Labs - design and implementation for NSD 1.2.x and later. Daniel Karrenberg, RIPE NCC - design, major testing and bug reports Jaap Akkerhuis, SIDN NL - consultancy, advice and company :) Jelte Jansen, NLnet Labs - testing, patches, advice, NSD 3 Matthijs Mekking, NLnet Labs - testing, patches, maintenance, NSD 3 Miek Gieben, NLnet Labs - testing, patches, zone compiler, NSD 2 Olaf Kolkman, RIPE NCC - protocol purist, design, perl test implementation Ronald van der Pol, NLnet Labs - code review, MacOS X portability, IPv6. Ted Lindgreen, NLnet Labs - design, code review, testing Wouter Wijngaards, NLnet Labs - design and implementation for NSD 3 and NSD 4. Contributors (in alphabetical order): Aaron Glenn - DragonflyBSD, BSD/sparc64 testing. Ben Laurie - NSEC3 patch. Bin Zhang - NSD 3 prerelease testing. Colm MacCárthaigh, - IPv6 binding and cleanups. Greg Bock - confine-to-zone feature. Farkas Levente - rpm specfile improvements. Jakob Schlyter, Kirei - chroot and several other patches Jun-ichiro itojun Hagino, IIJLab - IPv6 transport Kai - NSD 3 prerelease testing. Mans Nilsson - (Solaris) Testing Markus Heimhilcher - .AT zones for testing Martin Svec - Optimalization patches. Matthew Smith - NetBSD testing. Ondrej Sury - nsd-notify.8 man page Paul Wouters - zone compiler testing Peter Hessler - OpenBSD, amd64 testing. Stephane Bortzmeyer - Tru64 portability. Config conversion. nsd-4.12.0/dnstap/0000755000175000017500000000000015002373054013266 5ustar mozziemozziensd-4.12.0/dnstap/dnstap_config.h.in0000644000175000017500000000060215002373054016660 0ustar mozziemozzie#ifndef UNBOUND_DNSTAP_CONFIG_H #define UNBOUND_DNSTAP_CONFIG_H /* * Process this file (dnstap_config.h.in) with AC_CONFIG_FILES to generate * dnstap_config.h. * * This file exists so that USE_DNSTAP can be used without including config.h. */ #if @ENABLE_DNSTAP@ /* ENABLE_DNSTAP */ # ifndef USE_DNSTAP # define USE_DNSTAP 1 # endif #endif #endif /* UNBOUND_DNSTAP_CONFIG_H */ nsd-4.12.0/dnstap/dnstap_collector.h0000644000175000017500000000614115002373054017000 0ustar mozziemozzie/* * dnstap/dnstap_collector.h -- nsd collector process for dnstap information * * Copyright (c) 2018, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DNSTAP_COLLECTOR_H #define DNSTAP_COLLECTOR_H struct dt_env; struct nsd; struct event_base; struct event; struct dt_collector_input; struct zone; struct buffer; struct region; /* information for the dnstap collector process. It collects information * for dnstap from the worker processes. And writes them to the dnstap * socket. */ struct dt_collector { /* dnstap env for the write to the dnstap socket */ struct dt_env* dt_env; /* number of workers to collect from */ int count; /* socketpair for communication between (xfrd) and the * dnstap collector process. If closed, the collector process * exits. The collector closes the other side of the socketpair, so * that if xfrd exits, so does the dnstap collector */ int cmd_socket_dt, cmd_socket_nsd; /* the pid of the dt collector process (0 on that process) */ pid_t dt_pid; /* in the collector process, the event base */ struct event_base* event_base; /* in the collector process, the cmd handle event */ struct event* cmd_event; /* in the collector process, array size count of input per worker */ struct dt_collector_input* inputs; /* region for buffers */ struct region* region; /* buffer for sending data to the collector */ struct buffer* send_buffer; }; /* information per worker to get input from that worker. */ struct dt_collector_input { /* the collector this is part of (for use in callbacks) */ struct dt_collector* dt_collector; /* the event to listen to the datagrams to process for that worker*/ struct event* event; /* buffer to store the datagrams while they are read in */ struct buffer* buffer; }; /* create dt_collector process structure and dt_env */ struct dt_collector* dt_collector_create(struct nsd* nsd); /* destroy the dt_collector structure */ void dt_collector_destroy(struct dt_collector* dt_col, struct nsd* nsd); /* close file descriptors */ void dt_collector_close(struct dt_collector* dt_col, struct nsd* nsd); /* start the collector process */ void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd); /* submit auth query from worker. It attempts to send it to the collector, * if the nonblocking fails, then it silently skips it. So it does not block * on the log. */ void dt_collector_submit_auth_query(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet); /* submit auth response from worker. It attempts to send it to the collector, * if the nonblocking fails, then it silently skips it. So it does not block * on the log. */ void dt_collector_submit_auth_response(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone); #endif /* DNSTAP_COLLECTOR_H */ nsd-4.12.0/dnstap/dnstap_collector.c0000644000175000017500000004361415002373054017001 0ustar mozziemozzie/* * dnstap/dnstap_collector.c -- nsd collector process for dnstap information * * Copyright (c) 2018, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "dnstap/dnstap_collector.h" #include "dnstap/dnstap.h" #include "util.h" #include "nsd.h" #include "region-allocator.h" #include "buffer.h" #include "namedb.h" #include "options.h" #include "remote.h" #include "udb.h" #include "rrl.h" struct dt_collector* dt_collector_create(struct nsd* nsd) { int i, sv[2]; struct dt_collector* dt_col = (struct dt_collector*)xalloc_zero( sizeof(*dt_col)); dt_col->count = nsd->child_count * 2; dt_col->dt_env = NULL; dt_col->region = region_create(xalloc, free); dt_col->send_buffer = buffer_create(dt_col->region, /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + local_addr + addr */ 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 + #ifdef INET6 sizeof(struct sockaddr_storage) + sizeof(struct sockaddr_storage) #else sizeof(struct sockaddr_in) + sizeof(struct sockaddr_in) #endif ); /* open communication channels in struct nsd */ nsd->dt_collector_fd_send = (int*)xalloc_array_zero(dt_col->count, sizeof(int)); nsd->dt_collector_fd_recv = (int*)xalloc_array_zero(dt_col->count, sizeof(int)); for(i=0; icount; i++) { int sv[2]; int bufsz = buffer_capacity(dt_col->send_buffer); sv[0] = -1; /* For receiving by parent (dnstap-collector) */ sv[1] = -1; /* For sending by child (server childs) */ if(socketpair(AF_UNIX, SOCK_DGRAM #ifdef SOCK_NONBLOCK | SOCK_NONBLOCK #endif , 0, sv) < 0) { error("dnstap_collector: cannot create communication channel: %s", strerror(errno)); } #ifndef SOCK_NONBLOCK if (fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "dnstap_collector receive fd fcntl " "failed: %s", strerror(errno)); } if (fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "dnstap_collector send fd fcntl " "failed: %s", strerror(errno)); } #endif if(setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz))) { log_msg(LOG_ERR, "setting dnstap_collector " "receive buffer size failed: %s", strerror(errno)); } if(setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz))) { log_msg(LOG_ERR, "setting dnstap_collector " "send buffer size failed: %s", strerror(errno)); } nsd->dt_collector_fd_recv[i] = sv[0]; nsd->dt_collector_fd_send[i] = sv[1]; } nsd->dt_collector_fd_swap = nsd->dt_collector_fd_send + nsd->child_count; /* open socketpair */ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { error("dnstap_collector: cannot create socketpair: %s", strerror(errno)); } if(fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } if(fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } dt_col->cmd_socket_dt = sv[0]; dt_col->cmd_socket_nsd = sv[1]; return dt_col; } void dt_collector_destroy(struct dt_collector* dt_col, struct nsd* nsd) { if(!dt_col) return; free(nsd->dt_collector_fd_recv); nsd->dt_collector_fd_recv = NULL; if (nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap) free(nsd->dt_collector_fd_send); else free(nsd->dt_collector_fd_swap); nsd->dt_collector_fd_send = NULL; nsd->dt_collector_fd_swap = NULL; region_destroy(dt_col->region); free(dt_col); } void dt_collector_close(struct dt_collector* dt_col, struct nsd* nsd) { int i, *fd_send; if(!dt_col) return; if(dt_col->cmd_socket_dt != -1) { close(dt_col->cmd_socket_dt); dt_col->cmd_socket_dt = -1; } if(dt_col->cmd_socket_nsd != -1) { close(dt_col->cmd_socket_nsd); dt_col->cmd_socket_nsd = -1; } fd_send = nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap ? nsd->dt_collector_fd_send : nsd->dt_collector_fd_swap; for(i=0; icount; i++) { if(nsd->dt_collector_fd_recv[i] != -1) { close(nsd->dt_collector_fd_recv[i]); nsd->dt_collector_fd_recv[i] = -1; } if(fd_send[i] != -1) { close(fd_send[i]); fd_send[i] = -1; } } } /* handle command from nsd to dt collector. * mostly, check for fd closed, this means we have to exit */ void dt_handle_cmd_from_nsd(int ATTR_UNUSED(fd), short event, void* arg) { struct dt_collector* dt_col = (struct dt_collector*)arg; if((event&EV_READ) != 0) { event_base_loopexit(dt_col->event_base, NULL); } } /* receive data from fd into buffer, 1 when message received, -1 on error */ static int recv_into_buffer(int fd, struct buffer* buf) { size_t msglen; ssize_t r; assert(buffer_position(buf) == 0); r = recv(fd, buffer_current(buf), buffer_capacity(buf), MSG_DONTWAIT); if(r == -1) { if(errno == EAGAIN || errno == EINTR || errno == EMSGSIZE) { /* continue to receive a message later */ return 0; } log_msg(LOG_ERR, "dnstap collector: receive failed: %s", strerror(errno)); return -1; } if(r == 0) { /* Remote end closed the connection? */ log_msg(LOG_ERR, "dnstap collector: remote closed connection"); return -1; } assert(r > 4); msglen = buffer_read_u32_at(buf, 0); if(msglen != (size_t)(r - 4)) { /* Is this still possible now the communication channel is of * type SOCK_DGRAM? I think not, but better safe than sorry. */ log_msg(LOG_ERR, "dnstap collector: out of sync (msglen: %u)", (unsigned int) msglen); return 0; } buffer_skip(buf, r); buffer_flip(buf); return 1; } /* submit the content of the buffer received to dnstap */ static void dt_submit_content(struct dt_env* dt_env, struct buffer* buf) { uint8_t is_response, is_tcp; #ifdef INET6 struct sockaddr_storage local_addr, addr; #else struct sockaddr_in local_addr, addr; #endif socklen_t addrlen; size_t pktlen; uint8_t* data; size_t zonelen; uint8_t* zone; /* parse content from buffer */ if(!buffer_available(buf, 4+1+4)) return; buffer_skip(buf, 4); /* skip msglen */ is_response = buffer_read_u8(buf); addrlen = buffer_read_u32(buf); if(addrlen > sizeof(local_addr) || addrlen > sizeof(addr)) return; if(!buffer_available(buf, 2*addrlen)) return; buffer_read(buf, &local_addr, addrlen); buffer_read(buf, &addr, addrlen); if(!buffer_available(buf, 1+4)) return; is_tcp = buffer_read_u8(buf); pktlen = buffer_read_u32(buf); if(!buffer_available(buf, pktlen)) return; data = buffer_current(buf); buffer_skip(buf, pktlen); if(!buffer_available(buf, 4)) return; zonelen = buffer_read_u32(buf); if(zonelen == 0) { zone = NULL; } else { if(zonelen > MAXDOMAINLEN) return; if(!buffer_available(buf, zonelen)) return; zone = buffer_current(buf); buffer_skip(buf, zonelen); } /* submit it */ if(is_response) { dt_msg_send_auth_response(dt_env, &local_addr, &addr, is_tcp, zone, zonelen, data, pktlen); } else { dt_msg_send_auth_query(dt_env, &local_addr, &addr, is_tcp, zone, zonelen, data, pktlen); } } /* handle input from worker for dnstap */ void dt_handle_input(int fd, short event, void* arg) { struct dt_collector_input* dt_input = (struct dt_collector_input*)arg; if((event&EV_READ) != 0) { /* receive */ int r = recv_into_buffer(fd, dt_input->buffer); if(r == 0) return; else if(r < 0) { event_base_loopexit(dt_input->dt_collector->event_base, NULL); return; } /* once data is complete, send it to dnstap */ VERBOSITY(4, (LOG_INFO, "dnstap collector: received msg len %d", (int)buffer_remaining(dt_input->buffer))); if(dt_input->dt_collector->dt_env) { dt_submit_content(dt_input->dt_collector->dt_env, dt_input->buffer); } /* clear buffer for next message */ buffer_clear(dt_input->buffer); } } /* init dnstap */ static void dt_init_dnstap(struct dt_collector* dt_col, struct nsd* nsd) { int num_workers = 1; #ifdef HAVE_CHROOT if(nsd->chrootdir && nsd->chrootdir[0]) { int l = strlen(nsd->chrootdir)-1; /* ends in trailing slash */ if (nsd->options->dnstap_socket_path && nsd->options->dnstap_socket_path[0] == '/' && strncmp(nsd->options->dnstap_socket_path, nsd->chrootdir, l) == 0) nsd->options->dnstap_socket_path += l; } #endif dt_col->dt_env = dt_create(nsd->options->dnstap_socket_path, nsd->options->dnstap_ip, num_workers, nsd->options->dnstap_tls, nsd->options->dnstap_tls_server_name, nsd->options->dnstap_tls_cert_bundle, nsd->options->dnstap_tls_client_key_file, nsd->options->dnstap_tls_client_cert_file); if(!dt_col->dt_env) { log_msg(LOG_ERR, "could not create dnstap env"); return; } dt_apply_cfg(dt_col->dt_env, nsd->options); dt_init(dt_col->dt_env); } /* cleanup dt collector process for exit */ static void dt_collector_cleanup(struct dt_collector* dt_col, struct nsd* nsd) { int i; dt_delete(dt_col->dt_env); event_del(dt_col->cmd_event); for(i=0; icount; i++) { event_del(dt_col->inputs[i].event); } dt_collector_close(dt_col, nsd); event_base_free(dt_col->event_base); #ifdef MEMCLEAN free(dt_col->cmd_event); if(dt_col->inputs) { for(i=0; icount; i++) { free(dt_col->inputs[i].event); } free(dt_col->inputs); } dt_collector_destroy(dt_col, nsd); daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */ nsd_options_destroy(nsd->options); region_destroy(nsd->region); #endif } /* attach events to the event base to listen to the workers and cmd channel */ static void dt_attach_events(struct dt_collector* dt_col, struct nsd* nsd) { int i; /* create event base */ dt_col->event_base = nsd_child_event_base(); if(!dt_col->event_base) { error("dnstap collector: event_base create failed"); } /* add command handler */ dt_col->cmd_event = (struct event*)xalloc_zero( sizeof(*dt_col->cmd_event)); event_set(dt_col->cmd_event, dt_col->cmd_socket_dt, EV_PERSIST|EV_READ, dt_handle_cmd_from_nsd, dt_col); if(event_base_set(dt_col->event_base, dt_col->cmd_event) != 0) log_msg(LOG_ERR, "dnstap collector: event_base_set failed"); if(event_add(dt_col->cmd_event, NULL) != 0) log_msg(LOG_ERR, "dnstap collector: event_add failed"); /* add worker input handlers */ dt_col->inputs = xalloc_array_zero(dt_col->count, sizeof(*dt_col->inputs)); for(i=0; icount; i++) { dt_col->inputs[i].dt_collector = dt_col; dt_col->inputs[i].event = (struct event*)xalloc_zero( sizeof(struct event)); event_set(dt_col->inputs[i].event, nsd->dt_collector_fd_recv[i], EV_PERSIST|EV_READ, dt_handle_input, &dt_col->inputs[i]); if(event_base_set(dt_col->event_base, dt_col->inputs[i].event) != 0) log_msg(LOG_ERR, "dnstap collector: event_base_set failed"); if(event_add(dt_col->inputs[i].event, NULL) != 0) log_msg(LOG_ERR, "dnstap collector: event_add failed"); dt_col->inputs[i].buffer = buffer_create(dt_col->region, /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + local_addr + addr */ 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 + #ifdef INET6 sizeof(struct sockaddr_storage) + sizeof(struct sockaddr_storage) #else sizeof(struct sockaddr_in) + sizeof(struct sockaddr_in) #endif ); assert(buffer_capacity(dt_col->inputs[i].buffer) == buffer_capacity(dt_col->send_buffer)); } } /* the dnstap collector process main routine */ static void dt_collector_run(struct dt_collector* dt_col, struct nsd* nsd) { /* init dnstap */ VERBOSITY(1, (LOG_INFO, "dnstap collector started")); dt_init_dnstap(dt_col, nsd); dt_attach_events(dt_col, nsd); /* run */ if(event_base_loop(dt_col->event_base, 0) == -1) { error("dnstap collector: event_base_loop failed"); } /* cleanup and done */ VERBOSITY(1, (LOG_INFO, "dnstap collector stopped")); dt_collector_cleanup(dt_col, nsd); exit(0); } void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd) { int i, *fd_send; /* fork */ dt_col->dt_pid = fork(); if(dt_col->dt_pid == -1) { error("dnstap_collector: fork failed: %s", strerror(errno)); } if(dt_col->dt_pid == 0) { /* the dt collector process is this */ /* close the nsd side of the command channel */ close(dt_col->cmd_socket_nsd); dt_col->cmd_socket_nsd = -1; /* close the send side of the communication channels */ assert(nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap); fd_send = nsd->dt_collector_fd_send < nsd->dt_collector_fd_swap ? nsd->dt_collector_fd_send : nsd->dt_collector_fd_swap; for(i=0; icount; i++) { if(fd_send[i] != -1) { close(fd_send[i]); fd_send[i] = -1; } } #ifdef HAVE_SETPROCTITLE setproctitle("dnstap_collector"); #endif #ifdef USE_LOG_PROCESS_ROLE log_set_process_role("dnstap_collector"); #endif /* Free serve process specific memory pages */ #ifdef RATELIMIT rrl_mmap_deinit_keep_mmap(); #endif udb_base_free_keep_mmap(nsd->task[0]); udb_base_free_keep_mmap(nsd->task[1]); namedb_close(nsd->db); dt_collector_run(dt_col, nsd); /* NOTREACH */ exit(0); } else { /* the parent continues on, with starting NSD */ /* close the dt side of the command channel */ close(dt_col->cmd_socket_dt); dt_col->cmd_socket_dt = -1; /* close the receive side of the communication channels */ for(i=0; icount; i++) { if(nsd->dt_collector_fd_recv[i] != -1) { close(nsd->dt_collector_fd_recv[i]); nsd->dt_collector_fd_recv[i] = -1; } } } } /* put data for sending to the collector process into the buffer */ static int prep_send_data(struct buffer* buf, uint8_t is_response, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone) { buffer_clear(buf); #ifdef INET6 if(local_addr->ss_family != addr->ss_family) return 0; /* must be same length to send */ #else if(local_addr->sin_family != addr->sin_family) return 0; /* must be same length to send */ #endif if(!buffer_available(buf, 4+1+4+2*addrlen+1+4+buffer_remaining(packet))) return 0; /* does not fit in send_buffer, log is dropped */ buffer_skip(buf, 4); /* the length of the message goes here */ buffer_write_u8(buf, is_response); buffer_write_u32(buf, addrlen); buffer_write(buf, local_addr, (size_t)addrlen); buffer_write(buf, addr, (size_t)addrlen); buffer_write_u8(buf, (is_tcp?1:0)); buffer_write_u32(buf, buffer_remaining(packet)); buffer_write(buf, buffer_begin(packet), buffer_remaining(packet)); if(zone && zone->apex && domain_dname(zone->apex)) { if(!buffer_available(buf, 4 + domain_dname(zone->apex)->name_size)) return 0; buffer_write_u32(buf, domain_dname(zone->apex)->name_size); buffer_write(buf, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size); } else { if(!buffer_available(buf, 4)) return 0; buffer_write_u32(buf, 0); } buffer_flip(buf); /* write length of message */ buffer_write_u32_at(buf, 0, buffer_remaining(buf)-4); return 1; } /* attempt to send buffer to socket, if it blocks do not send it. * return 0 on success, -1 on error */ static int attempt_to_send(int s, uint8_t* data, size_t len) { ssize_t r; if(len == 0) return 0; r = send(s, data, len, MSG_DONTWAIT | MSG_NOSIGNAL); if(r == -1) { if(errno == EAGAIN || errno == EINTR || errno == ENOBUFS || errno == EMSGSIZE) { /* check if pipe is full, if the nonblocking fd blocks, * then drop the message */ return 0; } /* some sort of error, print it */ log_msg(LOG_ERR, "dnstap collector: send failed: %s", strerror(errno)); return -1; } assert(r > 0); if(r > 0) { assert((size_t)r == len); return 0; } /* Other end closed the channel? */ log_msg(LOG_ERR, "dnstap collector: server child closed the channel"); return -1; } void dt_collector_submit_auth_query(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet) { if(!nsd->dt_collector) return; if(!nsd->options->dnstap_log_auth_query_messages) return; if(nsd->dt_collector_fd_send[nsd->this_child->child_num] == -1) return; VERBOSITY(4, (LOG_INFO, "dnstap submit auth query")); /* marshal data into send buffer */ if(!prep_send_data(nsd->dt_collector->send_buffer, 0, local_addr, addr, addrlen, is_tcp, packet, NULL)) return; /* probably did not fit in buffer */ /* attempt to send data; do not block */ if(attempt_to_send(nsd->dt_collector_fd_send[nsd->this_child->child_num], buffer_begin(nsd->dt_collector->send_buffer), buffer_remaining(nsd->dt_collector->send_buffer))) { /* Something went wrong sending to the socket. Don't send to * this socket again. */ close(nsd->dt_collector_fd_send[nsd->this_child->child_num]); nsd->dt_collector_fd_send[nsd->this_child->child_num] = -1; } } void dt_collector_submit_auth_response(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone) { if(!nsd->dt_collector) return; if(!nsd->options->dnstap_log_auth_response_messages) return; if(nsd->dt_collector_fd_send[nsd->this_child->child_num] == -1) return; VERBOSITY(4, (LOG_INFO, "dnstap submit auth response")); /* marshal data into send buffer */ if(!prep_send_data(nsd->dt_collector->send_buffer, 1, local_addr, addr, addrlen, is_tcp, packet, zone)) return; /* probably did not fit in buffer */ /* attempt to send data; do not block */ if(attempt_to_send(nsd->dt_collector_fd_send[nsd->this_child->child_num], buffer_begin(nsd->dt_collector->send_buffer), buffer_remaining(nsd->dt_collector->send_buffer))) { /* Something went wrong sending to the socket. Don't send to * this socket again. */ close(nsd->dt_collector_fd_send[nsd->this_child->child_num]); nsd->dt_collector_fd_send[nsd->this_child->child_num] = -1; } } nsd-4.12.0/dnstap/dnstap.proto0000644000175000017500000002455615002373054015660 0ustar mozziemozzie// dnstap: flexible, structured event replication format for DNS software // // This file contains the protobuf schemas for the "dnstap" structured event // replication format for DNS software. // Written in 2013-2014 by Farsight Security, Inc. // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this file to the public // domain worldwide. This file is distributed without any warranty. // // You should have received a copy of the CC0 Public Domain Dedication along // with this file. If not, see: // // . syntax = "proto2"; package dnstap; // "Dnstap": this is the top-level dnstap type, which is a "union" type that // contains other kinds of dnstap payloads, although currently only one type // of dnstap payload is defined. // See: https://developers.google.com/protocol-buffers/docs/techniques#union message Dnstap { // DNS server identity. // If enabled, this is the identity string of the DNS server which generated // this message. Typically this would be the same string as returned by an // "NSID" (RFC 5001) query. optional bytes identity = 1; // DNS server version. // If enabled, this is the version string of the DNS server which generated // this message. Typically this would be the same string as returned by a // "version.bind" query. optional bytes version = 2; // Extra data for this payload. // This field can be used for adding an arbitrary byte-string annotation to // the payload. No encoding or interpretation is applied or enforced. optional bytes extra = 3; // Identifies which field below is filled in. enum Type { MESSAGE = 1; } required Type type = 15; // One of the following will be filled in. optional Message message = 14; } // SocketFamily: the network protocol family of a socket. This specifies how // to interpret "network address" fields. enum SocketFamily { INET = 1; // IPv4 (RFC 791) INET6 = 2; // IPv6 (RFC 2460) } // SocketProtocol: the transport protocol of a socket. This specifies how to // interpret "transport port" fields. enum SocketProtocol { UDP = 1; // User Datagram Protocol (RFC 768) TCP = 2; // Transmission Control Protocol (RFC 793) } // Message: a wire-format (RFC 1035 section 4) DNS message and associated // metadata. Applications generating "Message" payloads should follow // certain requirements based on the MessageType, see below. message Message { // There are eight types of "Message" defined that correspond to the // four arrows in the following diagram, slightly modified from RFC 1035 // section 2: // +---------+ +----------+ +--------+ // | | query | | query | | // | Stub |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth. | // | Resolver| | Server | | Name | // | |<-SR--------CR-| |<-RR----AR-| Server | // +---------+ response | | response | | // +----------+ +--------+ // Each arrow has two Type values each, one for each "end" of each arrow, // because these are considered to be distinct events. Each end of each // arrow on the diagram above has been marked with a two-letter Type // mnemonic. Clockwise from upper left, these mnemonic values are: // // SQ: STUB_QUERY // CQ: CLIENT_QUERY // RQ: RESOLVER_QUERY // AQ: AUTH_QUERY // AR: AUTH_RESPONSE // RR: RESOLVER_RESPONSE // CR: CLIENT_RESPONSE // SR: STUB_RESPONSE // Two additional types of "Message" have been defined for the // "forwarding" case where an upstream DNS server is responsible for // further recursion. These are not shown on the diagram above, but have // the following mnemonic values: // FQ: FORWARDER_QUERY // FR: FORWARDER_RESPONSE // The "Message" Type values are defined below. enum Type { // AUTH_QUERY is a DNS query message received from a resolver by an // authoritative name server, from the perspective of the authoritative // name server. AUTH_QUERY = 1; // AUTH_RESPONSE is a DNS response message sent from an authoritative // name server to a resolver, from the perspective of the authoritative // name server. AUTH_RESPONSE = 2; // RESOLVER_QUERY is a DNS query message sent from a resolver to an // authoritative name server, from the perspective of the resolver. // Resolvers typically clear the RD (recursion desired) bit when // sending queries. RESOLVER_QUERY = 3; // RESOLVER_RESPONSE is a DNS response message received from an // authoritative name server by a resolver, from the perspective of // the resolver. RESOLVER_RESPONSE = 4; // CLIENT_QUERY is a DNS query message sent from a client to a DNS // server which is expected to perform further recursion, from the // perspective of the DNS server. The client may be a stub resolver or // forwarder or some other type of software which typically sets the RD // (recursion desired) bit when querying the DNS server. The DNS server // may be a simple forwarding proxy or it may be a full recursive // resolver. CLIENT_QUERY = 5; // CLIENT_RESPONSE is a DNS response message sent from a DNS server to // a client, from the perspective of the DNS server. The DNS server // typically sets the RA (recursion available) bit when responding. CLIENT_RESPONSE = 6; // FORWARDER_QUERY is a DNS query message sent from a downstream DNS // server to an upstream DNS server which is expected to perform // further recursion, from the perspective of the downstream DNS // server. FORWARDER_QUERY = 7; // FORWARDER_RESPONSE is a DNS response message sent from an upstream // DNS server performing recursion to a downstream DNS server, from the // perspective of the downstream DNS server. FORWARDER_RESPONSE = 8; // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS // server, from the perspective of the stub resolver. STUB_QUERY = 9; // STUB_RESPONSE is a DNS response message sent from a DNS server to a // stub resolver, from the perspective of the stub resolver. STUB_RESPONSE = 10; } // One of the Type values described above. required Type type = 1; // One of the SocketFamily values described above. optional SocketFamily socket_family = 2; // One of the SocketProtocol values described above. optional SocketProtocol socket_protocol = 3; // The network address of the message initiator. // For SocketFamily INET, this field is 4 octets (IPv4 address). // For SocketFamily INET6, this field is 16 octets (IPv6 address). optional bytes query_address = 4; // The network address of the message responder. // For SocketFamily INET, this field is 4 octets (IPv4 address). // For SocketFamily INET6, this field is 16 octets (IPv6 address). optional bytes response_address = 5; // The transport port of the message initiator. // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. optional uint32 query_port = 6; // The transport port of the message responder. // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. optional uint32 response_port = 7; // The time at which the DNS query message was sent or received, depending // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. // This is the number of seconds since the UNIX epoch. optional uint64 query_time_sec = 8; // The time at which the DNS query message was sent or received. // This is the seconds fraction, expressed as a count of nanoseconds. optional fixed32 query_time_nsec = 9; // The initiator's original wire-format DNS query message, verbatim. optional bytes query_message = 10; // The "zone" or "bailiwick" pertaining to the DNS query message. // This is a wire-format DNS domain name. optional bytes query_zone = 11; // The time at which the DNS response message was sent or received, // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or // CLIENT_RESPONSE. // This is the number of seconds since the UNIX epoch. optional uint64 response_time_sec = 12; // The time at which the DNS response message was sent or received. // This is the seconds fraction, expressed as a count of nanoseconds. optional fixed32 response_time_nsec = 13; // The responder's original wire-format DNS response message, verbatim. optional bytes response_message = 14; } // All fields except for 'type' in the Message schema are optional. // It is recommended that at least the following fields be filled in for // particular types of Messages. // AUTH_QUERY: // socket_family, socket_protocol // query_address, query_port // query_message // query_time_sec, query_time_nsec // AUTH_RESPONSE: // socket_family, socket_protocol // query_address, query_port // query_time_sec, query_time_nsec // response_message // response_time_sec, response_time_nsec // RESOLVER_QUERY: // socket_family, socket_protocol // query_name, query_type, query_class // query_message // query_time_sec, query_time_nsec // query_zone // response_address, response_port // RESOLVER_RESPONSE: // socket_family, socket_protocol // query_name, query_type, query_class // query_time_sec, query_time_nsec // query_zone // response_address, response_port // response_message // response_time_sec, response_time_nsec // CLIENT_QUERY: // socket_family, socket_protocol // query_message // query_time_sec, query_time_nsec // CLIENT_RESPONSE: // socket_family, socket_protocol // query_time_sec, query_time_nsec // response_message // response_time_sec, response_time_nsec nsd-4.12.0/dnstap/dnstap.m40000644000175000017500000000420315002373054015020 0ustar mozziemozzie# dnstap.m4 # dt_DNSTAP(default_dnstap_socket_path, [action-if-true], [action-if-false]) # -------------------------------------------------------------------------- # Check for required dnstap libraries and add dnstap configure args. AC_DEFUN([dt_DNSTAP], [ AC_ARG_ENABLE([dnstap], AS_HELP_STRING([--enable-dnstap], [Enable dnstap support (requires fstrm, protobuf-c)]), [opt_dnstap=$enableval], [opt_dnstap=no]) AC_ARG_WITH([dnstap-socket-path], AS_HELP_STRING([--with-dnstap-socket-path=pathname], [set default dnstap socket path]), [opt_dnstap_socket_path=$withval], [opt_dnstap_socket_path="$1"]) if test "x$opt_dnstap" != "xno"; then AC_PATH_PROG([PROTOC_C], [protoc-c]) if test -z "$PROTOC_C"; then AC_MSG_ERROR([The protoc-c program was not found. Please install protobuf-c!]) fi AC_ARG_WITH([protobuf-c], AS_HELP_STRING([--with-protobuf-c=path], [Path where protobuf-c is installed, for dnstap]), [ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f $withval/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I$withval/include/google" else CFLAGS="$CFLAGS -I$withval/include" fi LDFLAGS="$LDFLAGS -L$withval/lib" ], [ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f /usr/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/include/google" else if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/local/include/google" LDFLAGS="$LDFLAGS -L/usr/local/lib" fi fi ]) AC_ARG_WITH([libfstrm], AS_HELP_STRING([--with-libfstrm=path], [Path where libfstrm is installed, for dnstap]), [ CFLAGS="$CFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" ]) AC_SEARCH_LIBS([fstrm_iothr_init], [fstrm], [], AC_MSG_ERROR([The fstrm library was not found. Please install fstrm!])) AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [], AC_MSG_ERROR([The protobuf-c library was not found. Please install protobuf-c!])) $2 else $3 fi ]) nsd-4.12.0/dnstap/dnstap.h0000644000175000017500000001321115002373054014726 0ustar mozziemozzie/* dnstap support for NSD */ /* * Copyright (c) 2013-2014, Farsight Security, 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: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef NSD_DNSTAP_H #define NSD_DNSTAP_H #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP struct nsd_options; struct fstrm_io; struct fstrm_queue; struct dt_tls_writer; struct dt_env { /** dnstap I/O thread */ struct fstrm_iothr *iothr; /** dnstap I/O thread input queue */ struct fstrm_iothr_queue *ioq; /** dnstap "identity" field, NULL if disabled */ char *identity; /** dnstap "version" field, NULL if disabled */ char *version; /** length of "identity" field */ unsigned len_identity; /** length of "version" field */ unsigned len_version; /** whether to log Message/AUTH_QUERY */ unsigned log_auth_query_messages : 1; /** whether to log Message/AUTH_RESPONSE */ unsigned log_auth_response_messages : 1; /** tls writer object, or NULL */ struct dt_tls_writer* tls_writer; }; /** * Create dnstap environment object. Afterwards, call dt_apply_cfg() to fill in * the config variables and dt_init() to fill in the per-worker state. Each * worker needs a copy of this object but with its own I/O queue (the fq field * of the structure) to ensure lock-free access to its own per-worker circular * queue. Duplicate the environment object if more than one worker needs to * share access to the dnstap I/O socket. * @param socket_path: path to dnstap logging socket, must be non-NULL if used. * @param ip: if NULL or "" use socket path, otherwise IP or IP@port. * @param num_workers: number of worker threads, must be > 0. * @param tls: set to true to use TLS, otherwise, TCP. Used when ip is set. * @param tls_server_name: name for authenticating the upstream server, or * NULL or "". * @param tls_cert_bundle: pem bundle to verify server with. Or NULL or "". * @param tls_client_key_file: key file for client authentication. Or NULL * or "". * @param tls_client_cert_file: cert file for client authentication. Or NULL * or "". * @return dt_env object, NULL on failure. */ struct dt_env * dt_create(const char *socket_path, char* ip, unsigned num_workers, int tls, char* tls_server_name, char* tls_cert_bundle, char* tls_client_key_file, char* tls_client_cert_file); /** * Apply config settings. * @param env: dnstap environment object. * @param cfg: new config settings. */ void dt_apply_cfg(struct dt_env *env, struct nsd_options *cfg); /** * Initialize per-worker state in dnstap environment object. * @param env: dnstap environment object to initialize, created with dt_create(). * @return: true on success, false on failure. */ int dt_init(struct dt_env *env); /** * Delete dnstap environment object. Closes dnstap I/O socket and deletes all * per-worker I/O queues. */ void dt_delete(struct dt_env *env); /** * Create and send a new dnstap "Message" event of type AUTH_QUERY. * @param env: dnstap environment object. * @param local_addr: address/port of server (local address). * @param addr: address/port of client. * @param is_tcp: true for tcp, false for udp. * @param zone: zone name, or NULL. in wireformat. * @param zonelen: length of zone in bytes. * @param pkt: query message. * @param pktlen: length of pkt. */ void dt_msg_send_auth_query(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen); /** * Create and send a new dnstap "Message" event of type AUTH_RESPONSE. * @param env: dnstap environment object. * @param local_addr: address/port of server (local address). * @param addr: address/port of client. * @param is_tcp: true for tcp, false for udp. * @param zone: zone name, or NULL. in wireformat. * @param zonelen: length of zone in bytes. * @param pkt: response message. * @param pktlen: length of pkt. */ void dt_msg_send_auth_response(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen); #endif /* USE_DNSTAP */ #endif /* NSD_DNSTAP_H */ nsd-4.12.0/dnstap/dnstap.c0000644000175000017500000005771415002373054014741 0ustar mozziemozzie/* dnstap support for NSD */ /* * Copyright (c) 2013-2014, Farsight Security, 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: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP #include "config.h" #include #include #ifdef HAVE_SYS_STAT_H #include #endif #include #include #include "util.h" #include "options.h" #include #include #include "dnstap/dnstap.h" #include "dnstap/dnstap.pb-c.h" #ifdef HAVE_SSL #ifdef HAVE_OPENSSL_SSL_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #endif #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap" #define DNSTAP_INITIAL_BUF_SIZE 256 struct dt_msg { void *buf; size_t len_buf; Dnstap__Dnstap d; Dnstap__Message m; }; static int dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz) { ProtobufCBufferSimple sbuf; memset(&sbuf, 0, sizeof(sbuf)); sbuf.base.append = protobuf_c_buffer_simple_append; sbuf.len = 0; sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE; sbuf.data = malloc(sbuf.alloced); if (sbuf.data == NULL) return 0; sbuf.must_free_data = 1; *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf); if (sbuf.data == NULL) return 0; *buf = sbuf.data; return 1; } static void dt_send(const struct dt_env *env, void *buf, size_t len_buf) { fstrm_res res; if (!buf) return; res = fstrm_iothr_submit(env->iothr, env->ioq, buf, len_buf, fstrm_free_wrapper, NULL); if (res != fstrm_res_success) free(buf); } static void dt_msg_init(const struct dt_env *env, struct dt_msg *dm, Dnstap__Message__Type mtype) { memset(dm, 0, sizeof(*dm)); dm->d.base.descriptor = &dnstap__dnstap__descriptor; dm->m.base.descriptor = &dnstap__message__descriptor; dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE; dm->d.message = &dm->m; dm->m.type = mtype; if (env->identity != NULL) { dm->d.identity.data = (uint8_t *) env->identity; dm->d.identity.len = (size_t) env->len_identity; dm->d.has_identity = 1; } if (env->version != NULL) { dm->d.version.data = (uint8_t *) env->version; dm->d.version.len = (size_t) env->len_version; dm->d.has_version = 1; } } #ifdef HAVE_SSL /** TLS writer object for fstrm. */ struct dt_tls_writer { /* ip address */ char* ip; /* if connected already */ int connected; /* file descriptor */ int fd; /* TLS context */ SSL_CTX* ctx; /* SSL transport */ SSL* ssl; /* the server name to authenticate */ char* tls_server_name; }; void log_crypto_err(const char* str); /* in server.c */ /* Create TLS writer object for fstrm. */ static struct dt_tls_writer* tls_writer_init(char* ip, char* tls_server_name, char* tls_cert_bundle, char* tls_client_key_file, char* tls_client_cert_file) { struct dt_tls_writer* dtw = (struct dt_tls_writer*)calloc(1, sizeof(*dtw)); if(!dtw) return NULL; dtw->fd = -1; dtw->ip = strdup(ip); if(!dtw->ip) { free(dtw); return NULL; } dtw->ctx = SSL_CTX_new(SSLv23_client_method()); if(!dtw->ctx) { log_msg(LOG_ERR, "dnstap: SSL_CTX_new failed"); free(dtw->ip); free(dtw); return NULL; } #if SSL_OP_NO_SSLv2 != 0 if((SSL_CTX_set_options(dtw->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) { log_msg(LOG_ERR, "dnstap: could not set SSL_OP_NO_SSLv2"); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } #endif if((SSL_CTX_set_options(dtw->ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) { log_msg(LOG_ERR, "dnstap: could not set SSL_OP_NO_SSLv3"); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } #if defined(SSL_OP_NO_RENEGOTIATION) /* disable client renegotiation */ if((SSL_CTX_set_options(dtw->ctx, SSL_OP_NO_RENEGOTIATION) & SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) { log_msg(LOG_ERR, "dnstap: could not set SSL_OP_NO_RENEGOTIATION"); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } #endif if(tls_client_key_file && tls_client_key_file[0]) { if(!SSL_CTX_use_certificate_chain_file(dtw->ctx, tls_client_cert_file)) { log_msg(LOG_ERR, "dnstap: SSL_CTX_use_certificate_chain_file failed for %s", tls_client_cert_file); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } if(!SSL_CTX_use_PrivateKey_file(dtw->ctx, tls_client_key_file, SSL_FILETYPE_PEM)) { log_msg(LOG_ERR, "dnstap: SSL_CTX_use_PrivateKey_file failed for %s", tls_client_key_file); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } if(!SSL_CTX_check_private_key(dtw->ctx)) { log_msg(LOG_ERR, "dnstap: SSL_CTX_check_private_key failed for %s", tls_client_key_file); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } } if(tls_cert_bundle && tls_cert_bundle[0]) { if(!SSL_CTX_load_verify_locations(dtw->ctx, tls_cert_bundle, NULL)) { log_msg(LOG_ERR, "dnstap: SSL_CTX_load_verify_locations failed for %s", tls_cert_bundle); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } if(SSL_CTX_set_default_verify_paths(dtw->ctx) != 1) { log_msg(LOG_ERR, "dnstap: SSL_CTX_set_default_verify_paths failed"); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } SSL_CTX_set_verify(dtw->ctx, SSL_VERIFY_PEER, NULL); } if(tls_server_name) { dtw->tls_server_name = strdup(tls_server_name); if(!dtw->tls_server_name) { log_msg(LOG_ERR, "dnstap: strdup failed"); SSL_CTX_free(dtw->ctx); free(dtw->ip); free(dtw); return NULL; } } return dtw; } /* Delete TLS writer object */ static void tls_writer_delete(struct dt_tls_writer* dtw) { if(!dtw) return; if(dtw->ssl) SSL_shutdown(dtw->ssl); SSL_free(dtw->ssl); dtw->ssl = NULL; SSL_CTX_free(dtw->ctx); if(dtw->fd != -1) { close(dtw->fd); dtw->fd = -1; } free(dtw->ip); free(dtw->tls_server_name); free(dtw); } /* The fstrm writer destroy callback for TLS */ static fstrm_res dt_tls_writer_destroy(void* obj) { struct dt_tls_writer* dtw = (struct dt_tls_writer*)obj; tls_writer_delete(dtw); return fstrm_res_success; } /* The fstrm writer open callback for TLS */ static fstrm_res dt_tls_writer_open(void* obj) { struct sockaddr_storage addr; socklen_t addrlen; char* svr, *at = NULL; int port = 3333; int addrfamily; struct dt_tls_writer* dtw = (struct dt_tls_writer*)obj; X509* x; /* skip action if already connected */ if(dtw->connected) return fstrm_res_success; /* figure out port number */ svr = dtw->ip; at = strchr(svr, '@'); if(at != NULL) { *at = 0; port = atoi(at+1); } /* parse addr */ memset(&addr, 0, sizeof(addr)); #ifdef INET6 if(strchr(svr, ':')) { struct sockaddr_in6 sa; addrlen = (socklen_t)sizeof(struct sockaddr_in6); memset(&sa, 0, addrlen); sa.sin6_family = AF_INET6; sa.sin6_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin6_family, svr, &sa.sin6_addr) <= 0) { log_msg(LOG_ERR, "dnstap: could not parse IP: %s", svr); if(at != NULL) *at = '@'; return fstrm_res_failure; } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET6; } else #else if(1) #endif { struct sockaddr_in sa; addrlen = (socklen_t)sizeof(struct sockaddr_in); memset(&sa, 0, addrlen); sa.sin_family = AF_INET; sa.sin_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin_family, svr, &sa.sin_addr) <= 0) { log_msg(LOG_ERR, "dnstap: could not parse IP: %s", svr); if(at != NULL) *at = '@'; return fstrm_res_failure; } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET; } if(at != NULL) *at = '@'; /* open socket */ dtw->fd = socket(addrfamily, SOCK_STREAM, 0); if(dtw->fd == -1) { log_msg(LOG_ERR, "dnstap: socket failed: %s", strerror(errno)); return fstrm_res_failure; } if(connect(dtw->fd, (struct sockaddr*)&addr, addrlen) < 0) { log_msg(LOG_ERR, "dnstap: connect failed: %s", strerror(errno)); return fstrm_res_failure; } dtw->connected = 1; /* setup SSL */ dtw->ssl = SSL_new(dtw->ctx); if(!dtw->ssl) { log_msg(LOG_ERR, "dnstap: SSL_new failed"); return fstrm_res_failure; } SSL_set_connect_state(dtw->ssl); (void)SSL_set_mode(dtw->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(dtw->ssl, dtw->fd)) { log_msg(LOG_ERR, "dnstap: SSL_set_fd failed"); return fstrm_res_failure; } if(dtw->tls_server_name && dtw->tls_server_name[0]) { if(!SSL_set1_host(dtw->ssl, dtw->tls_server_name)) { log_msg(LOG_ERR, "dnstap: TLS setting of hostname %s failed to %s", dtw->tls_server_name, dtw->ip); return fstrm_res_failure; } } /* handshake */ while(1) { int r; ERR_clear_error(); if( (r=SSL_do_handshake(dtw->ssl)) == 1) break; r = SSL_get_error(dtw->ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { if(r == SSL_ERROR_ZERO_RETURN) { log_msg(LOG_ERR, "dnstap: EOF on SSL_do_handshake"); return fstrm_res_failure; } if(r == SSL_ERROR_SYSCALL) { log_msg(LOG_ERR, "dnstap: SSL_do_handshake failed: %s", strerror(errno)); return fstrm_res_failure; } log_crypto_err("dnstap: SSL_do_handshake failed"); return fstrm_res_failure; } /* wants to be called again */ } /* check authenticity of server */ if(SSL_get_verify_result(dtw->ssl) != X509_V_OK) { log_crypto_err("SSL verification failed"); return fstrm_res_failure; } #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE x = SSL_get1_peer_certificate(dtw->ssl); #else x = SSL_get_peer_certificate(dtw->ssl); #endif if(!x) { log_crypto_err("Server presented no peer certificate"); return fstrm_res_failure; } X509_free(x); return fstrm_res_success; } /* The fstrm writer close callback for TLS */ static fstrm_res dt_tls_writer_close(void* obj) { struct dt_tls_writer* dtw = (struct dt_tls_writer*)obj; if(dtw->connected) { dtw->connected = 0; if(dtw->ssl) SSL_shutdown(dtw->ssl); SSL_free(dtw->ssl); dtw->ssl = NULL; if(dtw->fd != -1) { close(dtw->fd); dtw->fd = -1; } return fstrm_res_success; } return fstrm_res_failure; } /* The fstrm writer read callback for TLS */ static fstrm_res dt_tls_writer_read(void* obj, void* buf, size_t nbytes) { /* want to read nbytes of data */ struct dt_tls_writer* dtw = (struct dt_tls_writer*)obj; size_t nread = 0; if(!dtw->connected) return fstrm_res_failure; while(nread < nbytes) { int r; ERR_clear_error(); if((r = SSL_read(dtw->ssl, ((char*)buf)+nread, nbytes-nread)) <= 0) { r = SSL_get_error(dtw->ssl, r); if(r == SSL_ERROR_ZERO_RETURN) { log_msg(LOG_ERR, "dnstap: EOF from %s", dtw->ip); return fstrm_res_failure; } if(r == SSL_ERROR_SYSCALL) { log_msg(LOG_ERR, "dnstap: read %s: %s", dtw->ip, strerror(errno)); return fstrm_res_failure; } if(r == SSL_ERROR_SSL) { log_crypto_err("dnstap: could not SSL_read"); return fstrm_res_failure; } log_msg(LOG_ERR, "dnstap: SSL_read failed with err %d", r); return fstrm_res_failure; } nread += r; } return fstrm_res_success; } /* The fstrm writer write callback for TLS */ static fstrm_res dt_tls_writer_write(void* obj, const struct iovec* iov, int iovcnt) { struct dt_tls_writer* dtw = (struct dt_tls_writer*)obj; int i; if(!dtw->connected) return fstrm_res_failure; for(i=0; issl, iov[i].iov_base, (int)(iov[i].iov_len)) <= 0) { log_crypto_err("dnstap: could not SSL_write"); return fstrm_res_failure; } } return fstrm_res_success; } /* Create the fstrm writer object for TLS */ static struct fstrm_writer* dt_tls_make_writer(struct fstrm_writer_options* fwopt, struct dt_tls_writer* dtw) { struct fstrm_rdwr* rdwr = fstrm_rdwr_init(dtw); fstrm_rdwr_set_destroy(rdwr, dt_tls_writer_destroy); fstrm_rdwr_set_open(rdwr, dt_tls_writer_open); fstrm_rdwr_set_close(rdwr, dt_tls_writer_close); fstrm_rdwr_set_read(rdwr, dt_tls_writer_read); fstrm_rdwr_set_write(rdwr, dt_tls_writer_write); return fstrm_writer_init(fwopt, &rdwr); } #endif /* HAVE_SSL */ /* check that the socket file can be opened and exists, print error if not */ static void check_socket_file(const char* socket_path) { struct stat statbuf; memset(&statbuf, 0, sizeof(statbuf)); if(stat(socket_path, &statbuf) < 0) { log_msg(LOG_WARNING, "could not open dnstap-socket-path: %s, %s", socket_path, strerror(errno)); } } struct dt_env * dt_create(const char *socket_path, char* ip, unsigned num_workers, int tls, char* tls_server_name, char* tls_cert_bundle, char* tls_client_key_file, char* tls_client_cert_file) { #ifndef NDEBUG fstrm_res res; #endif struct dt_env *env; struct fstrm_iothr_options *fopt; struct fstrm_unix_writer_options *fuwopt = NULL; struct fstrm_tcp_writer_options *ftwopt = NULL; struct fstrm_writer *fw; struct fstrm_writer_options *fwopt; assert(num_workers > 0); if(ip == NULL || ip[0] == 0) { VERBOSITY(1, (LOG_INFO, "attempting to connect to dnstap socket %s", socket_path)); assert(socket_path != NULL); check_socket_file(socket_path); } else { VERBOSITY(1, (LOG_INFO, "attempting to connect to dnstap %ssocket %s", (tls?"tls ":""), ip)); } env = (struct dt_env *) calloc(1, sizeof(struct dt_env)); if (!env) return NULL; fwopt = fstrm_writer_options_init(); #ifndef NDEBUG res = #else (void) #endif fstrm_writer_options_add_content_type(fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1); assert(res == fstrm_res_success); if(ip == NULL || ip[0] == 0) { fuwopt = fstrm_unix_writer_options_init(); fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path); } else { char* at = strchr(ip, '@'); if(!tls) { ftwopt = fstrm_tcp_writer_options_init(); if(at == NULL) { fstrm_tcp_writer_options_set_socket_address(ftwopt, ip); fstrm_tcp_writer_options_set_socket_port(ftwopt, "3333"); } else { *at = 0; fstrm_tcp_writer_options_set_socket_address(ftwopt, ip); fstrm_tcp_writer_options_set_socket_port(ftwopt, at+1); *at = '@'; } } else { #ifdef HAVE_SSL env->tls_writer = tls_writer_init(ip, tls_server_name, tls_cert_bundle, tls_client_key_file, tls_client_cert_file); #else (void)tls_server_name; (void)tls_cert_bundle; (void)tls_client_key_file; (void)tls_client_cert_file; log_msg(LOG_ERR, "dnstap: tls enabled but compiled without ssl."); #endif if(!env->tls_writer) { log_msg(LOG_ERR, "dt_create: tls_writer_init() failed"); fstrm_writer_options_destroy(&fwopt); free(env); return NULL; } } } if(ip == NULL || ip[0] == 0) fw = fstrm_unix_writer_init(fuwopt, fwopt); else if(!tls) fw = fstrm_tcp_writer_init(ftwopt, fwopt); #ifdef HAVE_SSL else fw = dt_tls_make_writer(fwopt, env->tls_writer); #endif assert(fw != NULL); fopt = fstrm_iothr_options_init(); fstrm_iothr_options_set_num_input_queues(fopt, num_workers); env->iothr = fstrm_iothr_init(fopt, &fw); if (env->iothr == NULL) { log_msg(LOG_ERR, "dt_create: fstrm_iothr_init() failed"); fstrm_writer_destroy(&fw); free(env); env = NULL; } fstrm_iothr_options_destroy(&fopt); if(ip == NULL || ip[0] == 0) fstrm_unix_writer_options_destroy(&fuwopt); else if(!tls) fstrm_tcp_writer_options_destroy(&ftwopt); fstrm_writer_options_destroy(&fwopt); return env; } static void dt_apply_identity(struct dt_env *env, struct nsd_options *cfg) { char buf[MAXHOSTNAMELEN+1]; if (!cfg->dnstap_send_identity) return; free(env->identity); if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { if (gethostname(buf, MAXHOSTNAMELEN) == 0) { buf[MAXHOSTNAMELEN] = 0; env->identity = strdup(buf); } else { error("dt_apply_identity: gethostname() failed"); } } else { env->identity = strdup(cfg->dnstap_identity); } if (env->identity == NULL) error("dt_apply_identity: strdup() failed"); env->len_identity = (unsigned int)strlen(env->identity); VERBOSITY(1, (LOG_INFO, "dnstap identity field set to \"%s\"", env->identity)); } static void dt_apply_version(struct dt_env *env, struct nsd_options *cfg) { if (!cfg->dnstap_send_version) return; free(env->version); if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) env->version = strdup(PACKAGE_STRING); else env->version = strdup(cfg->dnstap_version); if (env->version == NULL) error("dt_apply_version: strdup() failed"); env->len_version = (unsigned int)strlen(env->version); VERBOSITY(1, (LOG_INFO, "dnstap version field set to \"%s\"", env->version)); } void dt_apply_cfg(struct dt_env *env, struct nsd_options *cfg) { if (!cfg->dnstap_enable) return; dt_apply_identity(env, cfg); dt_apply_version(env, cfg); if ((env->log_auth_query_messages = (unsigned int) cfg->dnstap_log_auth_query_messages)) { VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_QUERY enabled")); } if ((env->log_auth_response_messages = (unsigned int) cfg->dnstap_log_auth_response_messages)) { VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_RESPONSE enabled")); } } int dt_init(struct dt_env *env) { env->ioq = fstrm_iothr_get_input_queue(env->iothr); if (env->ioq == NULL) return 0; return 1; } void dt_delete(struct dt_env *env) { if (!env) return; VERBOSITY(1, (LOG_INFO, "closing dnstap socket")); fstrm_iothr_destroy(&env->iothr); free(env->identity); free(env->version); free(env); } static void dt_fill_timeval(const struct timeval *tv, uint64_t *time_sec, protobuf_c_boolean *has_time_sec, uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec) { #ifndef S_SPLINT_S *time_sec = tv->tv_sec; *time_nsec = tv->tv_usec * 1000; #endif *has_time_sec = 1; *has_time_nsec = 1; } static void dt_fill_buffer(uint8_t* pkt, size_t pktlen, ProtobufCBinaryData *p, protobuf_c_boolean *has) { p->len = pktlen; p->data = pkt; *has = 1; } static void dt_msg_fill_net(struct dt_msg *dm, #ifdef INET6 struct sockaddr_storage *rs, struct sockaddr_storage *qs, #else struct sockaddr_in *rs, struct sockaddr_in *qs, #endif int is_tcp, ProtobufCBinaryData *raddr, protobuf_c_boolean *has_raddr, uint32_t *rport, protobuf_c_boolean *has_rport, ProtobufCBinaryData *qaddr, protobuf_c_boolean *has_qaddr, uint32_t *qport, protobuf_c_boolean *has_qport) { #ifdef INET6 assert(qs->ss_family == AF_INET6 || qs->ss_family == AF_INET); if (qs->ss_family == AF_INET6) { struct sockaddr_in6 *s = (struct sockaddr_in6 *) qs; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ qaddr->data = s->sin6_addr.s6_addr; qaddr->len = 16; /* IPv6 */ *has_qaddr = 1; /* port: query_port or response_port */ *qport = ntohs(s->sin6_port); *has_qport = 1; } else if (qs->ss_family == AF_INET) { #else if (qs->sin_family == AF_INET) { #endif /* INET6 */ struct sockaddr_in *s = (struct sockaddr_in *) qs; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ qaddr->data = (uint8_t *) &s->sin_addr.s_addr; qaddr->len = 4; /* IPv4 */ *has_qaddr = 1; /* port: query_port or response_port */ *qport = ntohs(s->sin_port); *has_qport = 1; } #ifdef INET6 assert(rs->ss_family == AF_INET6 || rs->ss_family == AF_INET); if (rs->ss_family == AF_INET6) { struct sockaddr_in6 *s = (struct sockaddr_in6 *) rs; /* addr: query_address or response_address */ raddr->data = s->sin6_addr.s6_addr; raddr->len = 16; /* IPv6 */ *has_raddr = 1; /* port: query_port or response_port */ *rport = ntohs(s->sin6_port); *has_rport = 1; } else if (rs->ss_family == AF_INET) { #else if (rs->sin_family == AF_INET) { #endif /* INET6 */ struct sockaddr_in *s = (struct sockaddr_in *) rs; /* addr: query_address or response_address */ raddr->data = (uint8_t *) &s->sin_addr.s_addr; raddr->len = 4; /* IPv4 */ *has_raddr = 1; /* port: query_port or response_port */ *rport = ntohs(s->sin_port); *has_rport = 1; } if (!is_tcp) { /* socket_protocol */ dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; dm->m.has_socket_protocol = 1; } else { /* socket_protocol */ dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; dm->m.has_socket_protocol = 1; } } void dt_msg_send_auth_query(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen) { struct dt_msg dm; struct timeval qtime; gettimeofday(&qtime, NULL); /* type */ dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_QUERY); if(zone) { /* query_zone */ dm.m.query_zone.data = zone; dm.m.query_zone.len = zonelen; dm.m.has_query_zone = 1; } /* query_time */ dt_fill_timeval(&qtime, &dm.m.query_time_sec, &dm.m.has_query_time_sec, &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); /* query_message */ dt_fill_buffer(pkt, pktlen, &dm.m.query_message, &dm.m.has_query_message); /* socket_family, socket_protocol, query_address, query_port, reponse_address (local_address), response_port (local_port) */ dt_msg_fill_net(&dm, local_addr, addr, is_tcp, &dm.m.response_address, &dm.m.has_response_address, &dm.m.response_port, &dm.m.has_response_port, &dm.m.query_address, &dm.m.has_query_address, &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); } void dt_msg_send_auth_response(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* local_addr, struct sockaddr_storage* addr, #else struct sockaddr_in* local_addr, struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen) { struct dt_msg dm; struct timeval rtime; gettimeofday(&rtime, NULL); /* type */ dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE); if(zone) { /* query_zone */ dm.m.query_zone.data = zone; dm.m.query_zone.len = zonelen; dm.m.has_query_zone = 1; } /* response_time */ dt_fill_timeval(&rtime, &dm.m.response_time_sec, &dm.m.has_response_time_sec, &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); /* response_message */ dt_fill_buffer(pkt, pktlen, &dm.m.response_message, &dm.m.has_response_message); /* socket_family, socket_protocol, query_address, query_port, response_address (local_address), response_port (local_port) */ dt_msg_fill_net(&dm, local_addr, addr, is_tcp, &dm.m.response_address, &dm.m.has_response_address, &dm.m.response_port, &dm.m.has_response_port, &dm.m.query_address, &dm.m.has_query_address, &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); } #endif /* USE_DNSTAP */ nsd-4.12.0/dns.h0000644000175000017500000002767615002373054012754 0ustar mozziemozzie/* * dns.h -- DNS definitions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DNS_H #define DNS_H enum rr_section { QUESTION_SECTION, ANSWER_SECTION, AUTHORITY_SECTION, /* * Use a split authority section to ensure that optional * NS RRsets in the response can be omitted. */ OPTIONAL_AUTHORITY_SECTION, ADDITIONAL_SECTION, /* * Use a split additional section to ensure A records appear * before any AAAA records (this is recommended practice to * avoid truncating the additional section for IPv4 clients * that do not specify EDNS0), and AAAA records before other * types of additional records (such as X25 and ISDN). * Encode_answer sets the ARCOUNT field of the response packet * correctly. */ ADDITIONAL_A_SECTION = ADDITIONAL_SECTION, ADDITIONAL_AAAA_SECTION, ADDITIONAL_OTHER_SECTION, RR_SECTION_COUNT }; typedef enum rr_section rr_section_type; /* Possible OPCODE values */ #define OPCODE_QUERY 0 /* a standard query (QUERY) */ #define OPCODE_IQUERY 1 /* an inverse query (IQUERY) */ #define OPCODE_STATUS 2 /* a server status request (STATUS) */ #define OPCODE_NOTIFY 4 /* NOTIFY */ #define OPCODE_UPDATE 5 /* Dynamic update */ /* Possible RCODE values */ #define RCODE_OK 0 /* No error condition */ #define RCODE_FORMAT 1 /* Format error */ #define RCODE_SERVFAIL 2 /* Server failure */ #define RCODE_NXDOMAIN 3 /* Name Error */ #define RCODE_IMPL 4 /* Not implemented */ #define RCODE_REFUSE 5 /* Refused */ #define RCODE_YXDOMAIN 6 /* name should not exist */ #define RCODE_YXRRSET 7 /* rrset should not exist */ #define RCODE_NXRRSET 8 /* rrset does not exist */ #define RCODE_NOTAUTH 9 /* server not authoritative */ #define RCODE_NOTZONE 10 /* name not inside zone */ /* Standardized NSD return code. Partially maps to DNS RCODE values. */ enum nsd_rc { /* Discard the client request. */ NSD_RC_DISCARD = -1, /* OK, continue normal processing. */ NSD_RC_OK = RCODE_OK, /* Return the appropriate error code to the client. */ NSD_RC_FORMAT = RCODE_FORMAT, NSD_RC_SERVFAIL = RCODE_SERVFAIL, NSD_RC_NXDOMAIN = RCODE_NXDOMAIN, NSD_RC_IMPL = RCODE_IMPL, NSD_RC_REFUSE = RCODE_REFUSE, NSD_RC_NOTAUTH = RCODE_NOTAUTH }; typedef enum nsd_rc nsd_rc_type; /* RFC1035 */ #define CLASS_IN 1 /* Class IN */ #define CLASS_CS 2 /* Class CS */ #define CLASS_CH 3 /* Class CHAOS */ #define CLASS_HS 4 /* Class HS */ #define CLASS_NONE 254 /* Class NONE rfc2136 */ #define CLASS_ANY 255 /* Class ANY */ #define TYPE_A 1 /* a host address */ #define TYPE_NS 2 /* an authoritative name server */ #define TYPE_MD 3 /* a mail destination (Obsolete - use MX) */ #define TYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ #define TYPE_CNAME 5 /* the canonical name for an alias */ #define TYPE_SOA 6 /* marks the start of a zone of authority */ #define TYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ #define TYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ #define TYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ #define TYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ #define TYPE_WKS 11 /* a well known service description */ #define TYPE_PTR 12 /* a domain name pointer */ #define TYPE_HINFO 13 /* host information */ #define TYPE_MINFO 14 /* mailbox or mail list information */ #define TYPE_MX 15 /* mail exchange */ #define TYPE_TXT 16 /* text strings */ #define TYPE_RP 17 /* RFC1183 */ #define TYPE_AFSDB 18 /* RFC1183 */ #define TYPE_X25 19 /* RFC1183 */ #define TYPE_ISDN 20 /* RFC1183 */ #define TYPE_RT 21 /* RFC1183 */ #define TYPE_NSAP 22 /* RFC1706 (deprecated by RFC9121) */ #define TYPE_NSAP_PTR 23 /* RFC1348 (deprecated by RFC9121) */ #define TYPE_SIG 24 /* 2535typecode */ #define TYPE_KEY 25 /* 2535typecode */ #define TYPE_PX 26 /* RFC2163 */ #define TYPE_GPOS 27 /* RFC1712 */ #define TYPE_AAAA 28 /* ipv6 address */ #define TYPE_LOC 29 /* LOC record RFC1876 */ #define TYPE_NXT 30 /* 2535typecode */ #define TYPE_EID 31 /* draft-ietf-nimrod-dns-01 */ #define TYPE_NIMLOC 32 /* draft-ietf-nimrod-dns-01 */ #define TYPE_SRV 33 /* SRV record RFC2782 */ #define TYPE_ATMA 34 /* ATM Address */ #define TYPE_NAPTR 35 /* RFC2915 */ #define TYPE_KX 36 /* RFC2230 Key Exchange Delegation Record */ #define TYPE_CERT 37 /* RFC2538 */ #define TYPE_A6 38 /* RFC2874 */ #define TYPE_DNAME 39 /* RFC2672 */ #define TYPE_SINK 40 /* draft-eastlake-kitchen-sink */ #define TYPE_OPT 41 /* Pseudo OPT record... */ #define TYPE_APL 42 /* RFC3123 */ #define TYPE_DS 43 /* RFC 4033, 4034, and 4035 */ #define TYPE_SSHFP 44 /* SSH Key Fingerprint */ #define TYPE_IPSECKEY 45 /* public key for ipsec use. RFC 4025 */ #define TYPE_RRSIG 46 /* RFC 4033, 4034, and 4035 */ #define TYPE_NSEC 47 /* RFC 4033, 4034, and 4035 */ #define TYPE_DNSKEY 48 /* RFC 4033, 4034, and 4035 */ #define TYPE_DHCID 49 /* RFC4701 DHCP information */ #define TYPE_NSEC3 50 /* NSEC3, secure denial, prevents zonewalking */ #define TYPE_NSEC3PARAM 51 /* NSEC3PARAM at zone apex nsec3 parameters */ #define TYPE_TLSA 52 /* RFC 6698 */ #define TYPE_SMIMEA 53 /* RFC 8162 */ #define TYPE_HIP 55 /* RFC 8005 */ #define TYPE_NINFO 56 /* NINFO/ninfo-completed-template */ #define TYPE_RKEY 57 /* RKEY/rkey-completed-template */ #define TYPE_TALINK 58 /* draft-iet5f-dnsop-dnssec-trust-history */ #define TYPE_CDS 59 /* RFC 7344 */ #define TYPE_CDNSKEY 60 /* RFC 7344 */ #define TYPE_OPENPGPKEY 61 /* RFC 7929 */ #define TYPE_CSYNC 62 /* RFC 7477 */ #define TYPE_ZONEMD 63 /* RFC 8976 */ #define TYPE_SVCB 64 /* RFC 9460 */ #define TYPE_HTTPS 65 /* RFC 9460 */ #define TYPE_DSYNC 66 /* draft-ietf-dnsop-generalized-notify */ #define TYPE_SPF 99 /* RFC 4408 */ #define TYPE_NID 104 /* RFC 6742 */ #define TYPE_L32 105 /* RFC 6742 */ #define TYPE_L64 106 /* RFC 6742 */ #define TYPE_LP 107 /* RFC 6742 */ #define TYPE_EUI48 108 /* RFC 7043 */ #define TYPE_EUI64 109 /* RFC 7043 */ #define TYPE_TSIG 250 #define TYPE_IXFR 251 #define TYPE_AXFR 252 #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_AVC 258 /* AVC/avc-completed-template */ #define TYPE_DOA 259 /* draft-durand-doa-over-dns */ #define TYPE_AMTRELAY 260 /* RFC 8777 */ #define TYPE_RESINFO 261 /* RFC 9606 */ #define TYPE_WALLET 262 /* WALLET/wallet-completed-template */ #define TYPE_CLA 263 /* CLA/cla-completed-template */ #define TYPE_IPN 264 /* IPN/ipn-completed-template */ #define TYPE_TA 32768 /* http://www.watson.org/~weiler/INI1999-19.pdf */ #define TYPE_DLV 32769 /* RFC 4431 */ #define PSEUDO_TYPE_TA RRTYPE_DESCRIPTORS_LENGTH #define PSEUDO_TYPE_DLV (RRTYPE_DESCRIPTORS_LENGTH + 1) #define SVCB_KEY_MANDATORY 0 #define SVCB_KEY_ALPN 1 #define SVCB_KEY_NO_DEFAULT_ALPN 2 #define SVCB_KEY_PORT 3 #define SVCB_KEY_IPV4HINT 4 #define SVCB_KEY_ECH 5 #define SVCB_KEY_IPV6HINT 6 #define SVCB_KEY_DOHPATH 7 #define SVCB_KEY_OHTTP 8 #define SVCB_KEY_TLS_SUPPORTED_GROUPS 9 #define SVCPARAMKEY_COUNT 10 #define MAXLABELLEN 63 #define MAXDOMAINLEN 255 #define MAXRDATALEN 64 /* This is more than enough, think multiple TXT. */ #define MAX_RDLENGTH 65535 /* Maximum size of a single RR. */ #define MAX_RR_SIZE \ (MAXDOMAINLEN + sizeof(uint32_t) + 4*sizeof(uint16_t) + MAX_RDLENGTH) #define IP4ADDRLEN (32/8) #define IP6ADDRLEN (128/8) #define EUI48ADDRLEN (48/8) #define EUI64ADDRLEN (64/8) #define NSEC3_HASH_LEN 20 /* * The different types of RDATA wireformat data. */ enum rdata_wireformat { RDATA_WF_COMPRESSED_DNAME, /* Possibly compressed domain name. */ RDATA_WF_UNCOMPRESSED_DNAME, /* Uncompressed domain name. */ RDATA_WF_LITERAL_DNAME, /* Literal (not downcased) dname. */ RDATA_WF_BYTE, /* 8-bit integer. */ RDATA_WF_SHORT, /* 16-bit integer. */ RDATA_WF_LONG, /* 32-bit integer. */ RDATA_WF_LONGLONG, /* 64-bit integer. */ RDATA_WF_TEXT, /* Text string. */ RDATA_WF_TEXTS, /* Text string sequence. */ RDATA_WF_A, /* 32-bit IPv4 address. */ RDATA_WF_AAAA, /* 128-bit IPv6 address. */ RDATA_WF_BINARY, /* Binary data (unknown length). */ RDATA_WF_BINARYWITHLENGTH, /* Binary data preceded by 1 byte length */ RDATA_WF_APL, /* APL data. */ RDATA_WF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */ RDATA_WF_ILNP64, /* 64-bit uncompressed IPv6 address. */ RDATA_WF_EUI48, /* 48-bit address. */ RDATA_WF_EUI64, /* 64-bit address. */ RDATA_WF_LONG_TEXT, /* Long (>255) text string. */ RDATA_WF_SVCPARAM, /* SvcParam [=] */ RDATA_WF_HIP, /* HIP rdata up to the Rendezvous Servers */ RDATA_WF_AMTRELAY_RELAY /* ip4, ip6, dname or nothing */ }; typedef enum rdata_wireformat rdata_wireformat_type; /* * The different types of RDATA that can appear in the zone file. */ enum rdata_zoneformat { RDATA_ZF_DNAME, /* Domain name. */ RDATA_ZF_LITERAL_DNAME, /* DNS name (not lowercased domain name). */ RDATA_ZF_TEXT, /* Text string. */ RDATA_ZF_TEXTS, /* Text string sequence. */ RDATA_ZF_BYTE, /* 8-bit integer. */ RDATA_ZF_SHORT, /* 16-bit integer. */ RDATA_ZF_LONG, /* 32-bit integer. */ RDATA_ZF_LONGLONG, /* 64-bit integer. */ RDATA_ZF_A, /* 32-bit IPv4 address. */ RDATA_ZF_AAAA, /* 128-bit IPv6 address. */ RDATA_ZF_RRTYPE, /* RR type. */ RDATA_ZF_ALGORITHM, /* Cryptographic algorithm. */ RDATA_ZF_CERTIFICATE_TYPE, RDATA_ZF_PERIOD, /* Time period. */ RDATA_ZF_TIME, RDATA_ZF_BASE64, /* Base-64 binary data. */ RDATA_ZF_BASE32, /* Base-32 binary data. */ RDATA_ZF_HEX, /* Hexadecimal binary data. */ RDATA_ZF_HEX_LEN, /* Hexadecimal binary data. Skip initial length byte. */ RDATA_ZF_NSAP, /* NSAP. */ RDATA_ZF_APL, /* APL. */ RDATA_ZF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */ RDATA_ZF_SERVICES, /* Protocol and port number bitmap. */ RDATA_ZF_NXT, /* NXT type bitmap. */ RDATA_ZF_NSEC, /* NSEC type bitmap. */ RDATA_ZF_LOC, /* Location data. */ RDATA_ZF_ILNP64, /* 64-bit uncompressed IPv6 address. */ RDATA_ZF_EUI48, /* EUI48 address. */ RDATA_ZF_EUI64, /* EUI64 address. */ RDATA_ZF_LONG_TEXT, /* Long (>255) text string. */ RDATA_ZF_UNQUOTED, /* Unquoted text string. */ RDATA_ZF_UNQUOTEDS, /* A sequence of unquoted text strings. */ RDATA_ZF_TAG, /* A sequence of letters and numbers. */ RDATA_ZF_SVCPARAM, /* SvcParam [=] */ RDATA_ZF_HIP, /* HIP rdata up to the Rendezvous Servers */ RDATA_ZF_ATMA, /* ATM Address */ RDATA_ZF_AMTRELAY_D_TYPE,/* Discovery Optional and Type */ RDATA_ZF_AMTRELAY_RELAY,/* ip4, ip6, dname or nothing */ RDATA_ZF_UNKNOWN /* Unknown data. */ }; typedef enum rdata_zoneformat rdata_zoneformat_type; struct rrtype_descriptor { uint16_t type; /* RR type */ const char *name; /* Textual name. */ uint32_t minimum; /* Minimum number of RDATAs. */ uint32_t maximum; /* Maximum number of RDATAs. */ uint8_t wireformat[MAXRDATALEN]; /* rdata_wireformat_type */ uint8_t zoneformat[MAXRDATALEN]; /* rdata_zoneformat_type */ }; typedef struct rrtype_descriptor rrtype_descriptor_type; /* * Indexed by type. The special type "0" can be used to get a * descriptor for unknown types (with one binary rdata). * * CLA + 1 */ #define RRTYPE_DESCRIPTORS_LENGTH (TYPE_IPN + 1) rrtype_descriptor_type *rrtype_descriptor_by_name(const char *name); rrtype_descriptor_type *rrtype_descriptor_by_type(uint16_t type); const char *rrtype_to_string(uint16_t rrtype); /* * Lookup the type in the ztypes lookup table. If not found, check if * the type uses the "TYPExxx" notation for unknown types. * * Return 0 if no type matches. */ uint16_t rrtype_from_string(const char *name); const char *rrclass_to_string(uint16_t rrclass); uint16_t rrclass_from_string(const char *name); #endif /* DNS_H */ nsd-4.12.0/dns.c0000644000175000017500000012324315002373054012732 0ustar mozziemozzie/* * dns.c -- DNS definitions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "dns.h" #include "zonec.h" /* Taken from RFC 1035, section 3.2.4. */ static lookup_table_type dns_rrclasses[] = { { CLASS_IN, "IN" }, /* the Internet */ { CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */ { CLASS_CH, "CH" }, /* the CHAOS class */ { CLASS_HS, "HS" }, /* Hesiod */ { 0, NULL } }; static rrtype_descriptor_type rrtype_descriptors[(RRTYPE_DESCRIPTORS_LENGTH+2)] = { /* 0 */ { 0, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 1 */ { TYPE_A, "A", 1, 1, { RDATA_WF_A }, { RDATA_ZF_A } }, /* 2 */ { TYPE_NS, "NS", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 3 */ { TYPE_MD, "MD", 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 4 */ { TYPE_MF, "MF", 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 5 */ { TYPE_CNAME, "CNAME", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 6 */ { TYPE_SOA, "SOA", 7, 7, { RDATA_WF_COMPRESSED_DNAME, RDATA_WF_COMPRESSED_DNAME, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD } }, /* 7 */ { TYPE_MB, "MB", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 8 */ { TYPE_MG, "MG", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 9 */ { TYPE_MR, "MR", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 10 */ { TYPE_NULL, "NULL", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 11 */ { TYPE_WKS, "WKS", 2, 2, { RDATA_WF_A, RDATA_WF_BINARY }, { RDATA_ZF_A, RDATA_ZF_SERVICES } }, /* 12 */ { TYPE_PTR, "PTR", 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 13 */ { TYPE_HINFO, "HINFO", 2, 2, { RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_TEXT, RDATA_ZF_TEXT } }, /* 14 */ { TYPE_MINFO, "MINFO", 2, 2, { RDATA_WF_COMPRESSED_DNAME, RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 15 */ { TYPE_MX, "MX", 2, 2, { RDATA_WF_SHORT, RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 16 */ { TYPE_TXT, "TXT", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 17 */ { TYPE_RP, "RP", 2, 2, { RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 18 */ { TYPE_AFSDB, "AFSDB", 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 19 */ { TYPE_X25, "X25", 1, 1, { RDATA_WF_TEXT }, { RDATA_ZF_TEXT } }, /* 20 */ { TYPE_ISDN, "ISDN", 1, 2, { RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_TEXT, RDATA_ZF_TEXT } }, /* 21 */ { TYPE_RT, "RT", 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 22 */ { TYPE_NSAP, "NSAP", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_NSAP } }, /* 23 */ { TYPE_NSAP_PTR, "NSAP-PTR", 1, 1, { RDATA_WF_TEXT }, { RDATA_ZF_UNQUOTED } }, /* 24 */ { TYPE_SIG, "SIG", 9, 9, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_RRTYPE, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_PERIOD, RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_LITERAL_DNAME, RDATA_ZF_BASE64 } }, /* 25 */ { TYPE_KEY, "KEY", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 26 */ { TYPE_PX, "PX", 3, 3, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 27 */ { TYPE_GPOS, "GPOS", 3, 3, { RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_UNQUOTED, RDATA_ZF_UNQUOTED, RDATA_ZF_UNQUOTED} }, /* 28 */ { TYPE_AAAA, "AAAA", 1, 1, { RDATA_WF_AAAA }, { RDATA_ZF_AAAA } }, /* 29 */ { TYPE_LOC, "LOC", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_LOC } }, /* 30 */ { TYPE_NXT, "NXT", 2, 2, { RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_DNAME, RDATA_ZF_NXT } }, /* 31 */ { TYPE_EID, "EID", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_HEX } }, /* 32 */ { TYPE_NIMLOC, "NIMLOC", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_HEX } }, /* 33 */ { TYPE_SRV, "SRV", 4, 4, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 34 */ { TYPE_ATMA, "ATMA", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_ATMA } }, /* 35 */ { TYPE_NAPTR, "NAPTR", 6, 6, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_DNAME } }, /* 36 */ { TYPE_KX, "KX", 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 37 */ { TYPE_CERT, "CERT", 4, 4, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_CERTIFICATE_TYPE, RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 38 */ { TYPE_A6, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 39 */ { TYPE_DNAME, "DNAME", 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 40 */ { TYPE_SINK, "SINK", 3, 3, { RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BASE64 } }, /* 41 */ { TYPE_OPT, "OPT", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 42 */ { TYPE_APL, "APL", 0, MAXRDATALEN, { RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL }, { RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL } }, /* 43 */ { TYPE_DS, "DS", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 44 */ { TYPE_SSHFP, "SSHFP", 3, 3, { RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 45 */ { TYPE_IPSECKEY, "IPSECKEY", 4, 5, { RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_IPSECGATEWAY, RDATA_WF_BINARY }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_IPSECGATEWAY, RDATA_ZF_BASE64 } }, /* 46 */ { TYPE_RRSIG, "RRSIG", 9, 9, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_RRTYPE, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_PERIOD, RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_LITERAL_DNAME, RDATA_ZF_BASE64 } }, /* 47 */ { TYPE_NSEC, "NSEC", 2, 2, { RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_LITERAL_DNAME, RDATA_ZF_NSEC } }, /* 48 */ { TYPE_DNSKEY, "DNSKEY", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 49 */ { TYPE_DHCID, "DHCID", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_BASE64 } }, /* 50 */ { TYPE_NSEC3, "NSEC3", 6, 6, { RDATA_WF_BYTE, /* hash type */ RDATA_WF_BYTE, /* flags */ RDATA_WF_SHORT, /* iterations */ RDATA_WF_BINARYWITHLENGTH, /* salt */ RDATA_WF_BINARYWITHLENGTH, /* next hashed name */ RDATA_WF_BINARY /* type bitmap */ }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_SHORT, RDATA_ZF_HEX_LEN, RDATA_ZF_BASE32, RDATA_ZF_NSEC } }, /* 51 */ { TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, { RDATA_WF_BYTE, /* hash type */ RDATA_WF_BYTE, /* flags */ RDATA_WF_SHORT, /* iterations */ RDATA_WF_BINARYWITHLENGTH /* salt */ }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_SHORT, RDATA_ZF_HEX_LEN } }, /* 52 */ { TYPE_TLSA, "TLSA", 4, 4, { RDATA_WF_BYTE, /* usage */ RDATA_WF_BYTE, /* selector */ RDATA_WF_BYTE, /* matching type */ RDATA_WF_BINARY }, /* certificate association data */ { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 53 */ { TYPE_SMIMEA, "SMIMEA", 4, 4, { RDATA_WF_BYTE, /* usage */ RDATA_WF_BYTE, /* selector */ RDATA_WF_BYTE, /* matching type */ RDATA_WF_BINARY }, /* certificate association data */ { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 54 */ { 54, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 55 - HIP [RFC 5205] */ { TYPE_HIP, "HIP", 1, MAXRDATALEN, { RDATA_WF_HIP, RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME , RDATA_WF_LITERAL_DNAME }, { RDATA_ZF_HIP, RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME , RDATA_ZF_LITERAL_DNAME } }, /* 56 - NINFO */ { TYPE_NINFO, "NINFO", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 57 - RKEY */ { TYPE_RKEY, "RKEY", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 58 - TALINK */ { TYPE_TALINK, "TALINK", 2, 2, { RDATA_WF_LITERAL_DNAME, RDATA_WF_LITERAL_DNAME }, { RDATA_ZF_LITERAL_DNAME, RDATA_ZF_LITERAL_DNAME } }, /* 59 - CDS */ { TYPE_CDS, "CDS", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 60 - CDNSKEY */ { TYPE_CDNSKEY, "CDNSKEY", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 61 - OPENPGPKEY */ { TYPE_OPENPGPKEY, "OPENPGPKEY", 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_BASE64 } }, /* 62 - CSYNC */ { TYPE_CSYNC, "CSYNC", 3, 3, { RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_BINARY }, { RDATA_ZF_LONG, RDATA_ZF_SHORT, RDATA_ZF_NSEC } }, /* 63 - ZONEMD */ { TYPE_ZONEMD, "ZONEMD", 4, 4, { RDATA_WF_LONG, /* serial */ RDATA_WF_BYTE, /* scheme */ RDATA_WF_BYTE, /* hash Algorithm */ RDATA_WF_BINARY }, /* digest */ { RDATA_ZF_PERIOD, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 64 - SVCB */ { TYPE_SVCB, "SVCB", 2, MAXRDATALEN, { RDATA_WF_SHORT /* SvcFieldPriority */ , RDATA_WF_UNCOMPRESSED_DNAME /* SvcDomainName */ , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM /* SvcFieldValue */ , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM }, { RDATA_ZF_SHORT , RDATA_ZF_DNAME , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM } }, /* 65 - HTTPS */ { TYPE_HTTPS, "HTTPS", 2, MAXRDATALEN, { RDATA_WF_SHORT /* SvcFieldPriority */ , RDATA_WF_UNCOMPRESSED_DNAME /* SvcDomainName */ , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM /* SvcFieldValue */ , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM , RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM, RDATA_WF_SVCPARAM }, { RDATA_ZF_SHORT , RDATA_ZF_DNAME , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM , RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM, RDATA_ZF_SVCPARAM } }, /* 66 */ { TYPE_DSYNC, "DSYNC", 4, 4, { RDATA_WF_SHORT , RDATA_WF_BYTE, RDATA_WF_SHORT , RDATA_WF_LITERAL_DNAME }, { RDATA_ZF_RRTYPE, RDATA_ZF_BYTE, RDATA_ZF_SHORT , RDATA_ZF_LITERAL_DNAME } }, /* 67 */ { 67, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 68 */ { 68, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 69 */ { 69, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 70 */ { 70, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 71 */ { 71, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 72 */ { 72, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 73 */ { 73, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 74 */ { 74, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 75 */ { 75, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 76 */ { 76, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 77 */ { 77, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 78 */ { 78, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 79 */ { 79, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 80 */ { 80, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 81 */ { 81, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 82 */ { 82, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 83 */ { 83, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 84 */ { 84, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 85 */ { 85, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 86 */ { 86, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 87 */ { 87, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 88 */ { 88, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 89 */ { 89, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 90 */ { 90, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 91 */ { 91, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 92 */ { 92, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 93 */ { 93, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 94 */ { 94, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 95 */ { 95, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 96 */ { 96, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 97 */ { 97, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 98 */ { 98, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 99 */ { TYPE_SPF, "SPF", 1, MAXRDATALEN, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 100 - UINFO */ { 100, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 101 - UID */ { 101, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 102 - GID */ { 102, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 103 - UNSPEC */ { 103, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 104 */ { TYPE_NID, "NID", 2, 2, { RDATA_WF_SHORT, RDATA_WF_ILNP64 }, { RDATA_ZF_SHORT, RDATA_ZF_ILNP64 } }, /* 105 */ { TYPE_L32, "L32", 2, 2, { RDATA_WF_SHORT, RDATA_WF_A }, { RDATA_ZF_SHORT, RDATA_ZF_A } }, /* 106 */ { TYPE_L64, "L64", 2, 2, { RDATA_WF_SHORT, RDATA_WF_ILNP64 }, { RDATA_ZF_SHORT, RDATA_ZF_ILNP64 } }, /* 107 */ { TYPE_LP, "LP", 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 108 */ { TYPE_EUI48, "EUI48", 1, 1, { RDATA_WF_EUI48 }, { RDATA_ZF_EUI48 } }, /* 109 */ { TYPE_EUI64, "EUI64", 1, 1, { RDATA_WF_EUI64 }, { RDATA_ZF_EUI64 } }, /* 110 */ { 110, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 111 */ { 111, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 112 */ { 112, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 113 */ { 113, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 114 */ { 114, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 115 */ { 115, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 116 */ { 116, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 117 */ { 117, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 118 */ { 118, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 119 */ { 119, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 120 */ { 120, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 121 */ { 121, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 122 */ { 122, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 123 */ { 123, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 124 */ { 124, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 125 */ { 125, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 126 */ { 126, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 127 */ { 127, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 128 */ { 128, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 129 */ { 129, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 130 */ { 130, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 131 */ { 131, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 132 */ { 132, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 133 */ { 133, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 134 */ { 134, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 135 */ { 135, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 136 */ { 136, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 137 */ { 137, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 138 */ { 138, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 139 */ { 139, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 140 */ { 140, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 141 */ { 141, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 142 */ { 142, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 143 */ { 143, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 144 */ { 144, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 145 */ { 145, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 146 */ { 146, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 147 */ { 147, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 148 */ { 148, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 149 */ { 149, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 150 */ { 150, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 151 */ { 151, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 152 */ { 152, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 153 */ { 153, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 154 */ { 154, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 155 */ { 155, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 156 */ { 156, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 157 */ { 157, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 158 */ { 158, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 159 */ { 159, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 160 */ { 160, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 161 */ { 161, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 162 */ { 162, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 163 */ { 163, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 164 */ { 164, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 165 */ { 165, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 166 */ { 166, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 167 */ { 167, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 168 */ { 168, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 169 */ { 169, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 170 */ { 170, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 171 */ { 171, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 172 */ { 172, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 173 */ { 173, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 174 */ { 174, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 175 */ { 175, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 176 */ { 176, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 177 */ { 177, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 178 */ { 178, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 179 */ { 179, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 180 */ { 180, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 181 */ { 181, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 182 */ { 182, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 183 */ { 183, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 184 */ { 184, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 185 */ { 185, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 186 */ { 186, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 187 */ { 187, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 188 */ { 188, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 189 */ { 189, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 190 */ { 190, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 191 */ { 191, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 192 */ { 192, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 193 */ { 193, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 194 */ { 194, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 195 */ { 195, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 196 */ { 196, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 197 */ { 197, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 198 */ { 198, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 199 */ { 199, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 200 */ { 200, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 201 */ { 201, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 202 */ { 202, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 203 */ { 203, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 204 */ { 204, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 205 */ { 205, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 206 */ { 206, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 207 */ { 207, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 208 */ { 208, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 209 */ { 209, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 210 */ { 210, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 211 */ { 211, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 212 */ { 212, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 213 */ { 213, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 214 */ { 214, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 215 */ { 215, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 216 */ { 216, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 217 */ { 217, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 218 */ { 218, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 219 */ { 219, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 220 */ { 220, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 221 */ { 221, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 222 */ { 222, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 223 */ { 223, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 224 */ { 224, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 225 */ { 225, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 226 */ { 226, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 227 */ { 227, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 228 */ { 228, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 229 */ { 229, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 230 */ { 230, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 231 */ { 231, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 232 */ { 232, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 233 */ { 233, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 234 */ { 234, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 235 */ { 235, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 236 */ { 236, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 237 */ { 237, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 238 */ { 238, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 239 */ { 239, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 240 */ { 240, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 241 */ { 241, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 242 */ { 242, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 243 */ { 243, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 244 */ { 244, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 245 */ { 245, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 246 */ { 246, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 247 */ { 247, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 248 */ { 248, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 249 - TKEY [RFC 2930] */ { 249, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 250 - TSIG [RFC 2845] */ { 250, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 251 - IXFR [RFC 1995] */ { 251, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 252 - AXFR [RFC 1035, RFC 5936] */ { 252, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 253 - MAILB [RFC 1035] */ { 253, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 254 - MAILA [RFC 1035] */ { 254, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 255 - * [RFC 1035, RFC 6895] */ { 255, NULL, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 256 - URI */ { TYPE_URI, "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", 3, 3, { RDATA_WF_BYTE, RDATA_WF_TEXT, RDATA_WF_LONG_TEXT }, { RDATA_ZF_BYTE, RDATA_ZF_TAG, RDATA_ZF_LONG_TEXT } }, /* 258 - AVC */ { TYPE_AVC, "AVC", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 259 - DOA */ { TYPE_DOA, "DOA", 5, 5, { RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_BYTE, RDATA_WF_TEXT, RDATA_WF_BINARY }, { RDATA_ZF_LONG, RDATA_ZF_LONG, RDATA_ZF_BYTE, RDATA_ZF_TEXT, RDATA_ZF_BASE64 } }, /* 260 - AMTRELAY */ { TYPE_AMTRELAY, "AMTRELAY", 3, 3, { RDATA_WF_BYTE, RDATA_WF_BYTE , RDATA_WF_AMTRELAY_RELAY }, { RDATA_ZF_BYTE, RDATA_ZF_AMTRELAY_D_TYPE, RDATA_ZF_AMTRELAY_RELAY } }, /* 261 - RESINFO */ { TYPE_RESINFO, "RESINFO", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_UNQUOTEDS } }, /* 262 - WALLET */ { TYPE_WALLET, "WALLET", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 263 - CLA */ { TYPE_CLA, "CLA", 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 264 - IPN */ { TYPE_IPN, "IPN", 1, 1, { RDATA_WF_LONGLONG }, { RDATA_ZF_LONGLONG } }, /* 32768 - TA */ { TYPE_TA, "TA", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 32769 */ { TYPE_DLV, "DLV", 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, }; rrtype_descriptor_type * rrtype_descriptor_by_type(uint16_t type) { if (type < RRTYPE_DESCRIPTORS_LENGTH) return &rrtype_descriptors[type]; else if (type == TYPE_DLV) return &rrtype_descriptors[PSEUDO_TYPE_DLV]; else if (type == TYPE_TA) return &rrtype_descriptors[PSEUDO_TYPE_TA]; return &rrtype_descriptors[0]; } rrtype_descriptor_type * rrtype_descriptor_by_name(const char *name) { int i; for (i = 0; i < RRTYPE_DESCRIPTORS_LENGTH; ++i) { if (rrtype_descriptors[i].name && strcasecmp(rrtype_descriptors[i].name, name) == 0) { return &rrtype_descriptors[i]; } } if (rrtype_descriptors[PSEUDO_TYPE_DLV].name && strcasecmp(rrtype_descriptors[PSEUDO_TYPE_DLV].name, name) == 0) { return &rrtype_descriptors[PSEUDO_TYPE_DLV]; } return NULL; } const char * rrtype_to_string(uint16_t rrtype) { static char buf[20]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); if (descriptor->name) { return descriptor->name; } else { snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype); return buf; } } /* * Lookup the type in the ztypes lookup table. If not found, check if * the type uses the "TYPExxx" notation for unknown types. * * Return 0 if no type matches. */ uint16_t rrtype_from_string(const char *name) { char *end; long rrtype; rrtype_descriptor_type *entry; /* Because this routine is called during zone parse for every record, * we optimise for frequently occurring records. * Also, we optimise for 'IN' and numbers are not rr types, because * during parse this routine is called for every rr class and TTL * to determine that it is not an RR type */ switch(name[0]) { case 'r': case 'R': if(strcasecmp(name+1, "RSIG") == 0) return TYPE_RRSIG; break; case 'n': case 'N': switch(name[1]) { case 's': case 'S': switch(name[2]) { case 0: return TYPE_NS; case 'e': case 'E': if(strcasecmp(name+2, "EC") == 0) return TYPE_NSEC; if(strcasecmp(name+2, "EC3") == 0) return TYPE_NSEC3; if(strcasecmp(name+2, "EC3PARAM") == 0) return TYPE_NSEC3PARAM; break; } break; } break; case 'd': case 'D': switch(name[1]) { case 's': case 'S': if(name[2]==0) return TYPE_DS; break; case 'n': case 'N': if(strcasecmp(name+2, "SKEY") == 0) return TYPE_DNSKEY; break; } break; case 'a': case 'A': switch(name[1]) { case 0: return TYPE_A; case 'a': case 'A': if(strcasecmp(name+2, "AA") == 0) return TYPE_AAAA; break; } break; case 's': case 'S': if(strcasecmp(name+1, "OA") == 0) return TYPE_SOA; break; case 't': case 'T': if(strcasecmp(name+1, "XT") == 0) return TYPE_TXT; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return 0; /* no RR types start with 0-9 */ case 'i': case 'I': switch(name[1]) { case 'n': case 'N': return 0; /* 'IN' is a class not a type */ } break; } entry = rrtype_descriptor_by_name(name); if (entry) { return entry->type; } if (strlen(name) < 5) return 0; if (strncasecmp(name, "TYPE", 4) != 0) return 0; if (!isdigit((unsigned char)name[4])) return 0; /* The rest from the string must be a number. */ rrtype = strtol(name + 4, &end, 10); if (*end != '\0') return 0; if (rrtype < 0 || rrtype > 65535L) return 0; return (uint16_t) rrtype; } const char * rrclass_to_string(uint16_t rrclass) { static char buf[20]; lookup_table_type *entry = lookup_by_id(dns_rrclasses, rrclass); if (entry) { assert(strlen(entry->name) < sizeof(buf)); strlcpy(buf, entry->name, sizeof(buf)); } else { snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass); } return buf; } uint16_t rrclass_from_string(const char *name) { char *end; long rrclass; lookup_table_type *entry; entry = lookup_by_name(dns_rrclasses, name); if (entry) { return (uint16_t) entry->id; } if (strlen(name) < 6) return 0; if (strncasecmp(name, "CLASS", 5) != 0) return 0; if (!isdigit((unsigned char)name[5])) return 0; /* The rest from the string must be a number. */ rrclass = strtol(name + 5, &end, 10); if (*end != '\0') return 0; if (rrclass < 0 || rrclass > 65535L) return 0; return (uint16_t) rrclass; } nsd-4.12.0/dname.h0000644000175000017500000002275615002373054013246 0ustar mozziemozzie/* * dname.h -- Domain name handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DNAME_H #define DNAME_H #include #include #include "buffer.h" #include "region-allocator.h" #include "dns.h" /* for MAXDOMAINLEN */ #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE) #define DNAME_NORMALIZE toupper #else #define DNAME_NORMALIZE tolower #endif /* * Domain names stored in memory add some additional information to be * able to quickly index and compare by label. */ typedef struct dname dname_type; struct dname { /* * The size (in bytes) of the domain name in wire format. */ uint8_t name_size; /* * The number of labels in this domain name (including the * root label). */ uint8_t label_count; /* uint8_t label_offsets[label_count]; uint8_t name[name_size]; */ }; /* * Construct a new domain name based on NAME in wire format. NAME * cannot contain compression pointers. * * Pre: NAME != NULL. */ const dname_type *dname_make(region_type *region, const uint8_t *name, int normalize); /* * Construct a new domain name based on wire format dname stored at * PACKET's current position. Compression pointers are followed. The * PACKET's current position is changed to the end of the wire format * dname or set to just after the first compression pointer. */ const dname_type *dname_make_from_packet(region_type *region, buffer_type *packet, int allow_pointers, int normalize); /* * parse wireformat from packet (following pointers) into the * given buffer. Returns length in buffer or 0 on error. * buffer must be MAXDOMAINLEN+1 long. */ int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers); /* * Construct a new domain name based on the ASCII representation NAME. * If ORIGIN is not NULL and NAME is not terminated by a "." the * ORIGIN is appended to the result. NAME can contain escape * sequences. * * Returns NULL on failure. Otherwise a newly allocated domain name * is returned. * * Pre: name != NULL. */ const dname_type *dname_parse(region_type *region, const char *name); /* * parse ascii string to wireformat domain name (without compression ptrs) * returns 0 on failure, the length of the wireformat on success. * the result is stored in the wirefmt which must be at least MAXDOMAINLEN * in size. On failure, the wirefmt can be altered. */ int dname_parse_wire(uint8_t* wirefmt, const char* name); /* * Return NULL if DNAME is NULL or a copy of DNAME otherwise. */ const dname_type *dname_copy(region_type *region, const dname_type *dname); /* * Copy the most significant LABEL_COUNT labels from dname. */ const dname_type *dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count); /* * The origin of DNAME. */ const dname_type *dname_origin(region_type *region, const dname_type *dname); /* * Return true if LEFT is a subdomain of RIGHT. */ int dname_is_subdomain(const dname_type *left, const dname_type *right); /* * Offsets into NAME for each label starting with the most * significant label (the root label, followed by the TLD, * etc). */ static inline const uint8_t * dname_label_offsets(const dname_type *dname) { return (const uint8_t *) ((const char *) dname + sizeof(dname_type)); } /* * The actual name in wire format (a sequence of label, each * prefixed by a length byte, terminated by a zero length * label). */ static inline const uint8_t * dname_name(const dname_type *dname) { return (const uint8_t *) ((const char *) dname + sizeof(dname_type) + dname->label_count * sizeof(uint8_t)); } /* * Return the label for DNAME specified by LABEL_INDEX. The first * label (LABEL_INDEX == 0) is the root label, the next label is the * TLD, etc. * * Pre: dname != NULL && label_index < dname->label_count. */ static inline const uint8_t * dname_label(const dname_type *dname, uint8_t label) { uint8_t label_index; assert(dname != NULL); assert(label < dname->label_count); label_index = dname_label_offsets(dname)[label]; assert(label_index < dname->name_size); return dname_name(dname) + label_index; } /* * Compare two domain names. The comparison defines a lexicographical * ordering based on the domain name's labels, starting with the most * significant label. * * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT > * RIGHT. The comparison is case sensitive. * * Pre: left != NULL && right != NULL * left and right are dname_type*. */ int dname_compare(const void *left, const void *right); /* * Compare two labels. The comparison defines a lexicographical * ordering based on the characters in the labels. * * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT > * RIGHT. The comparison is case sensitive. * * Pre: left != NULL && right != NULL * label_is_normal(left) && label_is_normal(right) */ int label_compare(const uint8_t *left, const uint8_t *right); /* * Returns the number of labels that match in LEFT and RIGHT, starting * with the most significant label. Because the root label always * matches, the result will always be >= 1. * * Pre: left != NULL && right != NULL */ uint8_t dname_label_match_count(const dname_type *left, const dname_type *right); /* * The total size (in bytes) allocated to store DNAME. * * Pre: dname != NULL */ static inline size_t dname_total_size(const dname_type *dname) { return (sizeof(dname_type) + ((((size_t)dname->label_count) + ((size_t)dname->name_size)) * sizeof(uint8_t))); } /* * Is LABEL a normal LABEL (not a pointer or reserved)? * * Pre: label != NULL; */ static inline int label_is_normal(const uint8_t *label) { assert(label); return (label[0] & 0xc0) == 0; } /* * Is LABEL a pointer? * * Pre: label != NULL; */ static inline int label_is_pointer(const uint8_t *label) { assert(label); return (label[0] & 0xc0) == 0xc0; } /* * LABEL's pointer location. * * Pre: label != NULL && label_is_pointer(label) */ static inline uint16_t label_pointer_location(const uint8_t *label) { assert(label); assert(label_is_pointer(label)); return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1]; } /* * Length of LABEL. * * Pre: label != NULL && label_is_normal(label) */ static inline uint8_t label_length(const uint8_t *label) { assert(label); assert(label_is_normal(label)); return label[0]; } /* * The data of LABEL. * * Pre: label != NULL && label_is_normal(label) */ static inline const uint8_t * label_data(const uint8_t *label) { assert(label); assert(label_is_normal(label)); return label + 1; } /* * Is LABEL the root label? * * Pre: label != NULL */ static inline int label_is_root(const uint8_t *label) { assert(label); return label[0] == 0; } /* * Is LABEL the wildcard label? * * Pre: label != NULL */ static inline int label_is_wildcard(const uint8_t *label) { assert(label); return label[0] == 1 && label[1] == '*'; } /* * The next label of LABEL. * * Pre: label != NULL * label_is_normal(label) * !label_is_root(label) */ static inline const uint8_t * label_next(const uint8_t *label) { assert(label); assert(label_is_normal(label)); assert(!label_is_root(label)); return label + label_length(label) + 1; } /* * Convert DNAME to its string representation. The result points to a * static buffer that is overwritten the next time this function is * invoked. * * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname * will be represented relative to ORIGIN. * * Pre: dname != NULL */ const char *dname_to_string(const dname_type *dname, const dname_type *origin); /* * Convert DNAME to its string representation. The result if written * to the provided buffer buf, which must be at least 5 times * MAXDOMAINNAMELEN. * * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname * will be represented relative to ORIGIN. * * Pre: dname != NULL */ const char *dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5]); /* * Create a dname containing the single label specified by STR * followed by the root label. */ const dname_type *dname_make_from_label(region_type *region, const uint8_t *label, const size_t length); /* * Concatenate two dnames. */ const dname_type *dname_concatenate(region_type *region, const dname_type *left, const dname_type *right); /* * Perform DNAME substitution on a name, replace src with dest. * Name must be a subdomain of src. The returned name is a subdomain of dest. * Returns NULL if the result domain name is too long. */ const dname_type *dname_replace(region_type* region, const dname_type* name, const dname_type* src, const dname_type* dest); /** Convert uncompressed wireformat dname to a string */ char* wiredname2str(const uint8_t* dname); /** convert uncompressed label to string */ char* wirelabel2str(const uint8_t* label); /** check if two uncompressed dnames of the same total length are equal */ int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len); /* Test is the name is a subdomain of the other name. Equal names return true. * Subdomain d of d2 returns true, otherwise false. The names are in * wireformat, uncompressed. Does not perform canonicalization, it is case * sensitive. */ int is_dname_subdomain_of_case(const uint8_t* d, unsigned int len, const uint8_t* d2, unsigned int len2); #endif /* DNAME_H */ nsd-4.12.0/dname.c0000644000175000017500000003212115002373054013224 0ustar mozziemozzie/* * dname.c -- Domain name handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "dns.h" #include "dname.h" #include "query.h" const dname_type * dname_make(region_type *region, const uint8_t *name, int normalize) { size_t name_size = 0; uint8_t label_offsets[MAXDOMAINLEN]; uint8_t label_count = 0; const uint8_t *label = name; dname_type *result; ssize_t i; assert(name); while (1) { if (label_is_pointer(label)) return NULL; label_offsets[label_count] = (uint8_t) (label - name); ++label_count; name_size += label_length(label) + 1; if (label_is_root(label)) break; label = label_next(label); } if (name_size > MAXDOMAINLEN) return NULL; assert(label_count <= MAXDOMAINLEN / 2 + 1); /* Reverse label offsets. */ for (i = 0; i < label_count / 2; ++i) { uint8_t tmp = label_offsets[i]; label_offsets[i] = label_offsets[label_count - i - 1]; label_offsets[label_count - i - 1] = tmp; } result = (dname_type *) region_alloc( region, (sizeof(dname_type) + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t))); result->name_size = name_size; result->label_count = label_count; memcpy((uint8_t *) dname_label_offsets(result), label_offsets, label_count * sizeof(uint8_t)); if (normalize) { uint8_t *dst = (uint8_t *) dname_name(result); const uint8_t *src = name; while (!label_is_root(src)) { ssize_t len = label_length(src); *dst++ = *src++; for (i = 0; i < len; ++i) { *dst++ = DNAME_NORMALIZE((unsigned char)*src++); } } *dst = *src; } else { memcpy((uint8_t *) dname_name(result), name, name_size * sizeof(uint8_t)); } return result; } const dname_type * dname_make_from_packet(region_type *region, buffer_type *packet, int allow_pointers, int normalize) { uint8_t buf[MAXDOMAINLEN + 1]; if(!dname_make_wire_from_packet(buf, packet, allow_pointers)) return 0; return dname_make(region, buf, normalize); } int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers) { int done = 0; uint8_t visited[(MAX_PACKET_SIZE+7)/8]; size_t dname_length = 0; const uint8_t *label; ssize_t mark = -1; if(sizeof(visited)<(buffer_limit(packet)+7)/8) memset(visited, 0, sizeof(visited)); else memset(visited, 0, (buffer_limit(packet)+7)/8); while (!done) { if (!buffer_available(packet, 1)) { /* error("dname out of bounds"); */ return 0; } if (get_bit(visited, buffer_position(packet))) { /* error("dname loops"); */ return 0; } set_bit(visited, buffer_position(packet)); label = buffer_current(packet); if (label_is_pointer(label)) { size_t pointer; if (!allow_pointers) { return 0; } if (!buffer_available(packet, 2)) { /* error("dname pointer out of bounds"); */ return 0; } pointer = label_pointer_location(label); if (pointer >= buffer_limit(packet)) { /* error("dname pointer points outside packet"); */ return 0; } buffer_skip(packet, 2); if (mark == -1) { mark = buffer_position(packet); } buffer_set_position(packet, pointer); } else if (label_is_normal(label)) { size_t length = label_length(label) + 1; done = label_is_root(label); if (!buffer_available(packet, length)) { /* error("dname label out of bounds"); */ return 0; } if (dname_length + length >= MAXDOMAINLEN+1) { /* error("dname too large"); */ return 0; } buffer_read(packet, buf + dname_length, length); dname_length += length; } else { /* error("bad label type"); */ return 0; } } if (mark != -1) { buffer_set_position(packet, mark); } return dname_length; } const dname_type * dname_parse(region_type *region, const char *name) { uint8_t dname[MAXDOMAINLEN]; if(!dname_parse_wire(dname, name)) return 0; return dname_make(region, dname, 1); } int dname_parse_wire(uint8_t* dname, const char* name) { const uint8_t *s = (const uint8_t *) name; uint8_t *h; uint8_t *p; uint8_t *d = dname; size_t label_length; if (strcmp(name, ".") == 0) { /* Root domain. */ dname[0] = 0; return 1; } for (h = d, p = h + 1; *s; ++s, ++p) { if (p - dname >= MAXDOMAINLEN) { return 0; } switch (*s) { case '.': if (p == h + 1) { /* Empty label. */ return 0; } else { label_length = p - h - 1; if (label_length > MAXLABELLEN) { return 0; } *h = label_length; h = p; } break; case '\\': /* Handle escaped characters (RFC1035 5.1) */ if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) { int val = (hexdigit_to_int(s[1]) * 100 + hexdigit_to_int(s[2]) * 10 + hexdigit_to_int(s[3])); if (0 <= val && val <= 255) { s += 3; *p = val; } else { *p = *++s; } } else if (s[1] != '\0') { *p = *++s; } break; default: *p = *s; break; } } if (p != h + 1) { /* Terminate last label. */ label_length = p - h - 1; if (label_length > MAXLABELLEN) { return 0; } *h = label_length; h = p; p++; } /* Add root label. */ if (h - dname >= MAXDOMAINLEN) { return 0; } *h = 0; return p-dname; } const dname_type * dname_copy(region_type *region, const dname_type *dname) { return (dname_type *) region_alloc_init( region, dname, dname_total_size(dname)); } const dname_type * dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count) { if (!dname) return NULL; if (label_count == 0) { /* Always copy the root label. */ label_count = 1; } assert(label_count <= dname->label_count); return dname_make(region, dname_label(dname, label_count - 1), 0); } const dname_type * dname_origin(region_type *region, const dname_type *dname) { return dname_partial_copy(region, dname, dname->label_count - 1); } int dname_is_subdomain(const dname_type *left, const dname_type *right) { uint8_t i; if (left->label_count < right->label_count) return 0; for (i = 1; i < right->label_count; ++i) { if (label_compare(dname_label(left, i), dname_label(right, i)) != 0) return 0; } return 1; } int dname_compare(const void *a, const void *b) { int result; uint8_t label_count; uint8_t i; const dname_type *left, *right; left = a; right = b; assert(left); assert(right); if (left == right) { return 0; } label_count = (left->label_count <= right->label_count ? left->label_count : right->label_count); /* Skip the root label by starting at label 1. */ for (i = 1; i < label_count; ++i) { result = label_compare(dname_label(left, i), dname_label(right, i)); if (result) { return result; } } /* Dname with the fewest labels is "first". */ /* the subtraction works because the size of int is much larger than * the label count and the values won't wrap around */ return (int) left->label_count - (int) right->label_count; } int label_compare(const uint8_t *left, const uint8_t *right) { int left_length; int right_length; size_t size; int result; assert(left); assert(right); assert(label_is_normal(left)); assert(label_is_normal(right)); left_length = label_length(left); right_length = label_length(right); size = left_length < right_length ? left_length : right_length; result = memcmp(label_data(left), label_data(right), size); if (result) { return result; } else { /* the subtraction works because the size of int is much * larger than the lengths and the values won't wrap around */ return (int) left_length - (int) right_length; } } uint8_t dname_label_match_count(const dname_type *left, const dname_type *right) { uint8_t i; assert(left); assert(right); for (i = 1; i < left->label_count && i < right->label_count; ++i) { if (label_compare(dname_label(left, i), dname_label(right, i)) != 0) { return i; } } return i; } const char * dname_to_string(const dname_type *dname, const dname_type *origin) { static char buf[MAXDOMAINLEN * 5]; return dname_to_string_buf(dname, origin, buf); } const char * dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5]) { size_t i; size_t labels_to_convert = dname->label_count - 1; int absolute = 1; char *dst; const uint8_t *src; if (dname->label_count == 1) { strlcpy(buf, ".", MAXDOMAINLEN * 5); return buf; } if (origin && dname_is_subdomain(dname, origin)) { int common_labels = dname_label_match_count(dname, origin); labels_to_convert = dname->label_count - common_labels; absolute = 0; } dst = buf; src = dname_name(dname); for (i = 0; i < labels_to_convert; ++i) { size_t len = label_length(src); size_t j; ++src; for (j = 0; j < len; ++j) { uint8_t ch = *src++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { *dst++ = ch; } else if (ch == '.' || ch == '\\') { *dst++ = '\\'; *dst++ = ch; } else { snprintf(dst, 5, "\\%03u", (unsigned int)ch); dst += 4; } } *dst++ = '.'; } if (absolute) { *dst = '\0'; } else { *--dst = '\0'; } return buf; } const dname_type * dname_make_from_label(region_type *region, const uint8_t *label, const size_t length) { uint8_t temp[MAXLABELLEN + 2]; assert(length > 0 && length <= MAXLABELLEN); temp[0] = length; memcpy(temp + 1, label, length * sizeof(uint8_t)); temp[length + 1] = '\000'; return dname_make(region, temp, 1); } const dname_type * dname_concatenate(region_type *region, const dname_type *left, const dname_type *right) { uint8_t temp[MAXDOMAINLEN]; assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN); memcpy(temp, dname_name(left), left->name_size - 1); memcpy(temp + left->name_size - 1, dname_name(right), right->name_size); return dname_make(region, temp, 0); } const dname_type * dname_replace(region_type* region, const dname_type* name, const dname_type* src, const dname_type* dest) { /* nomenclature: name is said to be .. x can be null. */ dname_type* res; int x_labels = name->label_count - src->label_count; int x_len = name->name_size - src->name_size; int i; assert(dname_is_subdomain(name, src)); /* check if final size is acceptable */ if(x_len+dest->name_size > MAXDOMAINLEN) return NULL; res = (dname_type*)region_alloc(region, sizeof(dname_type) + (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) *sizeof(uint8_t)); res->name_size = x_len+dest->name_size; res->label_count = x_labels+dest->label_count; for(i=0; ilabel_count; i++) ((uint8_t*)dname_label_offsets(res))[i] = dname_label_offsets(dest)[i] + x_len; for(i=dest->label_count; ilabel_count; i++) ((uint8_t*)dname_label_offsets(res))[i] = dname_label_offsets(name)[i - dest->label_count + src->label_count]; memcpy((uint8_t*)dname_name(res), dname_name(name), x_len); memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size); assert(dname_is_subdomain(res, dest)); return res; } char* wirelabel2str(const uint8_t* label) { static char buf[MAXDOMAINLEN*5+3]; char* p = buf; uint8_t lablen; lablen = *label++; while(lablen--) { uint8_t ch = *label++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { *p++ = ch; } else if (ch == '.' || ch == '\\') { *p++ = '\\'; *p++ = ch; } else { snprintf(p, 5, "\\%03u", (unsigned int)ch); p += 4; } } *p++ = 0; return buf; } char* wiredname2str(const uint8_t* dname) { static char buf[MAXDOMAINLEN*5+3]; char* p = buf; uint8_t lablen; if(*dname == 0) { strlcpy(buf, ".", sizeof(buf)); return buf; } lablen = *dname++; while(lablen) { while(lablen--) { uint8_t ch = *dname++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { *p++ = ch; } else if (ch == '.' || ch == '\\') { *p++ = '\\'; *p++ = ch; } else { snprintf(p, 5, "\\%03u", (unsigned int)ch); p += 4; } } lablen = *dname++; *p++ = '.'; } *p++ = 0; return buf; } int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len) { uint8_t i, lablen; while(len > 0) { /* check labellen */ if(*a != *b) return 0; lablen = *a++; b++; len--; /* malformed or compression ptr; we stop scanning */ if((lablen & 0xc0) || len < lablen) return (memcmp(a, b, len) == 0); /* check the label, lowercased */ for(i=0; i len2, for d=a.example.com. and d2=example.com. */ /* trailing portion must be exactly name d2. */ if(memcmp(d+len-len2, d2, len2) != 0) return 0; /* that must also be a label point */ i=0; while(i < len) { if(i == len-len2) return 1; i += d[i]; i += 1; } /* The trailing portion is not at a label point. */ return 0; } nsd-4.12.0/difffile.h0000644000175000017500000001267115002373054013725 0ustar mozziemozzie/* * difffile.h - nsd.diff file handling header file. Read/write diff files. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DIFFFILE_H #define DIFFFILE_H #include "rbtree.h" #include "namedb.h" #include "options.h" #include "udb.h" struct nsd; struct nsdst; #define DIFF_PART_XXFR ('X'<<24 | 'X'<<16 | 'F'<<8 | 'R') #define DIFF_PART_XFRF ('X'<<24 | 'F'<<16 | 'R'<<8 | 'F') #define DIFF_NOT_COMMITTED (0u) /* XFR not (yet) committed to disk */ #define DIFF_COMMITTED (1u<<0) /* XFR committed to disk */ #define DIFF_CORRUPT (1u<<1) /* XFR corrupt */ #define DIFF_INCONSISTENT (1u<<2) /* IXFR cannot be applied */ #define DIFF_VERIFIED (1u<<3) /* XFR already verified */ /* write an xfr packet data to the diff file, type=IXFR. The diff file is created if necessary, with initial header(notcommitted). */ void diff_write_packet(const char* zone, const char* pat, uint32_t old_serial, uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len, struct nsd* nsd, uint64_t filenumber); /* * Overwrite header of diff file with committed vale and other data. * append log string. */ void diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial, uint32_t num_parts, uint8_t commit, const char* log_msg, struct nsd* nsd, uint64_t filenumber); /* * Overwrite committed value of diff file with discarded to ensure diff * file is not reapplied on reload. */ void diff_update_commit(const char* zone, uint8_t commit, struct nsd* nsd, uint64_t filenumber); /* * These functions read parts of the diff file. */ int diff_read_32(FILE *in, uint32_t* result); int diff_read_8(FILE *in, uint8_t* result); int diff_read_str(FILE* in, char* buf, size_t len); /* delete the RRs for a zone from memory */ void delete_zone_rrs(namedb_type* db, zone_type* zone); /* delete an RR */ int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, region_type* temp_region, int* softfail); /* add an RR */ int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, int* softfail); /* apply the xfr file identified by xfrfilenr to zone */ int apply_ixfr_for_zone(struct nsd* nsd, zone_type* zone, FILE* in, struct nsd_options* opt, udb_base* taskudb, uint32_t xfrfilenr); enum soainfo_hint { soainfo_ok, soainfo_gone, soainfo_bad }; /* task udb structure */ struct task_list_d { /** next task in list */ udb_rel_ptr next; /** task type */ enum { /** expire or un-expire a zone */ task_expire, /** apply an ixfr or axfr to a zone */ task_apply_xfr, /** soa info for zone */ task_soa_info, /** check mtime of zonefiles and read them, done on SIGHUP */ task_check_zonefiles, /** write zonefiles (if changed) */ task_write_zonefiles, /** set verbosity */ task_set_verbosity, /** add a zone */ task_add_zone, /** delete zone */ task_del_zone, /** add TSIG key */ task_add_key, /** delete TSIG key */ task_del_key, /** add pattern */ task_add_pattern, /** delete pattern */ task_del_pattern, /** options change */ task_opt_change, /** zonestat increment */ task_zonestat_inc, /** cookies */ task_cookies, } task_type; uint32_t size; /* size of this struct */ /** soainfo: zonename dname, soaRR wireform, yesno is soainfo_hint */ /** expire: zonename, boolyesno */ /** apply_xfr: zonename, serials, yesno is filenamecounter */ uint32_t oldserial, newserial; /** general variable. for some used to see if zname is present. */ uint64_t yesno; struct dname zname[0]; }; #define TASKLIST(ptr) ((struct task_list_d*)UDB_PTR(ptr)) /** create udb for tasks */ struct udb_base* task_file_create(const char* file); void task_remap(udb_base* udb); void task_process_sync(udb_base* udb); void task_clear(udb_base* udb); void task_new_soainfo(udb_base* udb, udb_ptr* last, struct zone* z, enum soainfo_hint hint); void task_new_expire(udb_base* udb, udb_ptr* last, const struct dname* z, int expired); void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone); void task_new_write_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone); void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v); void task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone, const char* pattern, unsigned zonestatid); void task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname); void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key); void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name); void task_new_add_pattern(udb_base* udb, udb_ptr* last, struct pattern_options* p); void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name); void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt); void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz); void task_new_cookies(udb_base* udb, udb_ptr* last, int answer_cookie, size_t cookie_count, void* cookie_secrets); int task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* zone, uint32_t old_serial, uint32_t new_serial, uint64_t filenumber); void task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *task); void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task); void task_process_expire(namedb_type* db, struct task_list_d* task); #endif /* DIFFFILE_H */ nsd-4.12.0/difffile.c0000644000175000017500000017235515002373054013726 0ustar mozziemozzie/* * difffile.c - DIFF file handling source code. Read and write diff files. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include "difffile.h" #include "xfrd-disk.h" #include "util.h" #include "packet.h" #include "rdata.h" #include "udb.h" #include "nsec3.h" #include "nsd.h" #include "rrl.h" #include "ixfr.h" #include "zonec.h" #include "xfrd-catalog-zones.h" static int write_64(FILE *out, uint64_t val) { return write_data(out, &val, sizeof(val)); } static int write_32(FILE *out, uint32_t val) { val = htonl(val); return write_data(out, &val, sizeof(val)); } static int write_8(FILE *out, uint8_t val) { return write_data(out, &val, sizeof(val)); } static int write_str(FILE *out, const char* str) { uint32_t len = strlen(str); if(!write_32(out, len)) return 0; return write_data(out, str, len); } void diff_write_packet(const char* zone, const char* pat, uint32_t old_serial, uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len, struct nsd* nsd, uint64_t filenumber) { FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w"); if(!df) { log_msg(LOG_ERR, "could not open transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); return; } /* if first part, first write the header */ if(seq_nr == 0) { struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { log_msg(LOG_ERR, "could not get timestamp for %s: %s", zone, strerror(errno)); } if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, 0) /* notcommitted(yet) */ || !write_32(df, 0) /* numberofparts when done */ || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_32(df, old_serial) || !write_32(df, new_serial) || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_str(df, zone) || !write_str(df, pat)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } } if(!write_32(df, DIFF_PART_XXFR) || !write_32(df, len) || !write_data(df, data, len) || !write_32(df, len)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); } fclose(df); } void diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial, uint32_t num_parts, uint8_t commit, const char* log_str, struct nsd* nsd, uint64_t filenumber) { struct timeval tv; FILE* df; if (gettimeofday(&tv, NULL) != 0) { log_msg(LOG_ERR, "could not set timestamp for %s: %s", zone, strerror(errno)); } /* overwrite the first part of the file with 'committed = 1', * as well as the end_time and number of parts. * also write old_serial and new_serial, so that a bad file mixup * will result in unusable serial numbers. */ df = xfrd_open_xfrfile(nsd, filenumber, "r+"); if(!df) { log_msg(LOG_ERR, "could not open transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); return; } if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, commit) /* committed */ || !write_32(df, num_parts) || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_32(df, old_serial) || !write_32(df, new_serial)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } /* append the log_str to the end of the file */ if(fseek(df, 0, SEEK_END) == -1) { log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } if(!write_str(df, log_str)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } fflush(df); fclose(df); } void diff_update_commit( const char* zone, uint8_t commit, struct nsd* nsd, uint64_t filenumber) { FILE *df; assert(zone != NULL); assert(nsd != NULL); assert(commit == DIFF_NOT_COMMITTED || commit == DIFF_COMMITTED || commit == DIFF_CORRUPT || commit == DIFF_INCONSISTENT || commit == DIFF_VERIFIED); df = xfrd_open_xfrfile(nsd, filenumber, "r+"); if(!df) { log_msg(LOG_ERR, "could not open transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); return; } if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, commit)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } fflush(df); fclose(df); } int diff_read_64(FILE *in, uint64_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } int diff_read_32(FILE *in, uint32_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { *result = ntohl(*result); return 1; } else { return 0; } } int diff_read_8(FILE *in, uint8_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } int diff_read_str(FILE* in, char* buf, size_t len) { uint32_t disklen; if(!diff_read_32(in, &disklen)) return 0; if(disklen >= len) return 0; if(fread(buf, disklen, 1, in) != 1) return 0; buf[disklen] = 0; return 1; } static void add_rdata_to_recyclebin(namedb_type* db, rr_type* rr) { /* add rdatas to recycle bin. */ size_t i; for(i=0; irdata_count; i++) { if(!rdata_atom_is_domain(rr->type, i)) region_recycle(db->region, rr->rdatas[i].data, rdata_atom_size(rr->rdatas[i]) + sizeof(uint16_t)); } region_recycle(db->region, rr->rdatas, sizeof(rdata_atom_type)*rr->rdata_count); } /* this routine determines if below a domain there exist names with * data (is_existing) or no names below the domain have data. */ static int has_data_below(domain_type* top) { domain_type* d = top; assert(d != NULL); /* in the canonical ordering subdomains are after this name */ d = domain_next(d); while(d != NULL && domain_is_subdomain(d, top)) { if(d->is_existing) return 1; d = domain_next(d); } return 0; } /** check if domain with 0 rrsets has become empty (nonexist) */ static domain_type* rrset_zero_nonexist_check(domain_type* domain, domain_type* ce) { /* is the node now an empty node (completely deleted) */ if(domain->rrsets == 0) { /* if there is no data below it, it becomes non existing. also empty nonterminals above it become nonexisting */ /* check for data below this node. */ if(!has_data_below(domain)) { /* nonexist this domain and all parent empty nonterminals */ domain_type* p = domain; while(p != NULL && p->rrsets == 0) { if(p == ce || has_data_below(p)) return p; p->is_existing = 0; /* fixup wildcard child of parent */ if(p->parent && p->parent->wildcard_child_closest_match == p) p->parent->wildcard_child_closest_match = domain_previous_existing_child(p); p = p->parent; } } } return NULL; } /** remove rrset. Adjusts zone params. Does not remove domain */ static void rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset) { int i; /* find previous */ rrset_type** pp = &domain->rrsets; while(*pp && *pp != rrset) { pp = &( (*pp)->next ); } if(!*pp) { /* rrset does not exist for domain */ return; } *pp = rrset->next; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s", domain_to_string(domain), rrtype_to_string(rrset_rrtype(rrset)))); /* is this a SOA rrset ? */ if(rrset->zone->soa_rrset == rrset) { rrset->zone->soa_rrset = 0; } if(rrset->zone->ns_rrset == rrset) { rrset->zone->ns_rrset = 0; } if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) { for (i = 0; i < rrset->rr_count; ++i) { if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) { rrset->zone->is_secure = 0; break; } } } /* recycle the memory space of the rrset */ for (i = 0; i < rrset->rr_count; ++i) add_rdata_to_recyclebin(db, &rrset->rrs[i]); region_recycle(db->region, rrset->rrs, sizeof(rr_type) * rrset->rr_count); rrset->rr_count = 0; region_recycle(db->region, rrset, sizeof(rrset_type)); } static int rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type, int* rdnum, char** reason) { int k, start, end; start = 0; end = num; /** * SOA RDATA comparisons in XFR are more lenient, * only serial rdata is checked. **/ if (type == TYPE_SOA) { start = 2; end = 3; } for(k = start; k < end; k++) { if(rdata_atom_is_domain(type, k)) { if(dname_compare(domain_dname(a[k].domain), domain_dname(b[k].domain))!=0) { *rdnum = k; *reason = "dname data"; return 0; } } else if(rdata_atom_is_literal_domain(type, k)) { /* literal dname, but compare case insensitive */ if(a[k].data[0] != b[k].data[0]) { *rdnum = k; *reason = "literal dname len"; return 0; /* uncompressed len must be equal*/ } if(!dname_equal_nocase((uint8_t*)(a[k].data+1), (uint8_t*)(b[k].data+1), a[k].data[0])) { *rdnum = k; *reason = "literal dname data"; return 0; } } else { /* check length */ if(a[k].data[0] != b[k].data[0]) { *rdnum = k; *reason = "rdata len"; return 0; } /* check data */ if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) { *rdnum = k; *reason = "rdata data"; return 0; } } } return 1; } static void debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass, rdata_atom_type *rdatas, ssize_t rdata_num) { int i, rd; char* reason = ""; for(i=0; i < rrset->rr_count; ++i) { if (rrset->rrs[i].type != type) { log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match " "RR num %d type %s", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), i, rrtype_to_string(rrset->rrs[i].type)); } if (rrset->rrs[i].klass != klass) { log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d " "does not match RR num %d class %d", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), klass, i, rrset->rrs[i].klass); } if (rrset->rrs[i].rdata_count != rdata_num) { log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u " "does not match RR num %d rdlen %d", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), (unsigned) rdata_num, i, (unsigned) rrset->rrs[i].rdata_count); } if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type, &rd, &reason)) { log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element " "%d differs from RR num %d rdata (%s)", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), rd, i, reason); } } } static int find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass, rdata_atom_type *rdatas, ssize_t rdata_num, int add) { int i, rd; char* reason; for(i=0; i < rrset->rr_count; ++i) { if(rrset->rrs[i].type == type && rrset->rrs[i].klass == klass && rrset->rrs[i].rdata_count == rdata_num && rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type, &rd, &reason)) { return i; } } /* this is odd. Log why rr cannot be found. */ if (!add) { debug_find_rr_num(rrset, type, klass, rdatas, rdata_num); } return -1; } #ifdef NSEC3 /* see if nsec3 deletion triggers need action */ static void nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone) { /* the RR has not actually been deleted yet, so we can inspect it */ if(!zone->nsec3_param) return; /* see if the domain was an NSEC3-domain in the chain, but no longer */ if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 && rr->owner->nsec3->nsec3_node.key && nsec3_rr_uses_params(rr, zone) && nsec3_in_chain_count(rr->owner, zone) <= 1) { domain_type* prev = nsec3_chain_find_prev(zone, rr->owner); /* remove from prehash because no longer an NSEC3 domain */ if(domain_is_prehash(db->domains, rr->owner)) prehash_del(db->domains, rr->owner); /* fixup the last in the zone */ if(rr->owner == zone->nsec3_last) zone->nsec3_last = prev; /* unlink from the nsec3tree */ zone_del_domain_in_hash_tree(zone->nsec3tree, &rr->owner->nsec3->nsec3_node); /* add previous NSEC3 to the prehash list */ if(prev && prev != rr->owner) prehash_add(db->domains, prev); else nsec3_clear_precompile(db, zone); /* this domain becomes ordinary data domain: done later */ } /* see if the rr was NSEC3PARAM that we were using */ else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) { /* clear trees, wipe hashes, wipe precompile */ nsec3_clear_precompile(db, zone); /* pick up new nsec3param (from udb, or avoid deleted rr) */ nsec3_find_zone_param(db, zone, rr, 0); /* if no more NSEC3, done */ if(!zone->nsec3_param) return; nsec3_precompile_newparam(db, zone); } } /* see if nsec3 prehash can be removed with new rrset content */ static void nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) { /* deletion of rrset already done, we can check if conditions apply */ /* see if the domain is no longer precompiled */ /* it has a hash_node, but no longer fulfills conditions */ if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 && domain->nsec3->hash_wc && domain->nsec3->hash_wc->hash.node.key && !nsec3_condition_hash(domain, zone)) { /* remove precompile */ domain->nsec3->nsec3_cover = NULL; domain->nsec3->nsec3_wcard_child_cover = NULL; domain->nsec3->nsec3_is_exact = 0; /* remove it from the hash tree */ zone_del_domain_in_hash_tree(zone->hashtree, &domain->nsec3->hash_wc->hash.node); zone_del_domain_in_hash_tree(zone->wchashtree, &domain->nsec3->hash_wc->wc.node); } if(domain != zone->apex && domain->nsec3 && domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key && (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) && !nsec3_condition_dshash(domain, zone)) { /* remove precompile */ domain->nsec3->nsec3_ds_parent_cover = NULL; domain->nsec3->nsec3_ds_parent_is_exact = 0; /* remove it from the hash tree */ zone_del_domain_in_hash_tree(zone->dshashtree, &domain->nsec3->ds_parent_hash->node); } } /* see if domain needs to get precompiled info */ static void nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain, zone_type* zone) { if(!zone->nsec3_param) return; if((!domain->nsec3 || !domain->nsec3->hash_wc || !domain->nsec3->hash_wc->hash.node.key) && nsec3_condition_hash(domain, zone)) { region_type* tmpregion = region_create(xalloc, free); nsec3_precompile_domain(db, domain, zone, tmpregion); region_destroy(tmpregion); } if((!domain->nsec3 || !domain->nsec3->ds_parent_hash || !domain->nsec3->ds_parent_hash->node.key) && nsec3_condition_dshash(domain, zone)) { nsec3_precompile_domain_ds(db, domain, zone); } } /* see if nsec3 rrset-deletion triggers need action */ static void nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone, uint16_t type) { if(!zone->nsec3_param) return; nsec3_rrsets_changed_remove_prehash(domain, zone); /* for type nsec3, or a delegation, the domain may have become a * 'normal' domain with its remaining data now */ if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS) nsec3_rrsets_changed_add_prehash(db, domain, zone); /* for type DNAME or a delegation, obscured data may be revealed */ if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) { /* walk over subdomains and check them each */ domain_type *d; for(d=domain_next(domain); d && domain_is_subdomain(d, domain); d=domain_next(d)) { nsec3_rrsets_changed_add_prehash(db, d, zone); } } } /* see if nsec3 addition triggers need action */ static void nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone) { /* the RR has been added in full, also to UDB (and thus NSEC3PARAM * in the udb has been adjusted) */ if(zone->nsec3_param && rr->type == TYPE_NSEC3 && (!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key) && nsec3_rr_uses_params(rr, zone)) { if(!zone->nsec3_last) { /* all nsec3s have previously been deleted, but * we have nsec3 parameters, set it up again from * being cleared. */ nsec3_precompile_newparam(db, zone); } /* added NSEC3 into the chain */ nsec3_precompile_nsec3rr(db, rr->owner, zone); /* the domain has become an NSEC3-domain, if it was precompiled * previously, remove that, neatly done in routine above */ nsec3_rrsets_changed_remove_prehash(rr->owner, zone); /* set this NSEC3 to prehash */ prehash_add(db->domains, rr->owner); } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) { /* see if this means NSEC3 chain can be used */ nsec3_find_zone_param(db, zone, NULL, 0); if(!zone->nsec3_param) return; nsec3_zone_trees_create(db->region, zone); nsec3_precompile_newparam(db, zone); } } /* see if nsec3 rrset-addition triggers need action */ static void nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone, uint16_t type) { /* the rrset has been added so we can inspect it */ if(!zone->nsec3_param) return; /* because the rrset is added we can check conditions easily. * check if domain needs to become precompiled now */ nsec3_rrsets_changed_add_prehash(db, domain, zone); /* if a delegation, it changes from normal name to unhashed referral */ if(type == TYPE_NS || type == TYPE_DS) { nsec3_rrsets_changed_remove_prehash(domain, zone); } /* if delegation or DNAME added, then some RRs may get obscured */ if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) { /* walk over subdomains and check them each */ domain_type *d; for(d=domain_next(domain); d && domain_is_subdomain(d, domain); d=domain_next(d)) { nsec3_rrsets_changed_remove_prehash(d, zone); } } } #endif /* NSEC3 */ /* fixup usage lower for domain names in the rdata */ static void rr_lower_usage(namedb_type* db, rr_type* rr) { unsigned i; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { assert(rdata_atom_domain(rr->rdatas[i])->usage > 0); rdata_atom_domain(rr->rdatas[i])->usage --; if(rdata_atom_domain(rr->rdatas[i])->usage == 0) domain_table_deldomain(db, rdata_atom_domain(rr->rdatas[i])); } } } static void rrset_lower_usage(namedb_type* db, rrset_type* rrset) { unsigned i; for(i=0; irr_count; i++) rr_lower_usage(db, &rrset->rrs[i]); } int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, region_type* temp_region, int* softfail) { domain_type *domain; rrset_type *rrset; domain = domain_table_find(db->domains, dname); if(!domain) { log_msg(LOG_WARNING, "diff: domain %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); *softfail = 1; return 1; /* not fatal error */ } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { log_msg(LOG_WARNING, "diff: rrset %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); *softfail = 1; return 1; /* not fatal error */ } else { /* find the RR in the rrset */ domain_table_type *temptable; rdata_atom_type *rdatas; ssize_t rdata_num; int rrnum; temptable = domain_table_create(temp_region); /* This will ensure that the dnames in rdata are * normalized, conform RFC 4035, section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( temp_region, temptable, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0); if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex && rrset->rr_count != 0) rrnum = 0; /* replace existing SOA if no match */ if(rrnum == -1) { log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist", dname_to_string(dname,0), rrtype_to_string(type)); *softfail = 1; return 1; /* not fatal error */ } #ifdef NSEC3 /* process triggers for RR deletions */ nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone); #endif /* lower usage (possibly deleting other domains, and thus * invalidating the current RR's domain pointers) */ rr_lower_usage(db, &rrset->rrs[rrnum]); if(rrset->rr_count == 1) { /* delete entire rrset */ rrset_delete(db, domain, rrset); /* check if domain is now nonexisting (or parents) */ rrset_zero_nonexist_check(domain, NULL); #ifdef NSEC3 /* cleanup nsec3 */ nsec3_delete_rrset_trigger(db, domain, zone, type); #endif /* see if the domain can be deleted (and inspect parents) */ domain_table_deldomain(db, domain); } else { /* swap out the bad RR and decrease the count */ rr_type* rrs_orig = rrset->rrs; add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]); if(rrnum < rrset->rr_count-1) rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1]; memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type)); /* realloc the rrs array one smaller */ rrset->rrs = region_alloc_array_init(db->region, rrs_orig, (rrset->rr_count-1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } region_recycle(db->region, rrs_orig, sizeof(rr_type) * rrset->rr_count); #ifdef NSEC3 if(type == TYPE_NSEC3PARAM && zone->nsec3_param) { /* fixup nsec3_param pointer to same RR */ assert(zone->nsec3_param >= rrs_orig && zone->nsec3_param <= rrs_orig+rrset->rr_count); /* last moved to rrnum, others at same index*/ if(zone->nsec3_param == &rrs_orig[ rrset->rr_count-1]) zone->nsec3_param = &rrset->rrs[rrnum]; else zone->nsec3_param = (void*) ((char*)zone->nsec3_param -(char*)rrs_orig + (char*)rrset->rrs); } #endif /* NSEC3 */ rrset->rr_count --; #ifdef NSEC3 /* for type nsec3, the domain may have become a * 'normal' domain with its remaining data now */ if(type == TYPE_NSEC3) nsec3_rrsets_changed_add_prehash(db, domain, zone); #endif /* NSEC3 */ } } return 1; } int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, int* softfail) { domain_type* domain; rrset_type* rrset; rdata_atom_type *rdatas; rr_type *rrs_old; ssize_t rdata_num; int rrnum; #ifdef NSEC3 int rrset_added = 0; #endif domain = domain_table_find(db->domains, dname); if(!domain) { /* create the domain */ domain = domain_table_insert(db->domains, dname); } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { /* create the rrset */ rrset = region_alloc(db->region, sizeof(rrset_type)); if(!rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } rrset->zone = zone; rrset->rrs = 0; rrset->rr_count = 0; domain_add_rrset(domain, rrset); #ifdef NSEC3 rrset_added = 1; #endif } /* dnames in rdata are normalized, conform RFC 4035, * Section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( db->region, db->domains, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1); if(rrnum != -1) { DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists", dname_to_string(dname,0), rrtype_to_string(type))); /* ignore already existing RR: lenient accepting of messages */ *softfail = 1; return 1; } if(rrset->rr_count == 65535) { log_msg(LOG_ERR, "diff: too many RRs at %s", dname_to_string(dname,0)); return 0; } /* re-alloc the rrs and add the new */ rrs_old = rrset->rrs; rrset->rrs = region_alloc_array(db->region, (rrset->rr_count+1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } if(rrs_old) memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type)); region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count); rrset->rr_count ++; rrset->rrs[rrset->rr_count - 1].owner = domain; rrset->rrs[rrset->rr_count - 1].rdatas = rdatas; rrset->rrs[rrset->rr_count - 1].ttl = ttl; rrset->rrs[rrset->rr_count - 1].type = type; rrset->rrs[rrset->rr_count - 1].klass = klass; rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num; /* see if it is a SOA */ if(domain == zone->apex) { apex_rrset_checks(db, rrset, domain); #ifdef NSEC3 if(type == TYPE_NSEC3PARAM && zone->nsec3_param) { /* the pointer just changed, fix it up to point * to the same record */ assert(zone->nsec3_param >= rrs_old && zone->nsec3_param < rrs_old+rrset->rr_count); /* in this order to make sure no overflow/underflow*/ zone->nsec3_param = (void*)((char*)zone->nsec3_param - (char*)rrs_old + (char*)rrset->rrs); } #endif /* NSEC3 */ } #ifdef NSEC3 if(rrset_added) { domain_type* p = domain->parent; nsec3_add_rrset_trigger(db, domain, zone, type); /* go up and process (possibly created) empty nonterminals, * until we hit the apex or root */ while(p && p->rrsets == NULL && !p->is_apex) { nsec3_rrsets_changed_add_prehash(db, p, zone); p = p->parent; } } nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone); #endif /* NSEC3 */ return 1; } static zone_type* find_or_create_zone(namedb_type* db, const dname_type* zone_name, struct nsd_options* opt, const char* zstr, const char* patname) { zone_type* zone; struct zone_options* zopt; zone = namedb_find_zone(db, zone_name); if(zone) { return zone; } zopt = zone_options_find(opt, zone_name); if(!zopt) { /* if _implicit_ then insert as _part_of_config */ if(strncmp(patname, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)) == 0) { zopt = zone_options_create(opt->region); if(!zopt) return 0; zopt->part_of_config = 1; zopt->name = region_strdup(opt->region, zstr); zopt->pattern = pattern_options_find(opt, patname); if(!zopt->name || !zopt->pattern) return 0; if(!nsd_options_insert_zone(opt, zopt)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", zstr, patname); } } else { /* create zone : presumably already added to zonelist * by xfrd, who wrote the AXFR or IXFR to disk, so we only * need to add it to our config. * This process does not need linesize and offset zonelist */ zopt = zone_list_zone_insert(opt, zstr, patname); if(!zopt) return 0; } } zone = namedb_zone_create(db, zone_name, zopt); return zone; } void delete_zone_rrs(namedb_type* db, zone_type* zone) { rrset_type *rrset; domain_type *domain = zone->apex, *next; int nonexist_check = 0; /* go through entire tree below the zone apex (incl subzones) */ while(domain && domain_is_subdomain(domain, zone->apex)) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s", domain_to_string(domain))); /* delete all rrsets of the zone */ while((rrset = domain_find_any_rrset(domain, zone))) { /* lower usage can delete other domains */ rrset_lower_usage(db, rrset); /* rrset del does not delete our domain(yet) */ rrset_delete(db, domain, rrset); /* no rrset_zero_nonexist_check, do that later */ if(domain->rrsets == 0) nonexist_check = 1; } /* the delete upcoming could delete parents, but nothing next * or after the domain so store next ptr */ next = domain_next(domain); /* see if the domain can be deleted (and inspect parents) */ domain_table_deldomain(db, domain); domain = next; } /* check if data deletions have created nonexisting domain entries, * but after deleting domains so the checks are faster */ if(nonexist_check) { domain_type* ce = NULL; /* for speeding up has_data_below */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check")); domain = zone->apex; while(domain && domain_is_subdomain(domain, zone->apex)) { /* the interesting domains should be existing==1 * and rrsets==0, speeding up out processing of * sub-zones, since we only spuriously check empty * nonterminals */ if(domain->is_existing) ce = rrset_zero_nonexist_check(domain, ce); domain = domain_next(domain); } } DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes", (unsigned long) region_get_recycle_size(db->region))); #ifndef NDEBUG if(nsd_debug_level >= 2) region_log_stats(db->region); #endif assert(zone->soa_rrset == 0); /* keep zone->soa_nx_rrset alloced: it is reused */ assert(zone->ns_rrset == 0); assert(zone->is_secure == 0); } /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ static int apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, struct zone* zone, int* bytes, int* softfail, struct ixfr_store* ixfr_store) { uint32_t msglen, checklen, pkttype; int qcount, ancount; buffer_type* packet; region_type* region; /* note that errors could not really happen due to format of the * packet since xfrd has checked all dnames and RRs before commit, * this is why the errors are fatal (exit process), it must be * something internal or a bad disk or something. */ /* read ixfr packet RRs and apply to in memory db */ if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) { log_msg(LOG_ERR, "could not read type or wrong type"); return 0; } if(!diff_read_32(in, &msglen)) { log_msg(LOG_ERR, "could not read len"); return 0; } if(msglen < QHEADERSZ) { log_msg(LOG_ERR, "msg too short"); return 0; } region = region_create(xalloc, free); if(!region) { log_msg(LOG_ERR, "out of memory"); return 0; } packet = buffer_create(region, QIOBUFSZ); if(msglen > QIOBUFSZ) { log_msg(LOG_ERR, "msg too long"); region_destroy(region); return 0; } buffer_clear(packet); if(fread(buffer_begin(packet), msglen, 1, in) != 1) { log_msg(LOG_ERR, "short fread: %s", strerror(errno)); region_destroy(region); return 0; } buffer_set_limit(packet, msglen); /* see if check on data fails: checks that we are not reading * random garbage */ if(!diff_read_32(in, &checklen) || checklen != msglen) { log_msg(LOG_ERR, "transfer part has incorrect checkvalue"); return 0; } *bytes += msglen; /* only answer section is really used, question, additional and authority section RRs are skipped */ qcount = QDCOUNT(packet); ancount = ANCOUNT(packet); buffer_skip(packet, QHEADERSZ); /* qcount should be 0 or 1 really, ancount limited by 64k packet */ if(qcount > 64 || ancount > 65530) { log_msg(LOG_ERR, "RR count impossibly high"); region_destroy(region); return 0; } /* skip queries */ for(int i=0; i < qcount; ++i) { if(!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "bad RR in question section"); region_destroy(region); return 0; } } DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "diff: started packet for zone %s", domain_to_string(zone->apex))); for(int i=0; i < ancount; ++i, ++(*rr_count)) { const dname_type *owner; uint16_t type, klass, rrlen; uint32_t ttl; owner = dname_make_from_packet(region, packet, 1, 1); if(!owner) { log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count); region_destroy(region); return 0; } if(!buffer_available(packet, 10)) { log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count); region_destroy(region); return 0; } type = buffer_read_u16(packet); klass = buffer_read_u16(packet); ttl = buffer_read_u32(packet); rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) { log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d", *rr_count, rrlen, (int)buffer_remaining(packet)); region_destroy(region); return 0; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); if (type == TYPE_SOA) { size_t position; uint32_t serial; position = buffer_position(packet); if (!packet_skip_dname(packet) || !packet_skip_dname(packet) || buffer_remaining(packet) < sizeof(uint32_t) * 5) { log_msg(LOG_ERR, "bad xfr SOA RR formerr."); region_destroy(region); return 0; } serial = buffer_read_u32(packet); buffer_set_position(packet, position); /* first RR: check if SOA and correct zone & serialno */ if (*rr_count == 0) { assert(!*is_axfr); assert(!*delete_mode); if (klass != CLASS_IN) { log_msg(LOG_ERR, "first RR not SOA IN"); region_destroy(region); return 0; } if(dname_compare(domain_dname(zone->apex), owner) != 0) { log_msg(LOG_ERR, "SOA dname not equal to zone %s", domain_to_string(zone->apex)); region_destroy(region); return 0; } if(serial != serialno) { log_msg(LOG_ERR, "SOA serial %u different from commit %u", (unsigned)serial, (unsigned)serialno); region_destroy(region); return 0; } buffer_skip(packet, rrlen); if(ixfr_store) ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); continue; } else if (*rr_count == 1) { assert(!*is_axfr); assert(!*delete_mode); /* if the serial no of the SOA equals the serialno, then AXFR */ if (serial == serialno) goto axfr; *delete_mode = 1; /* must have stuff in memory for a successful IXFR, * the serial number of the SOA has been checked * previously (by check_for_bad_serial) if it exists */ if(!domain_find_rrset(zone->apex, zone, TYPE_SOA)) { log_msg(LOG_ERR, "%s SOA serial %u is not " "in memory, skip IXFR", domain_to_string(zone->apex), serialno); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } if(ixfr_store) ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen); } else if (!*is_axfr) { /* do not delete final SOA RR for IXFR */ if (i == ancount - 1 && seq_nr == seq_total - 1) { if (ixfr_store) { ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); } *delete_mode = 0; buffer_skip(packet, rrlen); continue; } else *delete_mode = !*delete_mode; if (ixfr_store && *delete_mode) { ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); ixfr_store_finish(ixfr_store, nsd, NULL); ixfr_store_start(zone, ixfr_store); ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen); } /* switch from delete-part to add-part and back again, just before soa - so it gets deleted and added too */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); } } else { if (*rr_count == 0) { log_msg(LOG_ERR, "first RR not SOA IN"); region_destroy(region); return 0; /* second RR: if not SOA: this is an AXFR; delete all zone contents */ } else if (*rr_count == 1) { axfr: *is_axfr = 1; #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); if(ixfr_store) { ixfr_store_cancel(ixfr_store); ixfr_store_delixfrs(zone); } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); } } if(type == TYPE_TSIG || type == TYPE_OPT) { /* ignore pseudo RRs */ buffer_skip(packet, rrlen); continue; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", *delete_mode?"del":"add", dname_to_string(owner, 0), rrtype_to_string(type))); if(*delete_mode) { assert(!*is_axfr); /* delete this rr */ if(ixfr_store) ixfr_store_delrr(ixfr_store, owner, type, klass, ttl, packet, rrlen, region); if(!delete_RR(nsd->db, owner, type, klass, packet, rrlen, zone, region, softfail)) { region_destroy(region); return 0; } } else { /* add this rr */ if(ixfr_store) ixfr_store_addrr(ixfr_store, owner, type, klass, ttl, packet, rrlen, region); if(!add_RR(nsd->db, owner, type, klass, ttl, packet, rrlen, zone, softfail)) { region_destroy(region); return 0; } } } region_destroy(region); return 1; } static int check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) { /* see if serial OK with in-memory serial */ domain_type* domain; region_type* region = region_create(xalloc, free); const dname_type* zone_name = dname_parse(region, zone_str); zone_type* zone = 0; domain = domain_table_find(db->domains, zone_name); if(domain) zone = domain_find_zone(db, domain); if(zone && zone->apex == domain && zone->soa_rrset && old_serial) { uint32_t memserial; memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); if(old_serial != ntohl(memserial)) { region_destroy(region); return 1; } } region_destroy(region); return 0; } int apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, struct nsd_options* ATTR_UNUSED(opt), udb_base* taskudb, uint32_t xfrfilenr) { char zone_buf[3072]; char log_buf[5120]; char patname_buf[2048]; uint32_t old_serial, new_serial, num_parts, type; uint64_t time_end_0, time_start_0; uint32_t time_end_1, time_start_1; uint8_t committed; uint32_t i; int num_bytes = 0; assert(zone); /* read zone name and serial */ if(!diff_read_32(in, &type)) { log_msg(LOG_ERR, "diff file too short"); return 0; } if(type != DIFF_PART_XFRF) { log_msg(LOG_ERR, "xfr file has wrong format"); return 0; } /* committed and num_parts are first because they need to be * updated once the rest is written. The log buf is not certain * until its done, so at end of file. The patname is in case a * new zone is created, we know what the options-pattern is */ if(!diff_read_8(in, &committed) || !diff_read_32(in, &num_parts) || !diff_read_64(in, &time_end_0) || !diff_read_32(in, &time_end_1) || !diff_read_32(in, &old_serial) || !diff_read_32(in, &new_serial) || !diff_read_64(in, &time_start_0) || !diff_read_32(in, &time_start_1) || !diff_read_str(in, zone_buf, sizeof(zone_buf)) || !diff_read_str(in, patname_buf, sizeof(patname_buf))) { log_msg(LOG_ERR, "diff file bad commit part"); return 0; } /* has been read in completely */ if(strcmp(zone_buf, domain_to_string(zone->apex)) != 0) { log_msg(LOG_ERR, "file %s does not match task %s", zone_buf, domain_to_string(zone->apex)); return 0; } switch(committed) { case DIFF_NOT_COMMITTED: log_msg(LOG_ERR, "diff file %s was not committed", zone_buf); return 0; case DIFF_CORRUPT: log_msg(LOG_ERR, "diff file %s was corrupt", zone_buf); return 0; case DIFF_INCONSISTENT: log_msg(LOG_ERR, "diff file %s was inconsistent", zone_buf); return 0; case DIFF_VERIFIED: log_msg(LOG_INFO, "diff file %s already verified", zone_buf); break; default: break; } if(num_parts == 0) { log_msg(LOG_ERR, "diff file %s was not completed", zone_buf); return 0; } if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "skipping diff file commit with bad serial")); return -2; /* Success in "main" process, failure in "xfrd" */ } if(!zone->is_skipped) { int is_axfr=0, delete_mode=0, rr_count=0, softfail=0; struct ixfr_store* ixfr_store = NULL, ixfr_store_mem; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf)); if(zone_is_ixfr_enabled(zone)) ixfr_store = ixfr_store_start(zone, &ixfr_store_mem); /* read and apply all of the parts */ for(i=0; idb, zone); #endif /* NSEC3 */ zone->is_changed = 1; zone->is_updated = 1; zone->is_checked = (committed == DIFF_VERIFIED); zone->mtime.tv_sec = time_end_0; zone->mtime.tv_nsec = time_end_1*1000; if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = region_strdup(nsd->db->region, log_buf); namedb_zone_free_filenames(nsd->db, zone); if(softfail && taskudb && !is_axfr) { log_msg(LOG_ERR, "Failed to apply IXFR cleanly " "(deletes nonexistent RRs, adds existing RRs). " "Zone %s contents is different from primary, " "starting AXFR. Transfer %s", zone_buf, log_buf); /* add/del failures in IXFR, get an AXFR */ diff_update_commit( zone_buf, DIFF_INCONSISTENT, nsd, xfrfilenr); return -1; /* Fatal! */ } if(ixfr_store) ixfr_store_finish(ixfr_store, nsd, log_buf); if(1 <= verbosity) { double elapsed = (double)(time_end_0 - time_start_0)+ (double)((double)time_end_1 -(double)time_start_1) / 1000000.0; VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds", zone_buf, log_buf, num_bytes, elapsed)); } } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", zone_buf)); } return 1; } static void udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void *arg) { struct task_list_d* p = (struct task_list_d*)d; assert(s >= p->size); (void)s; (*cb)(base, &p->next, arg); } void udb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, udb_walk_relptr_cb* cb, void *arg) { (void)warg; switch(t) { case udb_chunk_type_task: udb_task_walk_chunk(base, d, s, cb, arg); break; default: /* no rel ptrs */ break; } } struct udb_base* task_file_create(const char* file) { return udb_base_create_new(file, &udb_walkfunc, NULL); } static int task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e, size_t sz, const dname_type* zname) { if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) { return 0; } if(udb_ptr_is_null(last)) { udb_base_set_userdata(udb, e->data); } else { udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e); } udb_ptr_set_ptr(last, udb, e); /* fill in tasklist item */ udb_rel_ptr_init(&TASKLIST(e)->next); TASKLIST(e)->size = sz; TASKLIST(e)->oldserial = 0; TASKLIST(e)->newserial = 0; TASKLIST(e)->yesno = 0; if(zname) { memmove(TASKLIST(e)->zname, zname, dname_total_size(zname)); } return 1; } void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z, enum soainfo_hint hint) { /* calculate size */ udb_ptr e; size_t sz; const dname_type* apex, *ns, *em; if(!z || !z->apex || !domain_dname(z->apex)) return; /* safety check */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s", domain_to_string(z->apex))); apex = domain_dname(z->apex); sz = sizeof(struct task_list_d) + dname_total_size(apex); if(z->soa_rrset && hint == soainfo_ok) { ns = domain_dname(rdata_atom_domain( z->soa_rrset->rrs[0].rdatas[0])); em = domain_dname(rdata_atom_domain( z->soa_rrset->rrs[0].rdatas[1])); sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2 + ns->name_size + em->name_size; } else { ns = 0; em = 0; } /* create new task_list item */ if(!task_create_new_elem(udb, last, &e, sz, apex)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO"); return; } TASKLIST(&e)->task_type = task_soa_info; TASKLIST(&e)->yesno = (uint64_t)hint; if(z->soa_rrset && hint == soainfo_ok) { uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl); uint8_t* p = (uint8_t*)TASKLIST(&e)->zname; p += dname_total_size(apex); memmove(p, &ttl, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, &ns->name_size, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(p, dname_name(ns), ns->name_size); p += ns->name_size; memmove(p, &em->name_size, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(p, dname_name(em), em->name_size); p += em->name_size; memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]), sizeof(uint32_t)); } udb_ptr_unlink(&e, udb); } void task_process_sync(struct udb_base* taskudb) { /* need to sync before other process uses the mmap? */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d", taskudb->fname, (int)taskudb->base_size)); (void)taskudb; } void task_remap(struct udb_base* taskudb) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d", taskudb->fname, (int)taskudb->glob_data->fsize)); udb_base_remap_process(taskudb); } void task_clear(struct udb_base* taskudb) { udb_ptr t, n; udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); udb_base_set_userdata(taskudb, 0); udb_ptr_init(&n, taskudb); while(!udb_ptr_is_null(&t)) { udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next); udb_rptr_zero(&TASKLIST(&t)->next, taskudb); udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size); udb_ptr_set_ptr(&t, taskudb, &n); } udb_ptr_unlink(&t, taskudb); udb_ptr_unlink(&n, taskudb); } void task_new_expire(struct udb_base* udb, udb_ptr* last, const struct dname* z, int expired) { udb_ptr e; if(!z) return; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s", dname_to_string(z,NULL))); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ dname_total_size(z), z)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add expire"); return; } TASKLIST(&e)->task_type = task_expire; TASKLIST(&e)->yesno = expired; udb_ptr_unlink(&e, udb); } void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone) { udb_ptr e; xfrd_check_catalog_consumer_zonefiles(zone); DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + (zone?dname_total_size(zone):0), zone)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones"); return; } TASKLIST(&e)->task_type = task_check_zonefiles; TASKLIST(&e)->yesno = (zone!=NULL); udb_ptr_unlink(&e, udb); } void task_new_write_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + (zone?dname_total_size(zone):0), zone)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones"); return; } TASKLIST(&e)->task_type = task_write_zonefiles; TASKLIST(&e)->yesno = (zone!=NULL); udb_ptr_unlink(&e, udb); } void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v"); return; } TASKLIST(&e)->task_type = task_set_verbosity; TASKLIST(&e)->yesno = v; udb_ptr_unlink(&e, udb); } void task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone, const char* pattern, unsigned zonestatid) { size_t zlen = strlen(zone); size_t plen = strlen(pattern); void *p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern)); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ zlen + 1 + plen + 1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addz"); return; } TASKLIST(&e)->task_type = task_add_zone; TASKLIST(&e)->yesno = zonestatid; p = TASKLIST(&e)->zname; memcpy(p, zone, zlen+1); memmove((char*)p+zlen+1, pattern, plen+1); udb_ptr_unlink(&e, udb); } void task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0))); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +dname_total_size(dname), dname)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delz"); return; } TASKLIST(&e)->task_type = task_del_zone; udb_ptr_unlink(&e, udb); } void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key) { char* p; udb_ptr e; assert(key->name && key->algorithm && key->secret); DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(key->name)+1+strlen(key->algorithm)+1+ strlen(key->secret)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addk"); return; } TASKLIST(&e)->task_type = task_add_key; p = (char*)TASKLIST(&e)->zname; memmove(p, key->name, strlen(key->name)+1); p+=strlen(key->name)+1; memmove(p, key->algorithm, strlen(key->algorithm)+1); p+=strlen(key->algorithm)+1; memmove(p, key->secret, strlen(key->secret)+1); udb_ptr_unlink(&e, udb); } void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name) { char* p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(name)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delk"); return; } TASKLIST(&e)->task_type = task_del_key; p = (char*)TASKLIST(&e)->zname; memmove(p, name, strlen(name)+1); udb_ptr_unlink(&e, udb); } void task_new_cookies(udb_base* udb, udb_ptr* last, int answer_cookie, size_t cookie_count, void* cookie_secrets) { udb_ptr e; char* p; size_t const secrets_size = sizeof(cookie_secrets_type); DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task cookies")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + secrets_size, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add cookies"); return; } TASKLIST(&e)->task_type = task_cookies; TASKLIST(&e)->newserial = (uint32_t) answer_cookie; TASKLIST(&e)->yesno = (uint64_t) cookie_count; p = (char*)TASKLIST(&e)->zname; memmove(p, cookie_secrets, secrets_size); udb_ptr_unlink(&e, udb); } void task_new_add_pattern(udb_base* udb, udb_ptr* last, struct pattern_options* p) { region_type* temp; buffer_type* buffer; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname)); temp = region_create(xalloc, free); buffer = buffer_create(temp, 4096); pattern_options_marshal(buffer, p); buffer_flip(buffer); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + buffer_limit(buffer), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addp"); region_destroy(temp); return; } TASKLIST(&e)->task_type = task_add_pattern; TASKLIST(&e)->yesno = buffer_limit(buffer); memmove(TASKLIST(&e)->zname, buffer_begin(buffer), buffer_limit(buffer)); udb_ptr_unlink(&e, udb); region_destroy(temp); } void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name) { char* p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name)); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(name)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delp"); return; } TASKLIST(&e)->task_type = task_del_pattern; p = (char*)TASKLIST(&e)->zname; memmove(p, name, strlen(name)+1); udb_ptr_unlink(&e, udb); } void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c"); return; } TASKLIST(&e)->task_type = task_opt_change; #ifdef RATELIMIT TASKLIST(&e)->oldserial = opt->rrl_ratelimit; TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit; TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip; #else (void)opt; #endif udb_ptr_unlink(&e, udb); } void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task zonestat_inc")); if(sz == 0) return; /* no need to decrease to 0 */ if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add z_i"); return; } TASKLIST(&e)->task_type = task_zonestat_inc; TASKLIST(&e)->oldserial = (uint32_t)sz; udb_ptr_unlink(&e, udb); } int task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname, uint32_t old_serial, uint32_t new_serial, uint64_t filenumber) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +dname_total_size(dname), dname)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr"); return 0; } TASKLIST(&e)->oldserial = old_serial; TASKLIST(&e)->newserial = new_serial; TASKLIST(&e)->yesno = filenumber; TASKLIST(&e)->task_type = task_apply_xfr; udb_ptr_unlink(&e, udb); return 1; } void task_process_expire(namedb_type* db, struct task_list_d* task) { uint8_t ok; zone_type* z = namedb_find_zone(db, task->zname); assert(task->task_type == task_expire); if(!z) { DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree", dname_to_string(task->zname, NULL), task->yesno?"expired":"unexpired")); return; } DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s", dname_to_string(task->zname,0), task->yesno?"expired":"unexpired")); /* find zone, set expire flag */ ok = !task->yesno; /* only update zone->is_ok if needed to minimize copy-on-write * of memory pages shared after fork() */ if(ok && !z->is_ok) z->is_ok = 1; else if(!ok && z->is_ok) z->is_ok = 0; } static void task_process_set_verbosity(struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno)); verbosity = task->yesno; } static void task_process_checkzones(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task, struct task_list_d* task) { /* on SIGHUP check if zone-text-files changed and if so, * reread. When from xfrd-reload, no need to fstat the files */ if(task->yesno) { struct zone_options* zo = zone_options_find(nsd->options, task->zname); if(zo) namedb_check_zonefile(nsd, taskudb, last_task, zo); } else { /* check all zones */ namedb_check_zonefiles(nsd, nsd->options, taskudb, last_task); } } static void task_process_writezones(struct nsd* nsd, struct task_list_d* task) { if(task->yesno) { struct zone_options* zo = zone_options_find(nsd->options, task->zname); if(zo) namedb_write_zonefile(nsd, zo); } else { namedb_write_zonefiles(nsd, nsd->options); } } static void task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, struct task_list_d* task) { zone_type* z; const dname_type* zdname; const char* zname = (const char*)task->zname; const char* pname = zname + strlen(zname)+1; DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname)); zdname = dname_parse(nsd->db->region, zname); if(!zdname) { log_msg(LOG_ERR, "can not parse zone name %s", zname); return; } /* create zone */ z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname); if(!z) { region_recycle(nsd->db->region, (void*)zdname, dname_total_size(zdname)); log_msg(LOG_ERR, "can not add zone %s %s", zname, pname); return; } /* zdname is not used by the zone allocation. */ region_recycle(nsd->db->region, (void*)zdname, dname_total_size(zdname)); z->zonestatid = (unsigned)task->yesno; /* if zone is empty, attempt to read the zonefile from disk (if any) */ if(!z->soa_rrset && z->opts->pattern->zonefile) { namedb_read_zonefile(nsd, z, udb, last_task); } } static void task_process_del_zone(struct nsd* nsd, struct task_list_d* task) { zone_type* zone; struct zone_options* zopt; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string( task->zname, NULL))); zone = namedb_find_zone(nsd->db, task->zname); if(!zone) return; #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); /* remove from zonetree, apex, soa */ zopt = zone->opts; namedb_zone_delete(nsd->db, zone); /* remove from options (zone_list already edited by xfrd) */ zone_options_delete(nsd->options, zopt); } static void task_process_add_key(struct nsd* nsd, struct task_list_d* task) { struct key_options key; key.name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name)); key.algorithm = key.name + strlen(key.name)+1; key.secret = key.algorithm + strlen(key.algorithm)+1; key_options_add_modify(nsd->options, &key); memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */ } static void task_process_del_key(struct nsd* nsd, struct task_list_d* task) { char* name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name)); /* this is reload and nothing is using the TSIG key right now */ key_options_remove(nsd->options, name); } static void task_process_cookies(struct nsd* nsd, struct task_list_d* task) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "cookies task answer: %s, count: %d", task->newserial ? "yes" : "no", (int)task->yesno)); nsd->do_answer_cookie = (int) task->newserial; nsd->cookie_count = (size_t) task->yesno; memmove(nsd->cookie_secrets, task->zname, sizeof(nsd->cookie_secrets)); explicit_bzero(task->zname, sizeof(nsd->cookie_secrets)); } static void task_process_add_pattern(struct nsd* nsd, struct task_list_d* task) { region_type* temp = region_create(xalloc, free); buffer_type buffer; struct pattern_options *pat; buffer_create_from(&buffer, task->zname, task->yesno); pat = pattern_options_unmarshal(temp, &buffer); DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname)); pattern_options_add_modify(nsd->options, pat); region_destroy(temp); } static void task_process_del_pattern(struct nsd* nsd, struct task_list_d* task) { char* name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name)); pattern_options_remove(nsd->options, name); } static void task_process_opt_change(struct nsd* nsd, struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task")); #ifdef RATELIMIT nsd->options->rrl_ratelimit = task->oldserial; nsd->options->rrl_whitelist_ratelimit = task->newserial; nsd->options->rrl_slip = task->yesno; rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit, nsd->options->rrl_slip); #else (void)nsd; (void)task; #endif } #ifdef USE_ZONE_STATS static void task_process_zonestat_inc(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "zonestat_inc task %u", (unsigned)task->oldserial)); nsd->zonestatdesired = (unsigned)task->oldserial; /* send echo to xfrd to increment on its end */ task_new_zonestat_inc(udb, last_task, nsd->zonestatdesired); } #endif void task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr* task) { /* we have to use an udb_ptr task here, because the apply_xfr procedure * appends soa_info which may remap and change the pointer. */ zone_type* zone; FILE* df; DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string( TASKLIST(task)->zname, NULL))); zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname); if(!zone) { /* assume the zone has been deleted and a zone transfer was * still waiting to be processed */ udb_ptr_free_space(task, udb, TASKLIST(task)->size); return; } /* apply the XFR */ /* oldserial, newserial, yesno is filenumber */ df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r"); if(!df) { /* could not open file to update */ /* soainfo_gone will be communicated from server_reload, unless preceding updates have been applied */ zone->is_skipped = 1; udb_ptr_free_space(task, udb, TASKLIST(task)->size); return; } /* read and apply zone transfer */ switch(apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, TASKLIST(task)->yesno)) { case 1: /* Success */ break; case 0: /* Failure */ /* soainfo_gone will be communicated from server_reload, unless preceding updates have been applied */ zone->is_skipped = 1; break; case -1:/* Fatal */ exit(1); break; default:break; } fclose(df); udb_ptr_free_space(task, udb, TASKLIST(task)->size); } void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task) { switch(TASKLIST(task)->task_type) { case task_expire: task_process_expire(nsd->db, TASKLIST(task)); break; case task_check_zonefiles: task_process_checkzones(nsd, udb, last_task, TASKLIST(task)); break; case task_write_zonefiles: task_process_writezones(nsd, TASKLIST(task)); break; case task_set_verbosity: task_process_set_verbosity(TASKLIST(task)); break; case task_add_zone: task_process_add_zone(nsd, udb, last_task, TASKLIST(task)); break; case task_del_zone: task_process_del_zone(nsd, TASKLIST(task)); break; case task_add_key: task_process_add_key(nsd, TASKLIST(task)); break; case task_del_key: task_process_del_key(nsd, TASKLIST(task)); break; case task_add_pattern: task_process_add_pattern(nsd, TASKLIST(task)); break; case task_del_pattern: task_process_del_pattern(nsd, TASKLIST(task)); break; case task_opt_change: task_process_opt_change(nsd, TASKLIST(task)); break; #ifdef USE_ZONE_STATS case task_zonestat_inc: task_process_zonestat_inc(nsd, udb, last_task, TASKLIST(task)); break; #endif case task_cookies: task_process_cookies(nsd, TASKLIST(task)); break; default: log_msg(LOG_WARNING, "unhandled task in reload type %d", (int)TASKLIST(task)->task_type); break; } udb_ptr_free_space(task, udb, TASKLIST(task)->size); } nsd-4.12.0/dbcreate.c0000644000175000017500000001673015002373054013721 0ustar mozziemozzie/* * dbcreate.c -- routines to create an nsd(8) name database * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "namedb.h" #include "udb.h" #include "options.h" #include "nsd.h" #include "ixfr.h" /* pathname directory separator character */ #define PATHSEP '/' /** add an rdata (uncompressed) to the destination */ static size_t add_rdata(rr_type* rr, unsigned i, uint8_t* buf, size_t buflen) { switch(rdata_atom_wireformat_type(rr->type, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: { const dname_type* dname = domain_dname( rdata_atom_domain(rr->rdatas[i])); if(dname->name_size > buflen) return 0; memmove(buf, dname_name(dname), dname->name_size); return dname->name_size; } default: break; } if(rdata_atom_size(rr->rdatas[i]) > buflen) return 0; memmove(buf, rdata_atom_data(rr->rdatas[i]), rdata_atom_size(rr->rdatas[i])); return rdata_atom_size(rr->rdatas[i]); } /* marshal rdata into buffer, must be MAX_RDLENGTH in size */ size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz) { size_t len = 0; unsigned i; assert(rr); for(i=0; irdata_count; i++) { len += add_rdata(rr, i, rdata+len, sz-len); } return len; } int print_rrs(FILE* out, struct zone* zone) { rrset_type *rrset; domain_type *domain = zone->apex; region_type* region = region_create(xalloc, free); region_type* rr_region = region_create(xalloc, free); buffer_type* rr_buffer = buffer_create(region, MAX_RDLENGTH); struct state_pretty_rr* state = create_pretty_rr(region); /* first print the SOA record for the zone */ if(zone->soa_rrset) { size_t i; for(i=0; i < zone->soa_rrset->rr_count; i++) { if(!print_rr(out, state, &zone->soa_rrset->rrs[i], rr_region, rr_buffer)){ log_msg(LOG_ERR, "There was an error " "printing SOARR to zone %s", zone->opts->name); region_destroy(region); region_destroy(rr_region); return 0; } } } /* go through entire tree below the zone apex (incl subzones) */ while(domain && domain_is_subdomain(domain, zone->apex)) { for(rrset = domain->rrsets; rrset; rrset=rrset->next) { size_t i; if(rrset->zone != zone || rrset == zone->soa_rrset) continue; for(i=0; i < rrset->rr_count; i++) { if(!print_rr(out, state, &rrset->rrs[i], rr_region, rr_buffer)){ log_msg(LOG_ERR, "There was an error " "printing RR to zone %s", zone->opts->name); region_destroy(region); region_destroy(rr_region); return 0; } } } domain = domain_next(domain); } region_destroy(region); region_destroy(rr_region); return 1; } static int print_header(zone_type* zone, FILE* out, time_t* now, const char* logs) { char buf[4096+16]; /* ctime prints newline at end of this line */ snprintf(buf, sizeof(buf), "; zone %s written by NSD %s on %s", zone->opts->name, PACKAGE_VERSION, ctime(now)); if(!write_data(out, buf, strlen(buf))) return 0; if(!logs || logs[0] == 0) return 1; snprintf(buf, sizeof(buf), "; %s\n", logs); return write_data(out, buf, strlen(buf)); } static int write_to_zonefile(zone_type* zone, const char* filename, const char* logs) { time_t now = time(0); FILE *out = fopen(filename, "w"); if(!out) { log_msg(LOG_ERR, "cannot write zone %s file %s: %s", zone->opts->name, filename, strerror(errno)); return 0; } if(!print_header(zone, out, &now, logs)) { fclose(out); log_msg(LOG_ERR, "There was an error printing " "the header to zone %s", zone->opts->name); return 0; } if(!print_rrs(out, zone)) { fclose(out); return 0; } if(fclose(out) != 0) { log_msg(LOG_ERR, "cannot write zone %s to file %s: fclose: %s", zone->opts->name, filename, strerror(errno)); return 0; } return 1; } /** create directories above this file, .../dir/dir/dir/file */ int create_dirs(const char* path) { char dir[4096]; char* p; strlcpy(dir, path, sizeof(dir)); /* if we start with / then do not try to create '' */ if(dir[0] == PATHSEP) p = strchr(dir+1, PATHSEP); else p = strchr(dir, PATHSEP); /* create each directory component from the left */ while(p) { assert(*p == PATHSEP); *p = 0; /* end the directory name here */ if(mkdir(dir #ifndef MKDIR_HAS_ONE_ARG , 0750 #endif ) == -1) { if(errno != EEXIST) { log_msg(LOG_ERR, "create dir %s: %s", dir, strerror(errno)); *p = PATHSEP; /* restore input string */ return 0; } /* it already exists, OK, continue */ } *p = PATHSEP; p = strchr(p+1, PATHSEP); } return 1; } /** create pathname components and check if file exists */ static int create_path_components(const char* path, int* notexist) { /* stat the file, to see if it exists, and if its directories exist */ struct stat s; if(stat(path, &s) != 0) { if(errno == ENOENT) { *notexist = 1; /* see if we need to create pathname components */ return create_dirs(path); } log_msg(LOG_ERR, "cannot stat %s: %s", path, strerror(errno)); return 0; } *notexist = 0; return 1; } void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt) { const char* zfile; int notexist = 0; zone_type* zone; /* if no zone exists, it has no contents or it has no zonefile * configured, then no need to write data to disk */ if(!zopt->pattern->zonefile) return; zone = namedb_find_zone(nsd->db, (const dname_type*)zopt->node.key); if(!zone || !zone->apex || !zone->soa_rrset) return; /* write if file does not exist, or if changed */ /* so, determine filename, create directory components, check exist*/ zfile = config_make_zonefile(zopt, nsd); if(!create_path_components(zfile, ¬exist)) { log_msg(LOG_ERR, "could not write zone %s to file %s because " "the path could not be created", zopt->name, zfile); return; } /* if not changed, do not write. */ if(notexist || zone->is_changed) { char logs[4096]; char bakfile[4096]; struct timespec mtime; /* write to zfile~ first, then rename if that works */ snprintf(bakfile, sizeof(bakfile), "%s~", zfile); if(zone->logstr) strlcpy(logs, zone->logstr, sizeof(logs)); else logs[0] = 0; VERBOSITY(1, (LOG_INFO, "writing zone %s to file %s", zone->opts->name, zfile)); if(!write_to_zonefile(zone, bakfile, logs)) { (void)unlink(bakfile); /* delete failed file */ return; /* error already printed */ } if(rename(bakfile, zfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", bakfile, zfile, strerror(errno)); (void)unlink(bakfile); /* delete failed file */ return; } zone->is_changed = 0; VERBOSITY(3, (LOG_INFO, "zone %s written to file %s", zone->opts->name, zfile)); /* fetch the mtime of the just created zonefile so we * do not waste effort reading it back in */ if(!file_get_mtime(zfile, &mtime, ¬exist)) { get_time(&mtime); } zone->mtime = mtime; if(zone->filename) region_recycle(nsd->db->region, zone->filename, strlen(zone->filename)+1); zone->filename = region_strdup(nsd->db->region, zfile); if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; if(zone_is_ixfr_enabled(zone) && zone->ixfr) ixfr_write_to_file(zone, zfile); } } void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options) { struct zone_options* zo; RBTREE_FOR(zo, struct zone_options*, options->zone_options) { namedb_write_zonefile(nsd, zo); } } nsd-4.12.0/dbaccess.c0000644000175000017500000002367615002373054013726 0ustar mozziemozzie/* * dbaccess.c -- access methods for nsd(8) database * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "dns.h" #include "namedb.h" #include "util.h" #include "options.h" #include "rdata.h" #include "udb.h" #include "zonec.h" #include "nsec3.h" #include "difffile.h" #include "nsd.h" #include "ixfr.h" #include "ixfrcreate.h" void namedb_close(struct namedb* db) { if(db) { region_destroy(db->region); } } void namedb_free_ixfr(struct namedb* db) { struct radnode* n; for(n=radix_first(db->zonetree); n; n=radix_next(n)) { zone_ixfr_free(((zone_type*)n->elem)->ixfr); } } /** create a zone */ zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zo) { zone_type* zone = (zone_type *) region_alloc(db->region, sizeof(zone_type)); zone->node = radname_insert(db->zonetree, dname_name(dname), dname->name_size, zone); assert(zone->node); zone->apex = domain_table_insert(db->domains, dname); zone->apex->usage++; /* the zone.apex reference */ zone->apex->is_apex = 1; zone->soa_rrset = NULL; zone->soa_nx_rrset = NULL; zone->ns_rrset = NULL; #ifdef NSEC3 zone->nsec3_param = NULL; zone->nsec3_last = NULL; zone->nsec3tree = NULL; zone->hashtree = NULL; zone->wchashtree = NULL; zone->dshashtree = NULL; #endif zone->opts = zo; zone->ixfr = NULL; zone->filename = NULL; zone->includes.count = 0; zone->includes.paths = NULL; zone->logstr = NULL; zone->mtime.tv_sec = 0; zone->mtime.tv_nsec = 0; zone->zonestatid = 0; zone->is_secure = 0; zone->is_changed = 0; zone->is_updated = 0; zone->is_skipped = 0; zone->is_checked = 0; zone->is_bad = 0; zone->is_ok = 1; return zone; } void namedb_zone_free_filenames(namedb_type *db, zone_type* zone) { assert(!zone->includes.paths == !zone->includes.count); if (zone->filename) { region_recycle( db->region, zone->filename, strlen(zone->filename) + 1); zone->filename = NULL; } if (zone->includes.count) { for (size_t i=0; i < zone->includes.count; i++) { region_recycle( db->region, zone->includes.paths[i], strlen(zone->includes.paths[i]) + 1); } region_recycle( db->region, zone->includes.paths, zone->includes.count * sizeof(*zone->includes.paths)); zone->includes.count = 0; zone->includes.paths = NULL; } } void namedb_zone_delete(namedb_type* db, zone_type* zone) { /* RRs and UDB and NSEC3 and so on must be already deleted */ radix_delete(db->zonetree, zone->node); /* see if apex can be deleted */ if(zone->apex) { zone->apex->usage --; zone->apex->is_apex = 0; if(zone->apex->usage == 0) { /* delete the apex, possibly */ domain_table_deldomain(db, zone->apex); } } /* soa_rrset is freed when the SOA was deleted */ if(zone->soa_nx_rrset) { region_recycle(db->region, zone->soa_nx_rrset->rrs, sizeof(rr_type)); region_recycle(db->region, zone->soa_nx_rrset, sizeof(rrset_type)); } #ifdef NSEC3 hash_tree_delete(db->region, zone->nsec3tree); hash_tree_delete(db->region, zone->hashtree); hash_tree_delete(db->region, zone->wchashtree); hash_tree_delete(db->region, zone->dshashtree); #endif zone_ixfr_free(zone->ixfr); namedb_zone_free_filenames(db, zone); if(zone->logstr) region_recycle(db->region, zone->logstr, strlen(zone->logstr)+1); region_recycle(db->region, zone, sizeof(zone_type)); } struct namedb * namedb_open (struct nsd_options* opt) { namedb_type* db; /* * Region used to store the loaded database. The region is * freed in namedb_close. */ region_type* db_region; (void)opt; #ifdef USE_MMAP_ALLOC db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1); #else /* !USE_MMAP_ALLOC */ db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); #endif /* !USE_MMAP_ALLOC */ db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb)); db->region = db_region; db->domains = domain_table_create(db->region); db->zonetree = radix_tree_create(db->region); db->diff_skip = 0; db->diff_pos = 0; if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { log_msg(LOG_ERR, "unable to load namedb: cannot initialize timestamp"); region_destroy(db_region); return NULL; } return db; } /** get the file mtime stat (or nonexist or error) */ int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist) { struct stat s; if(stat(file, &s) != 0) { mtime->tv_sec = 0; mtime->tv_nsec = 0; *nonexist = (errno == ENOENT); return 0; } *nonexist = 0; mtime->tv_sec = s.st_mtime; #ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC mtime->tv_nsec = s.st_mtimensec; #elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) mtime->tv_nsec = s.st_mtim.tv_nsec; #else mtime->tv_nsec = 0; #endif return 1; } void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, udb_ptr* last_task) { struct timespec mtime; int nonexist = 0; unsigned int errors; const char* fname; struct ixfr_create* ixfrcr = NULL; int ixfr_create_already_done = 0; if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile) return; mtime.tv_sec = 0; mtime.tv_nsec = 0; fname = config_make_zonefile(zone->opts, nsd); assert(fname); if(!file_get_mtime(fname, &mtime, &nonexist)) { if(nonexist) { if(zone_is_slave(zone->opts)) { /* for slave zones not as bad, no zonefile * may just mean we have to transfer it */ VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist", fname)); } else { /* without a download option, we can never * serve data, more severe error printout */ log_msg(LOG_ERR, "zonefile %s does not exist", fname); } } else log_msg(LOG_ERR, "zonefile %s: %s", fname, strerror(errno)); if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); return; } else { const char* zone_fname = zone->filename; struct timespec zone_mtime = zone->mtime; /* if no zone_fname, then it was acquired in zone transfer, * see if the file is newer than the zone transfer * (regardless if this is a different file), because the * zone transfer is a different content source too */ if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) { VERBOSITY(3, (LOG_INFO, "zonefile %s is older than " "zone transfer in memory", fname)); return; /* if zone_fname, then the file was acquired from reading it, * and see if filename changed or mtime newer to read it */ } else if(zone_fname && strcmp(zone_fname, fname) == 0 && timespec_compare(&zone_mtime, &mtime) == 0) { int changed = 0; struct timespec include_mtime; /* one of the includes may have been deleted, changed, etc */ for (size_t i=0; i < zone->includes.count; i++) { if (!file_get_mtime(zone->includes.paths[i], &include_mtime, &nonexist)) { changed = 1; } else if (timespec_compare(&zone_mtime, &include_mtime) < 0) { mtime = include_mtime; changed = 1; } } if (!changed) { VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified", fname)); return; } } } if(ixfr_create_from_difference(zone, fname, &ixfr_create_already_done)) { ixfrcr = ixfr_create_start(zone, fname, zone->opts->pattern->ixfr_size, 0); if(!ixfrcr) { /* leaves the ixfrcr at NULL, so it is not created */ log_msg(LOG_ERR, "out of memory starting ixfr create"); } } namedb_zone_free_filenames(nsd->db, zone); zone->filename = region_strdup(nsd->db->region, fname); /* wipe zone from memory */ #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); VERBOSITY(5, (LOG_INFO, "zone %s zonec_read(%s)", zone->opts->name, fname)); errors = zonec_read(nsd->db, nsd->db->domains, zone->opts->name, fname, zone); if(errors > 0) { log_msg(LOG_ERR, "zone %s file %s read with %u errors", zone->opts->name, fname, errors); /* wipe (partial) zone from memory */ zone->is_ok = 1; #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); namedb_zone_free_filenames(nsd->db, zone); if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; } else { VERBOSITY(1, (LOG_INFO, "zone %s read with success", zone->opts->name)); zone->is_ok = 1; zone->is_changed = 0; /* store zone into udb */ zone->mtime = mtime; if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; if(ixfr_create_already_done) { ixfr_readup_exist(zone, nsd, fname); } else if(ixfrcr) { if(!ixfr_create_perform(ixfrcr, zone, 1, nsd, fname, zone->opts->pattern->ixfr_number)) { log_msg(LOG_ERR, "failed to create IXFR"); } else { VERBOSITY(2, (LOG_INFO, "zone %s created IXFR %s.ixfr", zone->opts->name, fname)); } ixfr_create_free(ixfrcr); } else if(zone_is_ixfr_enabled(zone)) { ixfr_read_from_file(nsd, zone, fname); } } if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); #ifdef NSEC3 prehash_zone_complete(nsd->db, zone); #endif } void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task, struct zone_options* zopt) { zone_type* zone; const dname_type* dname = (const dname_type*)zopt->node.key; /* find zone to go with it, or create it */ zone = namedb_find_zone(nsd->db, dname); if(!zone) { zone = namedb_zone_create(nsd->db, dname, zopt); } namedb_read_zonefile(nsd, zone, taskudb, last_task); } void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task) { struct zone_options* zo; /* check all zones in opt, create if not exist in main db */ RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { namedb_check_zonefile(nsd, taskudb, last_task, zo); if(nsd->signal_hint_shutdown) break; } } nsd-4.12.0/contrib/0000755000175000017500000000000015002373054013435 5ustar mozziemozziensd-4.12.0/contrib/patch_for_s6_startup_and_other_service_supervisors.diff0000644000175000017500000000454015002373054026660 0ustar mozziemozziediff --git nsd.c nsd.c index 98dec613..e9d7b2cc 100644 --- nsd.c +++ nsd.c @@ -91,6 +91,9 @@ usage (void) " -n tcp-count The maximum number of TCP connections per server.\n" " -P pidfile Specify the PID file to write.\n" " -p port Specify the port to listen to.\n" + " -r Print a newline into the file descriptor index\n" + " described in the READY_FD environment variable to\n" + " indicate that nsd is ready to accept connections.\n" " -s seconds Dump statistics every SECONDS seconds.\n" " -t chrootdir Change root to specified directory on startup.\n" ); @@ -323,6 +326,24 @@ sig_handler(int sig) } } +/* + * Parse envvar as a positive integer. + * + */ +int +get_fd_from_env(const char* key) +{ + char *env = getenv(key); + if (!env || env[0] == '\0') + return -1; + errno = 0; + char *endptr; + int fd = (int)strtol(env, &endptr, 10); + if (errno != 0 || endptr[0] != '\0') + return -1; + return fd; +} + /* * Statistic output... * @@ -450,7 +471,7 @@ main(int argc, char *argv[]) } /* 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" + while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:rs:u:t:X:V:v" #ifndef NDEBUG /* only when configured with --enable-checking */ "F:L:" #endif /* NDEBUG */ @@ -533,6 +554,9 @@ main(int argc, char *argv[]) tcp_port = optarg; udp_port = optarg; break; + case 'r': + nsd.readyfd = 1; + break; case 's': #ifdef BIND8_STATS nsd.st.period = atoi(optarg); @@ -965,6 +989,18 @@ main(int argc, char *argv[]) } #endif /* HAVE_SSL */ + /* When asked to notify readiness via REâ’¶DY_FD, do so. */ + if (nsd.readyfd) { + int readyfd = get_fd_from_env("READY_FD"); + if (readyfd < 0) + error("READY_FD unset or contains garbage"); + unsetenv("READY_FD"); + int ret = dprintf(readyfd, "\n"); + close(readyfd); + if (ret < 0) + error("could not write to READY_FD index"); + } + /* Unless we're debugging, fork... */ if (!nsd.debug) { int fd; diff --git nsd.h nsd.h index de3ae8e1..ff27b798 100644 --- nsd.h +++ nsd.h @@ -179,6 +179,7 @@ struct nsd unsigned server_kind; struct namedb *db; int debug; + int readyfd; size_t child_count; struct nsd_child *children; nsd-4.12.0/contrib/nsd_munin_0000755000175000017500000002735515002373054015530 0ustar mozziemozzie#!/bin/sh # # plugin for munin to monitor usage of NSD. # # (C) 2008 W.C.A. Wijngaards. BSD Licensed. # # To install; compile with --enable-bind8-stats (enabled by default) # and enable nsd-control in nsd.conf with the line # remote-control: control-enable: yes # Run the command nsd-control-setup as root to generate the key files. # # Environment variables for this script # statefile - where to put temporary statefile. # nsd_conf - where the nsd.conf file is located. # nsd_control - where to find nsd-control executable. # nsd_checkconf - where to find nsd-checkconf executable. # # You can set them in your munin/plugin-conf.d/plugins.conf file # with: # [nsd_munin*] # user root # env.statefile /usr/local/var/munin/plugin-state/nsd-state # env.nsd_conf /usr/local/etc/nsd.conf # env.nsd_control /usr/local/sbin/nsd-control # env.nsd_checkconf /usr/local/sbin/nsd-checkconf # # This plugin can create different graphs depending on what name # you link it as (with ln -s) into the plugins directory # You can link it multiple times. # If you are only a casual user, the _hits and _by_type are most interesting, # possibly followed by _by_rcode. # # nsd_munin_hits - base volume, transport type, failures # nsd_munin_memory - memory usage # nsd_munin_by_type - incoming queries by type # nsd_munin_by_class - incoming queries by class # nsd_munin_by_opcode - incoming queries by opcode # nsd_munin_by_rcode - answers by rcode # nsd_munin_zones - number of zones # # Magic markers - optional - used by installation scripts and # munin-config: # #%# family=contrib #%# capabilities=autoconf suggest # POD documentation : <<=cut =head1 NAME nsd_munin_ - Munin plugin to monitor the NSD server. =head1 APPLICABLE SYSTEMS System with NSD daemon. =head1 CONFIGURATION [nsd_munin*] user root env.statefile /usr/local/var/munin/plugin-state/nsd-state env.nsd_conf /usr/local/etc/nsd.conf env.nsd_control /usr/local/sbin/nsd-control env.nsd_checkconf /usr/local/sbin/nsd-checkconf Use the .env settings to override the defaults. =head1 USAGE Can be used to present different graphs. Use ln -s for that name in the plugins directory to enable the graph. nsd_munin_hits - base volume, transport type, failures nsd_munin_memory - memory usage nsd_munin_by_type - incoming queries by type nsd_munin_by_class - incoming queries by class nsd_munin_by_opcode - incoming queries by opcode nsd_munin_by_rcode - answers by rcode nsd_munin_zones - number of zones =head1 AUTHOR Copyright 2008 W.C.A. Wijngaards =head1 LICENSE BSD =cut state=${statefile:-/usr/local/var/munin/plugin-state/nsd-state} conf=${nsd_conf:-/usr/local/etc/nsd.conf} ctrl=${nsd_control:-/usr/local/sbin/nsd-control} chkconf=${nsd_checkconf:-/usr/local/sbin/nsd-checkconf} lock=$state.lock # number of seconds between polling attempts. # makes the statefile hang around for at least this many seconds, # so that multiple links of this script can share the results. lee=55 # to keep things within 19 characters ABBREV="-e s/num/n/ -e s/type/t/ -e s/opcode/o/ -e s/rcode/r/ -e s/class/c/" # get value from $1 into return variable $value get_value ( ) { value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`" if test "$value"x = ""x; then value="0" fi } # download the state from NSD. get_state ( ) { # obtain lock for fetching the state # because there is a race condition in fetching and writing to file # see if the lock is stale, if so, take it if test -f $lock ; then pid="`cat $lock 2>&1`" kill -0 "$pid" >/dev/null 2>&1 if test $? -ne 0 -a "$pid" != $$ ; then echo $$ >$lock fi fi i=0 while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do while test -f $lock; do # wait i=`expr $i + 1` if test $i -gt 1000; then sleep 1; fi if test $i -gt 1500; then echo "error locking $lock" "=" `cat $lock` rm -f $lock exit 1 fi done # try to get it echo $$ >$lock done # do not refetch if the file exists and only LEE seconds old if test -f $state; then now=`date +%s` get_value "timestamp" if test $now -lt `expr $value + $lee`; then rm -f $lock return fi fi $ctrl -c $conf stats > $state if test $? -ne 0; then echo "error retrieving data from the server" rm -f $lock exit 1 fi echo "timestamp="`date +%s` >> $state rm -f $lock } if test "$1" = "autoconf" ; then if test ! -f $conf; then echo no "($conf does not exist)" exit 1 fi if test ! -d `dirname $state`; then mkdir -p `dirname $state` if test ! -d `dirname $state`; then echo no "($state directory does not exist)" exit 1 fi fi echo yes exit 0 fi if test "$1" = "suggest" ; then echo "hits" echo "memory" echo "by_type" echo "by_class" echo "by_opcode" echo "by_rcode" echo "zones" exit 0 fi # determine my type, by name id=`echo $0 | sed -e 's/^.*nsd_munin_//'` if test "$id"x = ""x; then # some default to keep people sane. id="hits" fi # if $1 exists in statefile, config is echoed with label $2 exist_config ( ) { mn=`echo $1 | sed $ABBREV | tr . _` if grep '^'$1'=' $state >/dev/null 2>&1; then echo "$mn.label $2" echo "$mn.min 0" echo "$mn.type ABSOLUTE" fi } # print label and min 0 for a name $1 in nsd format p_config ( ) { mn=`echo $1 | sed $ABBREV | tr . _` echo $mn.label "$2" echo $mn.min 0 echo $mn.type $3 } if test "$1" = "config" ; then if test ! -f $state; then get_state fi case $id in hits) echo "graph_title NSD traffic" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in server0.queries server1.queries server2.queries \ server3.queries server4.queries server5.queries \ server6.queries server7.queries server8.queries \ server9.queries server10.queries server11.queries \ server12.queries server13.queries server14.queries \ server15.queries ; do exist_config $x "queries handled by `basename $x .queries`" done p_config "num.queries" "total queries" "ABSOLUTE" p_config "num.udp" "UDP ip4 queries" "ABSOLUTE" p_config "num.udp6" "UDP ip6 queries" "ABSOLUTE" p_config "num.tcp" "TCP ip4 queries" "ABSOLUTE" p_config "num.tcp6" "TCP ip6 queries" "ABSOLUTE" p_config "num.edns" "queries with EDNS OPT" "ABSOLUTE" p_config "num.ednserr" "queries failed EDNS parse" "ABSOLUTE" p_config "num.answer_wo_aa" "nonauthor. queries (referrals)" "ABSOLUTE" p_config "num.rxerr" "receive failed" "ABSOLUTE" p_config "num.txerr" "transmit failed" "ABSOLUTE" p_config "num.truncated" "truncated replies with TC" "ABSOLUTE" p_config "num.raxfr" "AXFR from allowed client" "ABSOLUTE" p_config "num.rixfr" "IXFR from allowed client" "ABSOLUTE" p_config "num.dropped" "dropped due to sanity check" "ABSOLUTE" echo "graph_info DNS queries." ;; memory) echo "graph_title NSD memory usage" echo "graph_args --base 1024 -l 0" echo "graph_vlabel memory used in bytes" echo "graph_category DNS" p_config "size.vsz" "Total virtual memory (VSZ)" "GAUGE" p_config "size.rss" "Total resident memory (RSS)" "GAUGE" p_config "size.db.mem" "data in memory" "GAUGE" p_config "size.xfrd.mem" "xfr and notify memory" "GAUGE" p_config "size.config.mem" "config memory" "GAUGE" p_config "size.db.disk" "mmap of nsd.db file" "GAUGE" p_config "size.config.disk" "config zonelist on disk" "GAUGE" echo "graph_info The memory used by NSD, xfrd and config. Disk size of nsd.db and zonelist." ;; by_type) echo "graph_title NSD queries by type" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.type" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.type.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by DNS RR type queried for" ;; by_class) echo "graph_title NSD queries by class" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.class" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.class.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by DNS RR class queried for." ;; by_opcode) echo "graph_title NSD queries by opcode" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.opcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.opcode.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by opcode in the query packet." ;; by_rcode) echo "graph_title NSD answers by return code" echo "graph_args --base 1000 -l 0" echo "graph_vlabel answer packets / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.rcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.rcode.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info answers split out by return value." ;; zones) echo "graph_title NSD number of zones" echo "graph_args --base 1000 -l 0" echo "graph_vlabel zone count" echo "graph_category DNS" p_config "zone.total" "total zones" "GAUGE" p_config "zone.primary" "primary zones" "GAUGE" p_config "zone.secondary" "secondary zones" "GAUGE" echo "graph_info number of zones served by NSD." ;; esac exit 0 fi # do the stats itself get_state # get the time elapsed get_value "time.elapsed" if test $value = 0 || test $value = "0.000000"; then echo "error: time elapsed 0 or could not retrieve data" exit 1 fi elapsed="$value" # print value for $1 print_value ( ) { mn=`echo $1 | sed $ABBREV | tr . _` get_value $1 echo "$mn.value" $value } # print value if line already found in $2 print_value_line ( ) { mn=`echo $1 | sed $ABBREV | tr . _` value="`echo $2 | sed -e 's/^.*=//'`" echo "$mn.value" $value } case $id in hits) for x in server0.queries server1.queries server2.queries \ server3.queries server4.queries server5.queries \ server6.queries server7.queries server8.queries \ server9.queries server10.queries server11.queries \ server12.queries server13.queries server14.queries \ server15.queries \ num.queries num.udp num.udp6 num.tcp num.tcp6 \ num.edns num.ednserr num.answer_wo_aa num.rxerr num.txerr \ num.truncated num.raxfr num.rixfr num.dropped ; do if grep "^"$x"=" $state >/dev/null 2>&1; then print_value $x fi done ;; memory) # get the total memory for NSD serverpid=`$ctrl -c $conf serverpid 2>&1` # small race condition, if reload happens between previous and next # lines, if so, detect by checking if we have a number as output. rssval=`ps -p $serverpid -o rss= 2>&1` vszval=`ps -p $serverpid -o vsz= 2>&1` if test "`expr $rssval + 1 - 1 2>&1`" -eq "$rssval" >/dev/null 2>&1; then rssval=`expr $rssval \* 1024` else rssval=0 fi if test "`expr $vszval + 1 - 1 2>&1`" -eq "$vszval" >/dev/null 2>&1; then vszval=`expr $vszval \* 1024` else vszval=0 fi echo "size_vsz.value" $vszval echo "size_rss.value" $rssval for x in size.db.mem size.xfrd.mem size.config.mem \ size.db.disk size.config.disk; do print_value $x done ;; by_type) for x in `grep "^num.type" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_class) for x in `grep "^num.class" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_opcode) for x in `grep "^num.opcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_rcode) for x in `grep "^num.rcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; zones) get_value "zone.primary" nummas="$value" get_value "zone.secondary" numsla="$value" echo "zone_total.value" `expr $nummas + $numsla` echo "zone_primary.value" "$nummas" echo "zone_secondary.value" "$numsla" esac nsd-4.12.0/contrib/nsd.zones2nsd.conf0000644000175000017500000000704715002373054017024 0ustar mozziemozzie#!/usr/bin/env python # Contributed 2006 by Stephane Bortzmeyer. # Changed 20070102 by Wouter to handle primary zones and file names. # Converts a nsd 2 "nsd.zones" file to a nsd 3 "nsd.conf" file. # Change at will nsd_zones_name = "./nsd.zones" key_dir = "/local/nsd/etc/keys" # Directory holding the TSIG keys import re import os.path primary_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s*$", re.IGNORECASE) secondary_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s+masters\s+([0-9a-f:\. ]*)\s*$", re.IGNORECASE) notify_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s+notify\s+([0-9a-f:\. ]*)\s*$", re.IGNORECASE) comment_re = re.compile("^\s*;") empty_re = re.compile("^\s*$") nsd_zones = open(nsd_zones_name) keys = {} for line in nsd_zones.xreadlines(): if comment_re.search(line) or empty_re.search(line): pass elif secondary_line_re.search(line): match = secondary_line_re.search(line) zone = match.group(1) zonefile = match.group(2) master_group = match.group(3) masters = re.split("\s+", master_group) print """zone: name: "%s" zonefile: "%s" # This is to allow "nsdc update" to work. allow-notify: 127.0.0.1 NOKEY # This is a slave zone. Masters are listed below.""" % (zone, zonefile) for master in masters: if re.search("^\s*$", master): continue key_filename = "%s/%s.tsiginfo" % (key_dir, master) if os.path.exists(key_filename): key_content = open(key_filename) peer_ip = key_content.readline() peer_ip = peer_ip[:-1] key_name = key_content.readline() key_name = key_name[:-1] algorithm = key_content.readline() algorithm = int(algorithm[:-1]) if algorithm == 157: algorithm_name = "hmac-md5" else: raise Exception("Unsupported TSIG algorithm %i" % algorithm) secret = key_content.readline() secret = secret[:-1] key_content.close() key = key_name keys[key_name] = { 'algorithm': algorithm_name, 'secret': secret} else: key = "NOKEY" print """ allow-notify: %s %s request-xfr: %s %s""" % (master, key, master, key) print "" elif primary_line_re.search(line): match = primary_line_re.search(line) zone = match.group(1) zonefile = match.group(2) print """zone: name: "%s" zonefile: "%s" """ % (zone, zonefile) elif notify_line_re.search(line): match = notify_line_re.search(line) zone = match.group(1) zonefile = match.group(2) notify_group = match.group(3) notifies = re.split("\s+", notify_group) print """zone: name: "%s" zonefile: "%s" # This is a master zone. Slaves are listed below.""" % (zone, zonefile) for notify in notifies: if re.search("^\s*$", notify): continue key = "NOKEY" print """ notify: %s %s""" % (notify, key) print "" else: raise Exception("Invalid line \"%s\"" % line) nsd_zones.close() for key in keys.keys(): print """key: name: "%s" algorithm: %s secret: "%s" """ % (key, keys[key]['algorithm'], keys[key]['secret']) print "" ## Local Variables: ## ## mode:python ## ## End: ## nsd-4.12.0/contrib/nsd.spec0000644000175000017500000000607215002373054015102 0ustar mozziemozzieSummary: NSD is a complete implementation of an authoritative DNS name server Name: nsd Version: 4.1.6 Release: 1%{?dist} License: BSD Url: http://www.nlnetlabs.nl/%{name}/ #Source: http://www.nlnetlabs.nl/downloads/%{name}/%{name}-%{version}.tar.gz Source: %{name}-%{version}.tar.gz Source1: nsd.init Source2: nsd.cron Group: System Environment/Daemons BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: flex, openssl-devel Requires(pre): shadow-utils %description NSD is a complete implementation of an authoritative DNS name server. It can function as a primary or secondary DNS server, with DNSSEC support. For further information about what NSD is and what NSD is not please consult the REQUIREMENTS document which is a part of this distribution. (thanks to Olaf). %prep %setup -q -n %{name}-%{version} %build %configure --enable-pie --enable-relro-now --enable-ratelimit \ --enable-bind8-stats --enable-plugins --enable-checking \ --enable-mmap --with-ssl --enable-nsec3 --enable-nsid \ --with-pidfile=%{_localstatedir}/run/%{name}/%{name}.pid --with-ssl \ --with-user=nsd --with-xfrdfile=%{_localstatedir}/lib/%{name}/ixfr.state %{__make} %{?_smp_mflags} #convert to utf8 iconv -f iso8859-1 -t utf-8 doc/RELNOTES > doc/RELNOTES.utf8 iconv -f iso8859-1 -t utf-8 doc/CREDITS > doc/CREDITS.utf8 mv -f doc/RELNOTES.utf8 doc/RELNOTES mv -f doc/CREDITS.utf8 doc/CREDITS %install rm -rf %{buildroot} %{__make} DESTDIR=%{buildroot} install install -d -m 0755 %{buildroot}%{_initrddir} install -d -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/cron.hourly install -c -m 0755 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/cron.hourly/nsd install -m 0755 %{SOURCE1} %{buildroot}/%{_initrddir}/nsd install -d -m 0700 %{buildroot}%{_localstatedir}/run/%{name} install -d -m 0700 %{buildroot}%{_localstatedir}/lib/%{name} # change .sample to normal config files head -76 %{buildroot}%{_sysconfdir}/nsd/nsd.conf.sample > %{buildroot}%{_sysconfdir}/nsd/nsd.conf rm %{buildroot}%{_sysconfdir}/nsd/nsd.conf.sample echo "database: /var/lib/nsd/nsd.db" >> %{buildroot}%{_sysconfdir}/nsd/nsd.conf echo "# include: \"/some/path/file\"" >> %{buildroot}%{_sysconfdir}/nsd/nsd.conf %clean rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root,-) %doc doc/* %doc contrib/nsd.zones2nsd.conf %dir %{_sysconfdir}/nsd/ %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/nsd/nsd.conf #%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/nsd/nsd.zones %attr(0755,root,root) %{_initrddir}/%{name} %{_sysconfdir}/cron.hourly/nsd %attr(0755,%{name},%{name}) %dir %{_localstatedir}/run/%{name} %attr(0755,%{name},%{name}) %dir %{_localstatedir}/lib/%{name} %{_sbindir}/* %{_mandir}/*/* %pre getent group nsd >/dev/null || groupadd -r nsd getent passwd nsd >/dev/null || \ useradd -r -g nsd -d /etc/nsd -s /sbin/nologin \ -c "nsd daemon account" nsd exit 0 %post /sbin/chkconfig --add %{name} %preun if [ $1 -eq 0 ]; then /sbin/service %{name} stop /sbin/chkconfig --del %{name} fi %postun if [ "$1" -ge "1" ]; then /sbin/service %{name} condrestart fi nsd-4.12.0/contrib/nsd.service0000644000175000017500000000042115002373054015600 0ustar mozziemozzie[Unit] Description=NSD DNS Server After=syslog.target network-online.target [Service] Type=notify ExecStart=/usr/sbin/nsd -d -P "" -c /etc/nsd/nsd.conf $NSD_EXTRA_OPTS ExecReload=/bin/kill -HUP $MAINPID KillMode=mixed PrivateTmp=true [Install] WantedBy=multi-user.target nsd-4.12.0/contrib/nsd.openrc.in0000644000175000017500000000422115002373054016035 0ustar mozziemozzie#!/sbin/openrc-run description="The NLnet Labs Name Server Daemon (NSD)" extra_commands="configtest" extra_started_commands="reload" # For the config file, we use a combination of --with-configdir and # the service name instead of (say) the value passed to # --with-nsd_conf_file, because OpenRC supports running multiple # instances of the same daemon from one service script using symlinks. config_file="@configdir@/${RC_SVCNAME}.conf" checkconf="@sbindir@/nsd-checkconf" command="@sbindir@/nsd" # Run the daemon in the foreground and allow OpenRC to background it # and manage its PID file. This is the simplest way to ensure that a # PID file owned and writable only by the superuser is created outside # of e.g. the socket directory that must be writable by the nsd # user. It also happens to agree with what the nsd.service systemd # unit does. The PID file is named after the service name (and ignores # --with-pidfile) to support multiple instances running simultaneously. command_args="-c ${config_file} -d -P '' ${NSD_EXTRA_OPTS}" command_background=true pidfile="@runstatedir@/${RC_SVCNAME}.pid" required_files="${config_file}" depend() { use logger } checkconfig() { if ! "${checkconf}" "${config_file}" ; then eerror "You have errors in your config file (${config_file})" return $? fi return 0 } configtest() { ebegin "Checking ${RC_SVCNAME} configuration" checkconfig eend $? } start_pre() { # If this isn't a restart, make sure that the configuration is # usable before we try to start the daemon. Without this, the # service will start successfully but then immediately crash. # If this *is* a restart, then the stop_pre action will have # already checked the config. if [ "${RC_CMD}" != "restart" ] ; then checkconfig || return $? fi } stop_pre() { # If this is a restart, check to make sure the user's config # isn't busted before we stop the running daemon. If it's a # regular "stop," however, then we shouldn't interfere. if [ "${RC_CMD}" = "restart" ] ; then checkconfig || return $? fi } reload() { checkconfig || return $? ebegin "Reloading config and zone files" start-stop-daemon --signal HUP --pidfile "${pidfile}" eend $? } nsd-4.12.0/contrib/nsd.openrc.conf0000644000175000017500000000011515002373054016352 0ustar mozziemozzie# Extra command-line arguments to pass to the NSD daemon. #NSD_EXTRA_OPTS="" nsd-4.12.0/contrib/nsd.init0000644000175000017500000001030615002373054015106 0ustar mozziemozzie#!/bin/sh # # nsdc.sh -- a shell script to manage the beast # # Copyright (c) 2001-2006, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # (numbers are runlevels startpriority killpriority). # chkconfig: 2345 45 74 # description: NSD, authoritative only high performance name server. # configuration file default configfile="/etc/nsd.conf" # The directory where NSD binaries reside sbindir="/usr/sbin" # # You sure heard this many times before: NO USER SERVICEABLE PARTS BELOW # # see if user selects a different config file, with -c if test "x$1" = "x-c"; then shift if [ -e $1 ]; then configfile=$1 shift else echo "`basename $0`: Config file "$1" does not exist." exit 1 fi fi # locate nsd-checkconf : in sbindir, PATH, nsdc_dir or . nsd_checkconf="" if [ -e ${sbindir}/nsd-checkconf ]; then nsd_checkconf=${sbindir}/nsd-checkconf else if which nsd-checkconf >/dev/null 2>&1 ; then if which nsd-checkconf 2>&1 | grep "^[Nn]o " >/dev/null; then nsd_checkconf="" else nsd_checkconf=`which nsd-checkconf` fi fi if [ -z "${nsd_checkconf}" -a -e `dirname $0`/nsd-checkconf ]; then nsd_checkconf=`dirname $0`/nsd-checkconf fi if [ -z "${nsd_checkconf}" -a -e ./nsd-checkconf ]; then nsd_checkconf=./nsd-checkconf fi if [ -z "${nsd_checkconf}" ]; then echo "`basename $0`: Could not find nsd programs" \ "in $sbindir, in PATH=$PATH, in cwd=`pwd`," \ "or in dir of nsdc=`dirname $0`" exit 1 fi fi usage() { echo "Usage: `basename $0` [-c configfile] {start|stop|reload|restart|" echo " running}" echo "options:" echo " -c configfile Use specified configfile (default: @nsdconfigfile@)." echo "commands:" echo " start Start nsd server." echo " stop Stop nsd server." echo " reload Nsd server reloads database file." echo " restart Stop the nsd server and start it again." echo " running Prints message and exit nonzero if server not running." } # check the config syntax before using it ${nsd_checkconf} ${configfile} if test $? -ne 0 ; then usage exit 1 fi # Read some settings from the config file. pidfile=`${nsd_checkconf} -o pidfile ${configfile}` zonesdir=`${nsd_checkconf} -o zonesdir ${configfile}` sbindir=`dirname ${nsd_checkconf}` # move to zonesdir (if specified), and make absolute pathnames. if test -n "${zonesdir}"; then zonesdir=`dirname ${zonesdir}/.` if echo "${zonesdir}" | grep "^[^/]" >/dev/null; then zonesdir=`pwd`/${zonesdir} fi if echo "${pidfile}" | grep "^[^/]" >/dev/null; then pidfile=${zonesdir}/${pidfile} fi fi # for bash: -C or noclobber. For tcsh: noclobber. For bourne: -C. noclobber_set="set -C" # ugly check for tcsh if echo @shell@ | grep tcsh >/dev/null; then noclobber_set="set noclobber" fi # # useful routines # signal() { if [ -s ${pidfile} ] then kill -"$1" `cat ${pidfile}` && return 0 else echo "nsd is not running" fi return 1 } do_start() { if test -x ${sbindir}/nsd; then ${sbindir}/nsd -c ${configfile} test $? = 0 || (echo "nsd startup failed."; exit 1) else echo "${sbindir}/nsd not an executable file, nsd startup failed."; exit 1 fi } controlled_sleep() { if [ $1 -ge 25 ]; then sleep 1 fi } controlled_stop() { pid=$1 try=1 while [ $try -ne 0 ]; do if [ ${try} -gt 50 ]; then echo "nsdc stop failed" return 1 else if [ $try -eq 1 ]; then kill -TERM ${pid} else kill -TERM ${pid} >/dev/null 2>&1 fi # really stopped? kill -0 ${pid} >/dev/null 2>&1 if [ $? -eq 0 ]; then controlled_sleep ${try} try=`expr ${try} + 1` else try=0 fi fi done rm -f ${pidfile} return 0 } do_controlled_stop() { if [ -s ${pidfile} ]; then pid=`cat ${pidfile}` controlled_stop ${pid} && return 0 else echo "nsd is not running, starting anyway" && return 0 fi return 1 } do_stop() { signal "TERM" rm -f ${pidfile} } do_reload() { signal "HUP" } case "$1" in start) if test -s ${pidfile} && kill -"0" `cat ${pidfile}` then (echo "process `cat ${pidfile}` exists, please use restart"; exit 1) else do_start fi ;; stop) do_stop ;; stats) signal "USR1" ;; reload) do_reload ;; running) signal "0" ;; restart) do_controlled_stop && do_start ;; *) usage ;; esac exit $? nsd-4.12.0/contrib/nsd-tmpfiles.conf.in0000644000175000017500000000017515002373054017321 0ustar mozziemozzie# Create a writable directory in case the user wants to # use a local control socket. d @runstatedir@/nsd 0750 @user@ @user@ nsd-4.12.0/contrib/bug390.patch0000644000175000017500000000073015002373054015467 0ustar mozziemozzieIndex: nsec3.c =================================================================== --- nsec3.c (revision 3889) +++ nsec3.c (working copy) @@ -820,6 +820,10 @@ if(!query->zone->nsec3_param) return; nsec3_add_nonexist_proof(query, answer, wildcard, qname); + if(wildcard->parent && wildcard->parent->nsec3 && + wildcard->parent->nsec3->nsec3_is_exact) + nsec3_add_rrset(query, answer, AUTHORITY_SECTION, + wildcard->parent->nsec3->nsec3_cover); } static void nsd-4.12.0/contrib/bind2nsd/0000755000175000017500000000000015002373054015140 5ustar mozziemozziensd-4.12.0/contrib/bind2nsd/setup.py0000644000175000017500000000343415002373054016656 0ustar mozziemozzie# # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # installation/setup script for bind2nsd # from distutils.core import setup setup(name = 'bind2nsd', version = '0.5.0', author = 'Secure64 Software Corporation', author_email = 'support@secure64.com', maintainer = 'Al Stone', maintainer_email = 'ahs3@secure64.com', url = 'http://www.secure64.com', description = 'automatic named/nsd translation and synchronization', packages = [ 'bind2nsd' ], scripts = [ 'scripts/bind2nsd', 'scripts/s64-sync', 'scripts/s64-mkpw', ], data_files = [ ('/usr/share/doc/bind2nsd', ['./README', './TODO']), ('/etc/bind2nsd', ['etc/bind2nsd.conf']), ] ) nsd-4.12.0/contrib/bind2nsd/set_version0000644000175000017500000000432515002373054017427 0ustar mozziemozzie#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # set the version number in the right files # if [ $# -ne "1" ] then echo "usage: set_version " exit 1 fi NEWV=$1 #-- report on the current version numbers SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py is currently => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py is currently => ${CONFIGV}" #-- replace them sed --in-place=.bak \ "s/ version = '${SETUPV}',/ version = '${NEWV}',/" setup.py sed --in-place=.bak \ "s/[ \t]*'version'[ \t]*: '${CONFIGV}',/ 'version' : '${NEWV}',/" bind2nsd/Config.py #-- report on the new version numbers SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py is now => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py is now => ${CONFIGV}" nsd-4.12.0/contrib/bind2nsd/scripts/0000755000175000017500000000000015002373054016627 5ustar mozziemozziensd-4.12.0/contrib/bind2nsd/scripts/s64-sync0000644000175000017500000002652415002373054020151 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # When named.conf changes, update the DNS machine # # #-- imports import getopt import os import os.path import popen2 import re import sys import time if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from Utils import * from NamedConf import * from NsdConf import * else: from bind2nsd.Config import * from bind2nsd.Utils import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * if os.path.exists('../pexpect-2.1'): sys.path.append('../pexpect-2.1') import pexpect import pxssh #-- globals conf = Config() #-- useful functions def usage(): print 's64-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: s64-sync [-a|--analyze-only] [-h|--help] [-s|--sync-only]' print ' [-n|--now]' print ' -a | --analyze-only => look for and report errors, but do' print ' not sync with the Secure64 server' print ' -h | --help => print this message and quit' print ' -n | --now => do not poll, sync immediately' print ' -s | --sync-only => sync without translating BIND files' print ' -v | --verbose => output lots of info' return def rebuild_nsd_files(): result = False xlate = conf.getValue('bind2nsd') if os.path.exists(xlate): result = run_cmd(xlate, 'running bind2nsd...') else: report_error('? could not find "%s" and have got to have it' % (xlate)) report_error(' skipping rebuild of NSD files') return result def scp_s64(): #-- do the scp to an actual Secure64 server report_info('=> using scp to transfer to Secure64 system...') tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- this feels a bit dodgy due to issues in pexpect when it goes # up against passwd and other such nastiness from scp/ssh -- all # we should have to do is child.wait() really, but that does not # work as it should. # # NB: it turn out that you can _not_ put a '*' at the end of the # source path; pexpect.spawn() screws up and the parsing of the string # and ends up ignoring everything up to the '*', meaning the command # does not have the 'scp' part in it and does not get executed properly. # pwd = os.getcwd() os.chdir(tmpdir) #-- this is what i wanted to do... #cmd = 'scp -r ' + tmpdir + ' dns@' + conf.getValue('dest-ip') + ':' #-- this is what works... flist = os.listdir('.') fnames = ' '.join(flist) cmd = 'scp -r ' + fnames cmd += ' ' + conf.getValue('destuser') + '@' cmd += conf.getValue('dest-ip') + ':' report_info('=> ' + cmd) child = pexpect.spawn(cmd) if len(conf.getValue('dnspw')) > 0: child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('.*' + conf.getValue('nsd_conf') + '.*') child.expect(pexpect.EOF) child.close() os.chdir(pwd) return def cp_files(analyze): #-- we assume everything has already been copied to the tmpdir by bind2nsd if analyze: return tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- scp the entire tmp directory if conf.getValue('DEMO-MODE'): report_info('** scp would go here, but cp -r for demonstration purposes') cmd = 'cp -r ' + tmpdir + '* ' + conf.getValue('destdir') run_cmd(cmd, 'using cp to transfer to demo system...') else: scp_s64() return def restart_nsd(): if conf.getValue('DEMO-MODE'): cmd = conf.getValue('stop_cmd') run_cmd(cmd, 'stopping nsd...') # BOZO: rebuild is not behaving when there are errors, so the hack is # to remove the existing db, run the zone compiler and restart nsd #cmd = conf.getValue('rebuild_cmd') #os.system(cmd) cmd = 'rm -f ' + conf.getValue('database') run_cmd(cmd, 'removing old zonedb...') cmd = conf.getValue('zonec_cmd') run_cmd(cmd, 'rebuilding zonedb...') cmd = conf.getValue('start_cmd') run_cmd(cmd, 'starting nsd...') else: cmd = 'ssh -a -x dns@' + conf.getValue('dest-ip') child = pexpect.spawn(cmd) if not child.isalive(): bail('? cannot login to Secure64 system at %s' % \ (conf.getValue('dest-ip'))) else: report_info('=> restarting Secure64 NSD on %s' % \ (conf.getValue('dest-ip'))) child.expect('.*ssword:') child.sendline(conf.getValue('syspw')) child.expect('\[view@.*> ') report_info('=> now logged in') child.sendline('enable dnsconfig') child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('\*.*') report_info('=> issuing zonec') child.sendline('zonec') if isVerbose(): child.logfile = sys.stdout child.expect('\[dnsconfig@.*# ') report_info('=> issuing stop') child.sendline('stop') child.expect('\[dnsconfig@.*# ') report_info('=> issuing start') child.sendline('start') child.expect('\[dnsconfig@.*# ') child.sendline('exit') child.expect('\[view@.*> ') child.sendline('exit') child.close() report_info('=> restart done') return def quick_parse(): #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) os.chdir(pwd) return named def run_named_check(named): #-- run named-checkconf on the config file and then run named-checkzone # on each zone file chkconf = conf.getValue('named-checkconf') if os.path.exists(chkconf): fname = conf.getValue('named_root') fname += '/' + conf.getValue('named_conf') report_info('=> running "%s" on "%s"...' % (chkconf, fname)) (output, errors) = run_cmd_capture(chkconf + ' ' + fname) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? wanted to run named-checkconf, dude, but it's not there.") chkzone = conf.getValue('named-checkzone') if os.path.exists(chkzone): zdict = named.getZones() zlist = zdict.keys() zlist.sort() rname = named.getOptions().getDirectory().replace('"','') report_info('=> running "%s" on all zones...' % (chkzone)) prog = re.compile(':[0-9][0-9]*:') for ii in zlist: zone = zdict[ii].getName() zfile = rname + '/' + zdict[ii].getFile() (output, errors) = run_cmd_capture(chkzone + ' ' + zone + ' ' + zfile) if len(output) > 0 and prog.search(output) != None: report_info(output.strip()) else: report_error("? wanted to run named-checkzone, dude, but it's not there.") return def run_zonec(): zonec = conf.getValue('zonec_cmd') if os.path.exists(zonec): report_info('=> running the zone compiler "%s"...' % (zonec)) fname = conf.getValue('nsd_conf') tmpdir = conf.getValue('tmpdir') cmd = zonec + ' -c ' + tmpdir + '/' + fname + ' -d ' + tmpdir cmd += ' -f ' + tmpdir + '/zone.db' os.system('rm -f ' + tmpdir + '/zone.db') (output, errors) = run_cmd_capture(cmd) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? hmph. wanted to run zonec, but it's not there.") return #-- main --------------------------------------------------------------- def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'ahnsv', ['analyze-only', 'help', 'now', 'sync-only', 'verbose'] ) except getopt.GetoptError: usage() sys.exit(1) now = False analyze_only = False sync_only = False for ii, val in opts: if ii in ('-a', '--analyze-only'): analyze_only = True if ii in ('-h', '--help'): usage() sys.exit(0) if ii in ('-n', '--now'): now = True if ii in ('-s', '--sync-only'): sync_only = True if ii in ('-v', '--verbose'): set_verbosity(True) last_stat = {} this_stat = {} #-- don't poll unless we need to... if now: rebuild_nsd_files() cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we just need to sync up to the Secure64 machine... if sync_only: cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we're just checking things out... if analyze_only: #-- well, and do a couple of extra things, too set_verbosity(True) report_info( \ 's64-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version'))) named = quick_parse() rebuild_nsd_files() run_named_check(named) cp_files(analyze_only) run_zonec() sys.exit(0) #-- apparently we need to poll... tmplist = conf.getValue('named_watchlist').split() watchlist = [] for ii in tmplist: watchlist.append(ii.strip()) while True: for ii in watchlist: if ii in last_stat.keys(): statinfo = os.stat(ii) this_stat[ii] = (statinfo.st_size, statinfo.st_mtime) (old_size, old_mtime) = last_stat[ii] (new_size, new_mtime) = this_stat[ii] if old_size != new_size or old_mtime != new_mtime: report_info('aha! "%s" has changed!' % (ii)) last_stat[ii] = (new_size, new_mtime) rebuild_nsd_files() cp_files(analyze_only) restart_nsd() else: statinfo = os.stat(ii) last_stat[ii] = (statinfo.st_size, statinfo.st_mtime) this_stat[ii] = last_stat[ii] time.sleep(int(conf.getValue('sleep_time'))) sys.exit(0) #-- just in case if __name__ == '__main__': main() nsd-4.12.0/contrib/bind2nsd/scripts/s64-mkpw0000644000175000017500000000510015002373054020136 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # encrypt a passwd (very simplistic for now, using GPG or such-like # key someday) # # #-- imports import os import os.path import sys import getpass import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * else: from bind2nsd.Config import * if os.path.exists('../pyDes-1.2'): sys.path.append('../pyDes-1.2') import pyDes #-- globals conf = Config() #-- useful functions def usage(): print 's64-mkpw %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: s64-mkpw' return def mkprintable(val): cstr = '' for ii in range(0, len(val)): c = val[ii] cstr += '%d ' % (ord(c)) return cstr #-- main --------------------------------------------------------------- def main(): if len(sys.argv) > 1: usage() sys.exit(1) print 's64-mkpw %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) syspw = getpass.getpass('sysconfig password: ') dnspw = getpass.getpass('dnsconfig password: ') fd = open(conf.getValue('password_file'), 'w+') obj = pyDes.triple_des('aBcDeFgHiJkLmNoP', pyDes.ECB) fd.write(mkprintable(obj.encrypt(syspw, '#')) + '\n') fd.write(mkprintable(obj.encrypt(dnspw, '#')) + '\n') fd.close() print '=> stored password in "%s"' % (conf.getValue('password_file')) return if __name__ == '__main__': main() nsd-4.12.0/contrib/bind2nsd/scripts/nsd-sync0000644000175000017500000002604015002373054020312 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # When named.conf changes, update the NSD machine # # #-- imports import getopt import os import os.path import popen2 import re import sys import time if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from NamedConf import * from NsdConf import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * from bind2nsd.Utils import * if os.path.exists('../pexpect-2.1'): sys.path.append('../pexpect-2.1') import pexpect import pxssh #-- globals conf = Config() #-- useful functions def usage(): print 'nsd-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: nsd-sync [-a|--analyze-only] [-h|--help] [-s|--sync-only]' print ' [-n|--now]' print ' -a | --analyze-only => look for and report errors, but do' print ' not sync with the NSD server' print ' -h | --help => print this message and quit' print ' -n | --now => do not poll, sync immediately' print ' -s | --sync-only => sync without translating BIND files' print ' -v | --verbose => output lots of info' return def rebuild_nsd_files(): result = False xlate = conf.getValue('bind2nsd') if os.path.exists(xlate): result = run_cmd(xlate, 'running bind2nsd...') else: report_error('? could not find "%s" and have got to have it' % (xlate)) report_error(' skipping rebuild of NSD files') return result def scp_target(): #-- do the scp to an actual NSD server report_info('=> using scp to transfer to NSD system...') tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- this feels a bit dodgy due to issues in pexpect when it goes # up against passwd and other such nastiness from scp/ssh -- all # we should have to do is child.wait() really, but that does not # work as it should. # # NB: it turn out that you can _not_ put a '*' at the end of the # source path; pexpect.spawn() screws up and the parsing of the string # and ends up ignoring everything up to the '*', meaning the command # does not have the 'scp' part in it and does not get executed properly. # pwd = os.getcwd() os.chdir(tmpdir) flist = os.listdir('.') fnames = ' '.join(flist) cmd = 'scp -r ' + fnames cmd += ' ' + conf.getValue('destuser') + '@' cmd += conf.getValue('dest-ip') + ':' report_info('=> ' + cmd) child = pexpect.spawn(cmd) if len(conf.getValue('dnspw')) > 0: child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('.*' + conf.getValue('nsd_conf') + '.*') child.expect(pexpect.EOF) child.close() os.chdir(pwd) return def cp_files(analyze): #-- we assume everything has already been copied to the tmpdir by bind2nsd if analyze: return tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- scp the entire tmp directory if conf.getValue('DEMO-MODE'): report_info('** scp would go here, but cp -r for demonstration purposes') cmd = 'cp -r ' + tmpdir + '* ' + conf.getValue('destdir') run_cmd(cmd, 'using cp to transfer to demo system...') else: scp_target() return def restart_nsd(): if conf.getValue('DEMO-MODE'): cmd = conf.getValue('stop_cmd') run_cmd(cmd, 'stopping nsd...') # BOZO: rebuild is not behaving when there are errors, so the hack is # to remove the existing db, run the zone compiler and restart nsd #cmd = conf.getValue('rebuild_cmd') #os.system(cmd) cmd = 'rm -f ' + conf.getValue('database') run_cmd(cmd, 'removing old zonedb...') cmd = conf.getValue('zonec_cmd') run_cmd(cmd, 'rebuilding zonedb...') cmd = conf.getValue('start_cmd') run_cmd(cmd, 'starting nsd...') else: cmd = 'ssh -a -x ' cmd += conf.getValue('destuser') + '@' + conf.getValue('dest-ip') child = pexpect.spawn(cmd) if not child.isalive(): bail('? cannot login to NSD system at %s' % \ (conf.getValue('dest-ip'))) else: report_info('=> restarting NSD on %s' % \ (conf.getValue('dest-ip'))) child.expect('.*ssword:') child.sendline(conf.getValue('syspw')) child.expect('# ') report_info('=> now logged in') report_info('=> issuing zonec') child.sendline(conf.getValue('zonec_cmd')) if isVerbose(): child.logfile = sys.stdout child.expect('# ') report_info('=> issuing stop') child.sendline(conf.getValue('stop_cmd')) child.expect('# ') report_info('=> issuing start') child.sendline(conf.getValue('start_cmd')) child.expect('# ') child.sendline('exit') child.close() report_info('=> restart done') return def quick_parse(): #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) os.chdir(pwd) return named def run_named_check(named): #-- run named-checkconf on the config file and then run named-checkzone # on each zone file chkconf = conf.getValue('named-checkconf') if os.path.exists(chkconf): fname = conf.getValue('named_root') fname += '/' + conf.getValue('named_conf') report_info('=> running "%s" on "%s"...' % (chkconf, fname)) (output, errors) = run_cmd_capture(chkconf + ' ' + fname) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? wanted to run named-checkconf, dude, but it's not there.") chkzone = conf.getValue('named-checkzone') if os.path.exists(chkzone): zdict = named.getZones() zlist = zdict.keys() zlist.sort() rname = named.getOptions().getDirectory().replace('"','') report_info('=> running "%s" on all zones...' % (chkzone)) prog = re.compile(':[0-9][0-9]*:') for ii in zlist: zone = zdict[ii].getName() zfile = rname + '/' + zdict[ii].getFile() (output, errors) = run_cmd_capture(chkzone + ' ' + zone + ' ' + zfile) if len(output) > 0 and prog.search(output) != None: report_info(output.strip()) else: report_error("? wanted to run named-checkzone, dude, but it's not there.") return def run_zonec(): zonec = conf.getValue('zonec_cmd') if os.path.exists(zonec): report_info('=> running the zone compiler "%s"...' % (zonec)) fname = conf.getValue('nsd_conf') tmpdir = conf.getValue('tmpdir') cmd = zonec + ' -c ' + tmpdir + '/' + fname + ' -d ' + tmpdir cmd += ' -f ' + tmpdir + '/zone.db' os.system('rm -f ' + tmpdir + '/zone.db') (output, errors) = run_cmd_capture(cmd) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? hmph. wanted to run zonec, but it's not there.") return #-- main --------------------------------------------------------------- def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'ahnsv', ['analyze-only', 'help', 'now', 'sync-only', 'verbose'] ) except getopt.GetoptError: usage() sys.exit(1) now = False analyze_only = False sync_only = False for ii, val in opts: if ii in ('-a', '--analyze-only'): analyze_only = True if ii in ('-h', '--help'): usage() sys.exit(0) if ii in ('-n', '--now'): now = True if ii in ('-s', '--sync-only'): sync_only = True if ii in ('-v', '--verbose'): set_verbosity(True) last_stat = {} this_stat = {} #-- don't poll unless we need to... if now: rebuild_nsd_files() cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we just need to sync up to the machine... if sync_only: cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we're just checking things out... if analyze_only: #-- well, and do a couple of extra things, too set_verbosity(True) report_info( \ 'nsd-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version'))) named = quick_parse() rebuild_nsd_files() run_named_check(named) cp_files(analyze_only) run_zonec() sys.exit(0) #-- apparently we need to poll... tmplist = conf.getValue('named_watchlist').split() watchlist = [] for ii in tmplist: watchlist.append(ii.strip()) while True: for ii in watchlist: if ii in last_stat.keys(): statinfo = os.stat(ii) this_stat[ii] = (statinfo.st_size, statinfo.st_mtime) (old_size, old_mtime) = last_stat[ii] (new_size, new_mtime) = this_stat[ii] if old_size != new_size or old_mtime != new_mtime: report_info('aha! "%s" has changed!' % (ii)) last_stat[ii] = (new_size, new_mtime) rebuild_nsd_files() cp_files(analyze_only) restart_nsd() else: statinfo = os.stat(ii) last_stat[ii] = (statinfo.st_size, statinfo.st_mtime) this_stat[ii] = last_stat[ii] time.sleep(int(conf.getValue('sleep_time'))) sys.exit(0) #-- just in case if __name__ == '__main__': main() nsd-4.12.0/contrib/bind2nsd/scripts/bind2nsd0000644000175000017500000000641015002373054020256 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # Convert a BIND named.conf file to an NSD nsd.conf file # #-- imports import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from NamedConf import * from NsdConf import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * from bind2nsd.Utils import * #-- globals conf = Config() DEBUG = conf.getValue('DEBUG') #-- utility functions def usage(): print 'bind2nsd %s -- Copyright (c) 2007 Secure64 Software Corporation.' % \ (conf.getValue('version')) print 'usage: bind2nsd' print ' all options are controlled by the config file' return #-- main starts here ---------------------------------------------- if len(sys.argv) > 2: usage() sys.exit(1) elif len(sys.argv) == 2 and sys.argv[1] == '-v': set_verbosity(True) #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? er, cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) if DEBUG: named.dump() os.chdir(pwd) #-- open the nsd.conf file and write out the translated version, including # all of the zone files needed. note that we're stashing everything in # the tmpdir as if it were a chroot dir (it simplifies the copy to our # server later on. # # FIXME: this is not multi-user safe -- if someone runs two copies # with the same tmpdir, we're hosed # pwd = os.getcwd() tmpdir = conf.getValue('tmpdir') if not os.path.exists(tmpdir): os.makedirs(tmpdir) os.chdir(tmpdir) nsd_fname = conf.getValue('nsd_conf') report_info('=> writing translated configuration to \"%s\"...' % (nsd_fname)) nsd = NsdConf(conf) nsd.populate(named) if DEBUG: nsd.dump() nsd.write_conf() report_info('=> writing zone files to \"%s\"...' % (tmpdir)) nsd.write_zone_files() os.chdir(pwd) #-- all done sys.exit(0) nsd-4.12.0/contrib/bind2nsd/install.sh0000644000175000017500000000235415002373054017146 0ustar mozziemozzie#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # install script # python setup.py install (cd pexpect-2.1; python setup.py install) (cd pyDes-1.2; python setup.py install) nsd-4.12.0/contrib/bind2nsd/etc/0000755000175000017500000000000015002373054015713 5ustar mozziemozziensd-4.12.0/contrib/bind2nsd/etc/bind2nsd.conf0000644000175000017500000000653415002373054020275 0ustar mozziemozzie# Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # config file for bind2nsd # #--- parameters for the bind2nsd command --------------------------------- # default: named_root = /etc/bind9 # default: named_conf = named.conf # default: nsd_conf = nsd.conf # default: nsd_conf_dir = /etc/nsd/ # default: nsd_preamble = nsd.conf-preamble #--- options to fill in the blanks in nsd.conf --------------------------- # default: acl_list = "acl_list" # default: database = "nsd.db" => server data base name # default: difffile = "ixfr.db" => change data base on server # default: identity = "unknown" => nodename for server # default: ip-address = 127.0.0.1 1.2.3.4 => listen for requests on these # default: logfile = "log" => nsd log file on server # default: pidfile = "pid" => nsd pid file on server # default: port = 53 # default: statistics = 3600 # default: username = nsd # default: xfrd-reload-timeout = 10 #-- parameters for s64-sync or s64-mkpw ----------------------------------- # default: bind2nsd = /usr/bin/bind2nsd => where the translation script lives # default: dest-ip = 127.0.0.1 => where to copy to # default: destuser = dns => login name for scp (on server) # default: dnspw = iforgot => dnsconfig password (see s64-mkpw) # default: named-checkconf = /usr/sbin/named-checkconf => BIND command location # default: named-checkzone = /usr/sbin/named-checkzone => BIND command location # default: named_root = /etc/bind9 => default BIND config directory # default: named_conf = named.conf => BIND config file name # default: named_watchlist = /etc/named.conf => config files to poll # default: password_file = /etc/bind2nsd/passwd => encrypted passwords # default: sleep_time = 5 => poll time, in seconds # default: syspw = iforgot => sysconfig password (see s64-mkpw) # default: tmpdir = /tmp/secure64/ => must have trailing slash, is where the # xlated files are stashed #-- only useful in DEMO-MODE in s64-sync # default: destdir = /tmp/foobar => where to copy xlated files to # default: rebuild_cmd = /etc/init.d/nsdc rebuild => rebuild zonedb # default: restart_cmd = /etc/init.d/nsdc restart => restart nsd # default: start_cmd = /etc/init.d/nsdc start => start nsd # default: stop_cmd = /etc/init.d/nsdc stop => stop nsd # default: zonec_cmd = /etc/init.d/zonec => invoke nsd zone compiler nsd-4.12.0/contrib/bind2nsd/chk_version0000644000175000017500000000271715002373054017404 0ustar mozziemozzie#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # see what version number we're at # SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py => ${CONFIGV}" nsd-4.12.0/contrib/bind2nsd/bind2nsd/0000755000175000017500000000000015002373054016643 5ustar mozziemozziensd-4.12.0/contrib/bind2nsd/bind2nsd/__init__.py0000644000175000017500000000217115002373054020755 0ustar mozziemozzie# Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # initialize the module # nsd-4.12.0/contrib/bind2nsd/bind2nsd/Zone.py0000644000175000017500000000637015002373054020136 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a zone file # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class Zone: def __init__(self, name): self.name = name self.file = '' self.type = '' self.masters = [] # empty unless we're a slave zone self.allow_transfer = [] self.also_notify = [] self.allow_notify = [] return def dump(self): report_info('=> Zone:') report_info(' name = %s' % (self.name)) report_info(' file = %s' % (self.file)) report_info(' type = %s' % (self.type)) report_info(' masters = %s' % (str(self.masters))) report_info(' allow_notify = %s' % (str(self.allow_notify))) report_info(' allow_transfer = %s' % (str(self.allow_transfer))) report_info(' also_notify = %s' % (str(self.also_notify))) return def setName(self, name): self.name = name return def getName(self): return self.name def setFile(self, file): self.file = file return def getFile(self): return self.file def setType(self, type): self.type = type return def getType(self): return self.type def addMaster(self, quad): self.masters.append(quad) return def setMasters(self, list): self.masters = list return def getMasters(self): return self.masters def addAllowTransfer(self, quad): self.allow_transfer.append(quad) return def setAllowTransfers(self, list): self.allow_transfer = list return def getAllowTransfer(self): return self.allow_transfer def addAlsoNotify(self, quad): self.also_notify.append(quad) return def setAlsoNotify(self, list): self.also_notify = list return def getAlsoNotify(self): return self.also_notify def addAllowNotify(self, quad): self.allow_notify.append(quad) return def setAllowNotify(self, list): self.allow_notify = list return def getAllowNotify(self): return self.allow_notify nsd-4.12.0/contrib/bind2nsd/bind2nsd/Utils.py0000644000175000017500000000465115002373054020323 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # utility functions used throughout the package # # import popen2 import sys VERBOSE = False def set_verbosity(flag): global VERBOSE VERBOSE = flag return def isVerbose(): global VERBOSE return VERBOSE def report_error(somestuff): if len(somestuff) > 0: print >> sys.stderr, somestuff sys.stderr.flush() return def report_info(somestuff): global VERBOSE if VERBOSE and len(somestuff) > 0: print >> sys.stdout, somestuff sys.stdout.flush() return def bail(somestuff): report_error(somestuff) sys.exit(1) return def run_cmd_capture(cmd): (cout, cin, cerr) = popen2.popen3(cmd) cin.close() output = cout.readlines() cout.close() errors = cerr.readlines() cerr.close() return (''.join(output), ''.join(errors)) def run_cmd(cmd, desc): #-- run a command using our own particular idiom global VERBOSE result = True # T => ran without error reports, F otherwise if VERBOSE and len(desc) > 0: report_info('=> ' + desc) (cout, cin, cerr) = popen2.popen3(cmd) cin.close() output = cout.readlines() cout.close() if VERBOSE: report_info(''.join(output)) errors = cerr.readlines() cerr.close() if len(errors) > 0: result = False report_error(''.join(errors)) return result nsd-4.12.0/contrib/bind2nsd/bind2nsd/Tokenizer.py0000644000175000017500000001127215002373054021172 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to tokenize a named.conf file # # T_KEYWORD = 0 T_STRING = 1 T_LBRACE = 2 T_RBRACE = 3 T_SEMI = 4 T_COMMA = 5 T_QUAD = 6 T_COMMENT = 7 T_NAME = 8 T_EOF = 9 T_LPAREN = 10 T_RPAREN = 11 NAMED_KEYWORDS = [ 'algorithm', 'allow-notify', 'allow-recursion', 'allow-transfer', 'also-notify', 'category', 'channel', 'check-names', 'controls', 'coresize', 'directory', 'dump-file', 'file', 'IN', 'in', 'include', 'key', 'keys', 'logging', 'masters', 'options', 'pid-file', 'print-time', 'recursive-clients', 'secret', 'severity', 'statistics-file', 'syslog', 'transfer-format', 'type', 'version', 'versions', 'zone', ] class Tokenizer: def __init__(self, fname): infile = file(fname) self.data = ''.join(infile.readlines()) self.curpos = 0 self.lastpos = len(self.data) self.line = 1 return def get(self): tok = '' done = False while not done: if self.curpos >= self.lastpos: return (T_EOF, None, self.line) c = self.data[self.curpos] if c == '\n': self.line += 1 if c.isspace(): self.curpos += 1 continue elif c == '{': self.curpos += 1 return (T_LBRACE, c, self.line) elif c == '}': self.curpos += 1 return (T_RBRACE, c, self.line) elif c == '(': self.curpos += 1 return (T_LPAREN, c, self.line) elif c == ')': self.curpos += 1 return (T_RPAREN, c, self.line) elif c == ';': self.curpos += 1 return (T_SEMI, c, self.line) elif c == '#': while c != '\n': tok += c self.curpos += 1 c = self.data[self.curpos] self.curpos += 1 if c == '\n': self.line += 1 return (T_COMMENT, tok, self.line) elif c == '"': tok += c self.curpos += 1 c = self.data[self.curpos] while c != '"': tok += c self.curpos += 1 c = self.data[self.curpos] tok += c self.curpos += 1 return (T_STRING, tok, self.line) elif c == '/' and self.data[self.curpos+1] == '/': while c != '\n': tok += c self.curpos += 1 c = self.data[self.curpos] if c == '\n': self.line += 1 self.curpos += 1 return (T_COMMENT, tok, self.line) elif c == '/' and self.data[self.curpos+1] == '*': cmtDone = False tok += c tok += self.data[self.curpos+1] self.curpos += 2 c = self.data[self.curpos] while not cmtDone: if c == '*' and self.data[self.curpos+1] == '/': tok += c tok += self.data[self.curpos+1] self.curpos += 2 return (T_COMMENT, tok, self.line) else: tok += c if c == '\n': self.line += 1 self.curpos +=1 c = self.data[self.curpos] return (T_COMMENT, tok, self.line) elif c.isdigit(): tok += c self.curpos += 1 c = self.data[self.curpos] while c.isdigit() or c == '.' or c == '/': tok += c self.curpos += 1 c = self.data[self.curpos] return (T_QUAD, tok, self.line) else: while c.isalnum() or c == '_' or c == '-' or c == '.': tok += c self.curpos += 1 c = self.data[self.curpos] if tok in NAMED_KEYWORDS: return (T_KEYWORD, tok, self.line) else: return (T_NAME, tok, self.line) return def dump(self): print 'Tokenizer raw data:' print 'cur, last: %d, %d' % (self.curpos, self.lastpos) print self.data return nsd-4.12.0/contrib/bind2nsd/bind2nsd/Parser.py0000644000175000017500000003650515002373054020462 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class containing the parser for BIND configuration files # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from NamedConf import * from Zone import * from Key import * from Tokenizer import * from Utils import * else: from bind2nsd.NamedConf import * from bind2nsd.Zone import * from bind2nsd.Key import * from bind2nsd.Tokenizer import * from bind2nsd.Utils import * #-- the following options {} clauses are currently currently ignored, # typically because they are not implemented or not applicable to NSD IGNORED_OPTIONS = [ 'cleaning-interval', 'datasize', 'interface-interval', 'max-cache-size', 'stacksize', ] class Parser: def __init__(self, named): self.named = named return def handle_include(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_STRING: fname = val.replace('"', '') self.named.includes.append(fname) report_info(' include file "%s"...' % (fname)) if os.path.exists(fname): self.parse(Tokenizer(fname)) else: report_error('? missing include file "%s"' % (fname)) else: bail('? dude. where is the filename string after "include"?') (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "include" (%d: %s)' % (ttype, val)) return def handle_key(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_STRING: name = val.replace('"', '') key = Key(name) (ttype, val, curline) = tokens.get() if ttype != T_LBRACE: bail('? need opening brace for "key" defn (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() while ttype != T_RBRACE: if ttype == T_KEYWORD and val == 'algorithm': (ttype, val, curline) = tokens.get() if ttype == T_KEYWORD or ttype == T_NAME: key.setAlgorithm(val) else: bail('? bogosity after "algorithm" (%d: %s)' % (ttype, val)) elif ttype == T_KEYWORD and val == 'secret': (ttype, val, curline) = tokens.get() if ttype == T_STRING: s = val.replace('"','') key.setSecret(s) else: bail('? bogosity after "secret" (%d: %s)' % (ttype, val)) elif ttype == T_SEMI: pass (ttype, val, curline) = tokens.get() else: bail('? need to have a string after "key" (%d: %s)' % (ttype, val)) self.named.addKey(key) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "key" (%d: %s)' % (ttype, val)) return def handle_server(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_QUAD: ipaddr = val (ttype, val, curline) = tokens.get() if ttype != T_LBRACE: bail('? need opening brace for "server" (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() while ttype != T_RBRACE: if ttype == T_KEYWORD and val == 'keys': (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: nlist = self.name_list(val, tokens) for ii in nlist: self.named.keys[ii].addIpAddr(ipaddr) else: bail('? bogosity after "keys" (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() else: bail('? need to have an IP address after "server" (%d: %s)' % \ (ttype, val)) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "server" (%d: %s)' % (ttype, val)) return def name_list(self, name, tokens): nlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_NAME: nlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass else: bail('? was expecting a name in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return nlist def quad_list(self, name, tokens): qlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_QUAD: qlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass else: bail('? was expecting a quad in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return qlist def quad_list_with_keys(self, name, tokens, named): qlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_QUAD: qlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass elif ttype == T_KEYWORD and val == 'key': (ttype, val, curline) = tokens.get() if ttype == T_NAME: if val in named.getKeys(): qlist.append(val) else: bail('? was expecting a key name in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) else: bail('? was expecting a quad in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return qlist def skip_value(self, name, tokens): (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_STRING: pass else: bail('? need something after "%s" keyword (%d: %s)' % (name, ttype, val)) return def handle_options(self, tokens): report_info('=> processing server options') optsDone = False depth = 0 (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: depth += 1 else: bail('? urk. bad info after "options" keyword.') (ttype, val, curline) = tokens.get() while not optsDone: if ttype == T_KEYWORD and val == 'directory': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setDirectory(val) else: bail('? need string after "directory" keyword') elif ttype == T_KEYWORD and val == 'dump-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setDumpFile(val) else: bail('? need string after "dump-file" keyword') elif ttype == T_KEYWORD and val == 'pid-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setPidFile(val) else: bail('? need string after "pid-file" keyword') elif ttype == T_KEYWORD and val == 'coresize': (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_KEYWORD: self.named.options.setCoresize(val) else: bail('? need name after "coresize" keyword (%d: %s)' % \ (ttype, val)) elif ttype == T_KEYWORD and val == 'version': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setVersion(val) else: bail('? need string after "version" keyword') elif ttype == T_KEYWORD and val == 'transfer-format': (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_KEYWORD: self.named.options.setTransferFormat(val) else: bail('? need name after "transfer-format" keyword (%d: %s)' % \ (ttype, val)) elif ttype == T_KEYWORD and val == 'statistics-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setStatisticsFile(val) else: bail('? need string after "statistics-file" keyword') elif ttype == T_KEYWORD and val == 'allow-transfer': qlist = self.quad_list_with_keys(val, tokens, self.named) self.named.options.setAllowTransfer(qlist) elif ttype == T_KEYWORD and val == 'allow-notify': qlist = self.quad_list(val, tokens) self.named.options.setAllowNotify(qlist) elif ttype == T_KEYWORD and val == 'also-notify': qlist = self.quad_list(val, tokens) self.named.options.setAlsoNotify(qlist) elif ttype == T_KEYWORD and val == 'allow-recursion': qlist = self.quad_list(val, tokens) self.named.options.setAllowRecursion(qlist) elif ttype == T_KEYWORD and val == 'check-names': (ttype, val, curline) = tokens.get() info = [] while ttype != T_SEMI: info.append(val) (ttype, val, curline) = tokens.get() self.named.options.addCheckNames(' '.join(info)) elif ttype == T_KEYWORD and val in IGNORED_OPTIONS: self.skip_value(val, tokens) elif ttype == T_KEYWORD and val == 'recursive-clients': (ttype, val, curline) = tokens.get() if ttype == T_QUAD: # well, it's a number, actually... self.named.options.setRecursiveClients(val) else: bail('? need value after "recursive-clients" keyword (%d: %s)' % (ttype, val)) elif ttype == T_RBRACE: optDone = True break (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? um, junk after closing brace of "options" section') return def handle_zone(self, tokens): (ttype, val, curline) = tokens.get() if ttype != T_STRING: bail('? expected string for zone name (%d: %s)' % (ttype, val)) zname = val.replace('"','') zone = Zone(zname) (ttype, val, curline) = tokens.get() if ttype == T_KEYWORD and (val == 'in' or val == 'IN'): (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_KEYWORD and val == 'type': (ttype, val, curline) = tokens.get() info = [] while ttype == T_KEYWORD or ttype == T_NAME: info.append(val) (ttype, val, curline) = tokens.get() zone.setType(' '.join(info)) elif ttype == T_KEYWORD and val == 'file': (ttype, val, curline) = tokens.get() if ttype != T_STRING: bail('? eh? no string for zone file name? (%d: %s)' % \ (ttype, val)) fname = val.replace('"','') zone.setFile(fname) elif ttype == T_KEYWORD and val == 'masters': qlist = self.quad_list(val, tokens) zone.setMasters(qlist) elif ttype == T_KEYWORD and val == 'allow-transfer': qlist = self.quad_list_with_keys(val, tokens, self.named) zone.setAllowTransfers(qlist) elif ttype == T_KEYWORD and val == 'also-notify': qlist = self.quad_list(val, tokens) zone.setAlsoNotify(qlist) elif ttype == T_SEMI: pass else: bail('? bugger. do NOT grok "%s" yet (%d: %s @ line %s)' % \ (val, ttype, val, curline)) (ttype, val, curline) = tokens.get() self.named.addZone(zone) else: bail('? expected left brace to start zone definition (%d: %s)' % \ (ttype, val)) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "zone" (%d: %s)' % (ttype, val)) return def ignore_section(self, name, tokens): report_info('=> ignoring %s' % (name)) done = False depth = 0 (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: depth += 1 else: bail('? urk. bad info after "%s" keyword.' % (name)) (ttype, val, curline) = tokens.get() while not done: if ttype == T_LBRACE: depth += 1 elif ttype == T_RBRACE: depth -= 1 if depth == 0: break else: pass (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? um, junk after closing brace of "%s" section' % (name)) return def parse(self, tokens): (ttype, val, curline) = tokens.get() while ttype != T_EOF: if ttype == T_COMMENT: pass elif ttype == T_KEYWORD and val == 'controls': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'key': self.handle_key(tokens) elif ttype == T_KEYWORD and val == 'include': self.handle_include(tokens) elif ttype == T_KEYWORD and val == 'logging': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'lwres': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'options': self.handle_options(tokens) elif ttype == T_KEYWORD and val == 'server': self.handle_server(tokens) elif ttype == T_KEYWORD and val == 'trusted-keys': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'view': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'zone': self.handle_zone(tokens) else: bail('? ew. what _is_ this? -> %2d: %s @ line %d' \ % (ttype, val, curline)) (ttype, val, curline) = tokens.get() return nsd-4.12.0/contrib/bind2nsd/bind2nsd/NsdConf.py0000644000175000017500000003733515002373054020562 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a nsd.conf file # # import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class NsdKey: def __init__(self, name): self.name = name self.algorithm = '' self.secret = '' return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> NsdKey:' print >> ofile,' name = %s' % (self.name) print >> ofile,' algorithm = %s' % (self.algorithm) print >> ofile,' secret = %s' % (self.secret) else: print >> ofile, 'key:' print >> ofile,' name: "%s"' % (self.name) print >> ofile,' algorithm: %s' % (self.algorithm) print >> ofile,' secret: "%s"' % (self.secret) return def setName(self, val): self.name = val return def getName(self): return self.name def setAlgorithm(self, val): self.algorithm = val return def getAlgorithm(self): return self.algorithm def setSecret(self, val): self.secret = val return def getSecret(self): return self.secret class NsdZone: def __init__(self, name, config, ipkeymap): self.name = name self.config = config self.include = '' self.zonefile = '' self.type = '' self.allow_notify = [] # empty unless we're a slave zone self.also_notify = [] # empty unless we're a master zone self.provide_xfr = [] self.oldrootdir = '' self.ipkeymap = ipkeymap return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> NsdZone:' print >> ofile, ' name = %s' % (self.name) print >> ofile, ' include = %s' % (self.include) print >> ofile, ' zonefile = %s' % (self.zonefile) print >> ofile, ' type = %s' % (self.type) print >> ofile, ' allow_notify = %s' % (str(self.allow_notify)) print >> ofile, ' also_notify = %s' % (str(self.also_notify)) print >> ofile, ' provide_xfr = %s' % (str(self.provide_xfr)) else: print >> ofile, '' print >> ofile, 'zone:' print >> ofile, ' name: "%s"' % (self.name) print >> ofile, ' zonefile: "%s"' % (self.zonefile) # BOZO: this is a hack to avoid errors in the zone compiler # and needs to be handled more intelligently; this allows the # zone file to be non-existent (done by some ISPs) but still # listed in the named.conf if not os.path.exists(self.oldrootdir + self.zonefile): report_error('? missing zone file "%s"' % \ (self.oldrootdir + self.zonefile)) nlist = self.allow_notify if self.type == 'slave': print >> ofile, ' # this is a slave zone. masters are listed next.' for ii in nlist: print >> ofile, ' allow-notify: %s NOKEY' % (ii) print >> ofile, ' request-xfr: %s NOKEY' % (ii) else: print >> ofile, ' include: "%s"' % (self.include) for ii in self.also_notify: print >> ofile, ' notify: %s NOKEY' % (ii) for ii in self.provide_xfr: if ii in self.ipkeymap: print >> ofile, ' provide-xfr: %s %s' % (ii, self.ipkeymap[ii]) print >> ofile, ' notify: %s %s' % (ii, self.ipkeymap[ii]) else: print >> ofile, ' provide-xfr: %s NOKEY' % (ii) print >> ofile, ' notify: %s NOKEY' % (ii) return def setName(self, name): self.name = name return def getName(self): return self.name def setOldRootDir(self, name): self.oldrootdir = name return def getOldRootDir(self): return self.oldrootdir def setZonefile(self, file): self.zonefile = file return def getZonefile(self): return self.zonefile def setType(self, type): self.type = type return def getType(self): return self.type def addMaster(self, quad): self.masters.append(quad) return def getMasters(self): return self.masters def setInclude(self, name): self.include = name return def getInclude(self): return self.include def setAllowNotify(self, quad_list): self.allow_notify = quad_list return def getAllowNotify(self): return self.allow_notify def addAllowNotify(self, nlist): self.allow_notify.append(nlist) return def setAlsoNotify(self, quad_list): self.also_notify = quad_list return def getAlsoNotify(self): return self.also_notify def addAlsoNotify(self, nlist): self.also_notify.append(nlist) return def setProvideXfr(self, quad_list): self.provide_xfr = quad_list return def getProvideXfr(self): return self.provide_xfr class NsdOptions: def __init__(self, config): self.database = config.getValue('database') self.difffile = config.getValue('difffile') self.identity = config.getValue('identity') self.ip_address = config.getValue('ip-address') self.logfile = config.getValue('logfile') self.pidfile = config.getValue('pidfile') self.port = config.getValue('port') self.statistics = config.getValue('statistics') self.username = config.getValue('username') self.xfrd_reload_timeout = config.getValue('xfrd-reload-timeout') return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> Options:' print >> ofile, ' database: %s' % (self.database) print >> ofile, ' difffile: %s' % (self.difffile) print >> ofile, ' identity: %s' % (self.identity) print >> ofile, ' ip-address: %s' % (self.ip_address) print >> ofile, ' logfile: %s' % (self.logfile) print >> ofile, ' pidfile: %s' % (self.pidfile) print >> ofile, ' port: %s' % (self.port) print >> ofile, ' statistics: %s' % (self.statistics) print >> ofile, ' username: %s' % (self.username) print >> ofile, ' xfrd-reload-timeout: %s' % (self.xfrd_reload_timeout) else: print >> ofile, '#' print >> ofile, '# All of the values below have been pulled from' print >> ofile, '# either defaults or the config file' print >> ofile, '#' print >> ofile, '' print >> ofile, 'server:' print >> ofile, ' database: %s' % (self.database) print >> ofile, ' difffile: %s' % (self.difffile) print >> ofile, ' identity: %s' % (self.identity) iplist = self.ip_address.split() for ii in iplist: print >> ofile, ' ip-address: %s' % (ii.strip()) print >> ofile, ' logfile: %s' % (self.logfile) print >> ofile, ' pidfile: %s' % (self.pidfile) print >> ofile, ' port: %s' % (self.port) print >> ofile, ' statistics: %s' % (self.statistics) print >> ofile, ' username: %s' % (self.username) print >> ofile, ' xfrd-reload-timeout: %s' % \ (self.xfrd_reload_timeout) print >> ofile, '' return def setDatabase(self, name): self.database = name return def getDatabase(self): return self.database def setDifffile(self, name): self.difffile = name return def getDifffile(self): return self.difffile def setIdentity(self, name): self.identity = name return def getIdentity(self): return self.identity def setIpAddress(self, quad): self.ip_address = quad return def getIpAddress(self): return self.ip_address def setLogfile(self, val): self.logfile = val return def getLogfile(self): return self.logfile def setPort(self, val): self.port = val return def getPort(self): return self.port def setPidfile(self, val): self.pidfile = val return def getPidfile(self): return self.pidfile def setStatistics(self, val): self.statistics = val return def getStatistics(self): return self.statistics def setXfrdReloadTimeout(self, val): self.xfrd_reload_timeout = val return def getXfrdReloadTimeout(self): return self.xfrd_reload_timeout class NsdConf: def __init__(self, config): self.config = config self.fname = config.getValue('nsd_conf') self.files = config.getValue('nsd_files') self.preamble = config.getValue('nsd_preamble') self.acl_list = config.getValue('acl_list') self.oldrootdir = '' self.options = NsdOptions(config) self.includes = [] self.zones = {} self.keys = {} self.ipkeymap = {} return def populate(self, named): self.oldrootdir = named.getOptions().getDirectory().replace('"','') if self.oldrootdir[len(self.oldrootdir)-1] != '/': self.oldrootdir += '/' klist = named.getKeys() for ii in klist: oldk = named.getKey(ii) k = NsdKey(oldk.getName()) k.setAlgorithm(oldk.getAlgorithm()) k.setSecret(oldk.getSecret()) self.keys[k.getName()] = k #-- map each of the key ip addresses for faster lookup on dump() iplist = oldk.getIpAddrs() for jj in iplist: if jj not in self.ipkeymap: self.ipkeymap[jj] = k.getName() zlist = named.getZones() for ii in zlist: oldz = named.getZone(ii) z = NsdZone(oldz.getName(), self.config, self.ipkeymap) z.setZonefile(oldz.getFile()) z.setInclude(self.acl_list) z.setOldRootDir(self.oldrootdir) if 'slave' in oldz.getType().split(): z.setType('slave') # not used, but nice to know nlist = oldz.getMasters() for ii in nlist: z.addAllowNotify(ii) if len(oldz.getAllowNotify()) > 0: nlist = oldz.getAllowNotify() else: nlist = named.getOptions().getAllowNotify() for ii in nlist: z.addAllowNotify(ii) else: z.setType('master') if len(oldz.getAlsoNotify()): nlist = oldz.getAlsoNotify() else: nlist = named.getOptions().getAlsoNotify() for ii in nlist: z.addAlsoNotify(ii) if len(named.getOptions().getAllowTransfer()) > 0: z.setProvideXfr(named.getOptions().getAllowTransfer()) self.zones[z.getName()] = z return def dump(self): report_info('=> NsdConf: dumping data from \"%s\"...' % (self.fname)) self.options.dump(sys.stdout) report_info('=> NsdConf: list of includes...') report_info( str(self.includes)) report_info('=> NsdConf: zone info...') zlist = self.zones.keys() zlist.sort() for ii in zlist: self.zones[ii].dump(sys.stdout) report_info('=> NsdConf: key info...') klist = self.keys.keys() klist.sort() for ii in klist(): self.keys[ii].dump(sys.stdout) return def write_conf(self): nfile = open(self.fname, 'w+') self.options.dump(nfile) klist = self.keys.keys() klist.sort() for ii in klist: self.keys[ii].dump(nfile) zlist = self.zones.keys() zlist.sort() for ii in zlist: report_info(' writing info for zone "%s"...' % (self.zones[ii].getName())) self.zones[ii].dump(nfile) nfile.close() return def do_generate(self, newfd, start, stop, step, lhs, rrtype, rhs): #-- write the equivalent of the $GENERATE for ii in range(start, stop, step): left = lhs.replace('$', str(ii)) right = rhs.replace('$', str(ii)) print >> newfd, '%s %s %s' % (left, rrtype, right) return def make_zone_copy(self, oldpath, newpath): #-- copy the zone file line-by-line so we can catch $GENERATE usage report_info('=> copying "%s" to "%s"' % (oldpath, newpath)) if not os.path.exists(oldpath): os.system('touch ' + newpath) return oldfd = open(oldpath, 'r+') newfd = open(newpath, 'w+') line = oldfd.readline() while line: fields = line.split() if len(fields) > 0 and fields[0].strip() == '$GENERATE': report_info('=> processing "%s"...' % (line.strip())) index = 1 #-- determine start/stop range indices = fields[index].split('-') start = 0 stop = 0 if len(indices) == 2: start = int(indices[0]) stop = int(indices[1]) if stop < start: bail('? stop < start in range "%s"' % (fields[1].strip())) else: bail('? invalid range "%s"' % (fields[1].strip())) index += 1 #-- determine increment step = 1 if len(fields) == 6: step = int(fields[index]) index += 1 #-- get lhs lhs = fields[index].strip() index += 1 #-- get RR type rrtype = fields[index].strip() if rrtype not in [ 'NS', 'PTR', 'A', 'AAAA', 'DNAME', 'CNAME' ]: bail('? illegal RR type "%s"' % (rrtype)) index += 1 #-- get rhs rhs = fields[index].strip() index += 1 #-- do the $GENERATE self.do_generate(newfd, start, stop, step, lhs, rrtype, rhs) else: #-- just copy the line as is print >> newfd, line, line = oldfd.readline() oldfd.close() newfd.close() return def write_zone_files(self): acls = {} zlist = self.zones.keys() zlist.sort() for ii in zlist: oldpath = self.oldrootdir + self.zones[ii].getZonefile() newpath = self.config.getValue('tmpdir') + self.zones[ii].getZonefile() if not os.path.exists(os.path.dirname(newpath)): os.makedirs(os.path.dirname(newpath)) self.make_zone_copy(oldpath, newpath) incl = self.zones[ii].getInclude() if acls.has_key(incl): acls[incl] += 1 else: acls[incl] = 1 alist = acls.keys() alist.sort() for ii in alist: newpath = self.config.getValue('tmpdir') + ii run_cmd('touch ' + newpath, 'touch "%s"' % (newpath)) return def addZone(self, zone): name = zone.getName() self.zones[name] = zone return def getZones(self): return self.zones def addKey(self, key): self.keys[key.getName()] = key return def getKeys(self): return self.keys def getKey(self, name): if name in self.keys: return self.keys[name] else: return None nsd-4.12.0/contrib/bind2nsd/bind2nsd/NamedConf.py0000644000175000017500000001446415002373054021060 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a named.conf file # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from Parser import * from Zone import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.Parser import * from bind2nsd.Zone import * from bind2nsd.Utils import * class Options: def __init__(self): self.allow_notify = [] self.allow_recursion = [] self.allow_transfer = [] self.also_notify = [] self.check_names = [] self.coresize = "" self.directory = "" self.dump_file = "" self.pid_file = "" self.recursive_clients = "" self.statistics_file = "" self.transfer_format = "" self.version = "" return def dump(self): report_info('=> Options:') report_info(' allow-notify: %s' % (self.allow_notify)) report_info(' allow-recursion: %s' % (self.allow_recursion)) report_info(' allow-transfer: %s' % (self.allow_transfer)) report_info(' also-notify: %s' % (self.also_notify)) report_info(' check-names: %s' % (str(self.check_names))) report_info(' coresize: %s' % (self.coresize)) report_info(' directory: %s' % (self.directory)) report_info(' dump-file: %s' % (self.dump_file)) report_info(' pid-file: %s' % (self.pid_file)) report_info(' recursive-clients: %s' % (self.recursive_clients)) report_info(' statistics-file: %s' % (self.statistics_file)) report_info(' transfer-format: %s' % (self.transfer_format)) report_info(' version: %s' % (self.version)) return def setDirectory(self, name): self.directory = name return def getDirectory(self): return self.directory def setDumpFile(self, name): self.dump_file = name return def getDumpFile(self): return self.dump_file def setPidFile(self, name): self.pid_file = name return def getPidFile(self): return self.pid_file def setStatisticsFile(self, name): self.statistics_file = name return def getStatisticsFile(self): return self.statistics_file def addAllowNotify(self, quad): self.allow_notify.append(quad) return def setAllowNotify(self, list): self.allow_notify = list return def getAllowNotify(self): return self.allow_notify def addAllowTransfer(self, quad): self.allow_transfer.append(quad) return def setAllowTransfer(self, list): self.allow_transfer = list return def getAllowTransfer(self): return self.allow_transfer def addAlsoNotify(self, quad): self.also_notify.append(quad) return def setAlsoNotify(self, list): self.also_notify = list return def getAlsoNotify(self): return self.also_notify def addAllowRecursion(self, quad): self.allow_recursion.append(quad) return def setAllowRecursion(self, list): self.allow_recursion = list return def getAllowRecursion(self): return self.allow_recursion def addCheckNames(self, val): self.check_names.append(val) return def getCheckNames(self): return self.check_names def setCoresize(self, val): self.coresize = val return def getCoresize(self): return self.coresize def setTransferFormat(self, val): self.transfer_format = val return def getTransferFormat(self): return self.transfer_format def setVersion(self, val): self.version = val return def getVersion(self): return self.version def setRecursiveClients(self, val): self.recursive_clients = val return def getRecursiveClients(self): return self.recursive_clients class NamedConf: def __init__(self, fname): self.fname = fname self.options = Options() self.includes = [] self.zones = {} self.keys = {} parser = Parser(self) parser.parse(Tokenizer(self.fname)) return def dump(self): report_info('=> NamedConf: dumping data from \"%s\"...' % (self.fname)) self.options.dump() report_info('=> NamedConf: list of includes...') report_info(str(self.includes)) report_info('=> NamedConf: zone info...') zlist = self.zones.keys() zlist.sort() for ii in zlist: self.zones[ii].dump() report_info('=> NamedConf: key info...') klist = self.keys.keys() klist.sort() for ii in klist: self.keys[ii].dump() return def getOptions(self): return self.options def addZone(self, zone): name = zone.getName() self.zones[name] = zone return def getZones(self): return self.zones def getZone(self, name): if name in self.zones: return self.zones[name] else: return None def addKey(self, key): name = key.getName() self.keys[name] = key return def getKey(self, name): if name in self.keys: return self.keys[name] else: return None def getKeys(self): return self.keys nsd-4.12.0/contrib/bind2nsd/bind2nsd/Key.py0000644000175000017500000000443115002373054017747 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a named.conf key # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class Key: def __init__(self, name): self.name = name self.algorithm = '' self.secret = '' self.ipaddrs = [] return def dump(self): report_info('=> Key:') report_info(' algorithm = %s' % (self.algorithm)) report_info(' name = %s' % (self.name)) report_info(' secret = %s' % (self.secret)) report_info(' ipaddrs = %s' % (str(self.ipaddrs))) return def setName(self, val): self.name = val return def getName(self): return self.name def setAlgorithm(self, val): self.algorithm = val return def getAlgorithm(self): return self.algorithm def setSecret(self, val): self.secret = val return def getSecret(self): return self.secret def addIpAddr(self, addr): if addr not in self.ipaddrs: self.ipaddrs.append(addr) return def getIpAddrs(self): return self.ipaddrs nsd-4.12.0/contrib/bind2nsd/bind2nsd/Config.py0000644000175000017500000001247415002373054020432 0ustar mozziemozzie#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # class to represent all of the bind2nsd/syncem config items # import os import os.path import sys if os.path.exists('../pyDes-1.2'): sys.path.append('../pyDes-1.2') import pyDes def mkcipher(val): data = val.split() ctxt = '' for ii in range(0, len(data)): ctxt += chr(int(data[ii])) return ctxt def mkprintable(val): cstr = '' for ii in range(0, len(val)): c = val[ii] cstr += '%d ' % (ord(c)) return cstr class Config: def __init__(self): #-- set all of the defaults self.fname = '' self.config = \ { 'acl_list' : 'acl_list', 'bind2nsd' : '/usr/bin/bind2nsd', 'database' : '"nsd.db"', 'DEBUG' : False, 'DEMO-MODE' : False, 'destdir' : '/tmp/foobar', 'dest-ip' : '127.0.0.1', 'destuser' : 'dns', 'difffile' : '"ixfr.db"', 'dnspw' : 'iforgot', 'identity' : '"unknown"', 'ip-address' : '127.0.0.1', 'logfile' : '"log"', 'named-checkconf' : '/usr/sbin/named-checkconf', 'named-checkzone' : '/usr/sbin/named-checkzone', 'named_root' : '/etc/bind9', 'named_conf' : 'named.conf', 'named_watchlist' : '/etc/named.conf', 'nsd-checkconf' : '/usr/sbin/nsd-checkconf', 'nsd_conf' : 'nsd.conf', 'nsd_conf_dir' : '/etc/nsd/', 'nsd_preamble' : 'nsd.conf-preamble', 'password_file' : '/etc/bind2nsd/passwd', 'pidfile' : '"nsd.pid"', 'port' : '53', 'rebuild_cmd' : '/etc/init.d/nsdc rebuild', 'restart_cmd' : '/etc/init.d/nsdc restart', 'sleep_time' : '5', 'start_cmd' : '/etc/init.d/nsdc start', 'statistics' : '3600', 'stop_cmd' : '/etc/init.d/nsdc stop', 'syspw' : 'iforgot', 'tmpdir' : '/tmp/secure64/', # must have trailing '/' 'username' : 'nsd', 'version' : '0.5.0', 'xfrd-reload-timeout' : '10', 'zonec_cmd' : '/etc/init.d/zonec', } self.init() self.read_passwords() if self.config['DEBUG']: self.dump() return def init(self): fname = '' if os.path.exists('bind2nsd.conf'): self.fname = 'bind2nsd.conf' else: fname = os.getenv('HOME', '.') + '/bind2nsd.conf' if os.path.exists(fname): self.fname = fname else: if os.path.exists('/etc/bind2nsd/bind2nsd.conf'): self.fname = '/etc/bind2nsd/bind2nsd.conf' else: print '? hrm. no config file found -- did you _mean_ that?' #-- override the defaults if self.fname != '': fd = open(self.fname, 'r') line = fd.readline() while line: if len(line) > 0: info = line.split() if line[0] == '#': pass # ignore comments elif len(info) > 0: item = info[0].strip() if info[1].strip() == '=': if item in self.config: self.config[item] = ' '.join(info[2:]) else: pass # ignore lines with only one field else: pass # ignore empty lines line = fd.readline() return def read_passwords(self): fname = self.config['password_file'] if os.path.exists(fname): fd = open(fname, 'r+') syspw = fd.readline() dnspw = fd.readline() fd.close() obj = pyDes.triple_des('aBcDeFgHiJkLmNoP', pyDes.ECB) self.config['syspw'] = obj.decrypt(mkcipher(syspw), '#') self.config['dnspw'] = obj.decrypt(mkcipher(dnspw), '#') return def getValue(self, item): if item in self.config: return self.config[item] else: return None def setValue(self, item, val): if item in self.config: self.config[item] = val else: print '? no such config item "%s" (%s)' % (item, val) return def dump(self): print '=> Config:' print ' %-20s = %s' % ('fname', self.fname) for ii in self.config: print ' %-20s = %s' % (ii, self.config[ii]) return nsd-4.12.0/contrib/bind2nsd/TODO0000644000175000017500000000410715002373054015632 0ustar mozziemozzieto be done: =========== -- key {}'s have to be handled -- zone allow-transfer xlates to what in NSD? -- install process needs cleanup -- document install/update process -- performance: can this be improved? translation ought to be able to go quicker, perhaps by only handling changes vs complete re-translation every time -- license under MIT license and post to newly created bind2nsd.sf.net -- must handle 'control { ... }' settings? -- look for all 'BOZO's -- look for all 'FIXME's -- return code checking is abysmal, if done at all -- trap ctrl-C properly -- verify BIND named.conf grammar details -- verify NSD nsd.conf grammar details -- report specifically what line of what file has an error for ALL errors recently done: ============== -- can now report specifically what line of what file has an error and using it in some interesting places -- refactored the parser (much more maintainable now) -- acl_list: now set these up (as empty files) and copy them to the right places -- if scp does not require a password, and it is set to '' in the config file, then do not wait for the password prompt -- can now specify multiple ip-addresses for use in nsd.conf (and to say which one to scp to when sync'ing using 'dest-ip' option) -- zonec output again displayed when using 's64-sync --verbose' -- search for bind2nsd.conf in '.', $HOME, _and_ /etc/bind2nsd -- install config files, etc., in /etc/bind2nsd (passwd file, too) -- clean up example bind2nsd.conf -- set better config defaults -- GENERATE commands in the zone data are now intercepted and converted to the desired text (since we don't handle $GENERATE and it _is_ a BIND specific tool). -- Added in key xlation (i.e., 'key { ... }') -- 'options { pid-file } => server: pidfile' is ignorable -- handle options { recursive-clients nnn; } -- do not scp when using 's64-sync --analyze-only' -- handle allow-notify {} -- handle also-notify {} in options {} and in server {} or per zone -- create an 'nsd-sync' that works with any old NSD server on a remote machine (permutation of 's64-sync') nsd-4.12.0/contrib/bind2nsd/README0000644000175000017500000000312015002373054016014 0ustar mozziemozziebind2nsd -- translate from BIND named.conf to NSD nsd.conf -- then, sync up configuration files with a Secure64 server To install these tools on Linux systems: # ./install.sh Then, copy bind2nsd.conf to the directory you will run these commands from (e.g., /etc/named or /etc/bind9) and then edit the values properly. Passwords for logging into a Secure64 system can be stored in the bind2nsd.conf file (as clear text only) or can be stored encrypted by using the 'password_file' config item and the s64-mkpw utility. -- Copyright (c) 2007, Secure64 Software Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nsd-4.12.0/contrib/bind2nsd/MANIFEST0000644000175000017500000000036115002373054016271 0ustar mozziemozzieREADME setup.py bind2nsd/Config.py bind2nsd/Key.py bind2nsd/NamedConf.py bind2nsd/NsdConf.py bind2nsd/Parser.py bind2nsd/Tokenizer.py bind2nsd/Utils.py bind2nsd/Zone.py bind2nsd/__init__.py scripts/bind2nsd scripts/s64-mkpw scripts/s64-sync nsd-4.12.0/contrib/bind2nsd/ChangeLog0000644000175000017500000000500215002373054016707 0ustar mozziemozzie2007-07-24 Al Stone * bind2nsd/*, scripts/*: cleaned up the way modules were being imported so that it's much simpler, hopefully more reliable. * bind2nsd/Parser.py: added code to recognize but skip the view{}, trusted-keys{}, and lwres{} clauses; added quad_list_with_keys(). * bind2nsd/Zone.py: store allow-notify statements. 2007-07-18 Al Stone * bind2nsd/Config.py: do not open config file with r+ * bind2nsd/NamedConf.py: remove recursive module import when running in ways I hadn't tried. 2007-07-13 Al Stone * etc/: added in some files forgotten when conversion to FOSS.... * scripts/nsd-sync: ...including this one. 2007-07-06 Al Stone * TODO: update. * bind2nsd/Key.py: correct missing ')'. * bind2nsd/Tokenizer.py: reformatting. * bind2nsd/Parser.py: handle 'recursive-clients' option; handle 'allow-notify' option; handle 'also-notify' option in zones. * bind2nsd/NamedConf.py: handle 'allow-notify' option; handle 'also-notify' for simple cases. * bind2nsd/NsdConf.py: handle 'allow-notify' option; handle 'also-notify' for simple cases. 2007-06-29 Al Stone * TODO: update. * bind2nsd/NsdConf.py: when writing zone data files, look for any use of the $GENERATE directive and replace it with the proper RRs; populate info from 'key {}' in BIND. * bind2nsd/Parser.py: add in several 'options {}' clauses that we'll recognize but do nothing about for now; handle multiple 'key {}' clauses; recognize 'server {}' clauses. * bind2nsd/Key.py: add getName(); added self.ipaddrs and methods. * bind2nsd/NamedConf.py: allow for more than one 'key {}' clause. * bind2nsd/Tokenizer.py: added 'keys' as a keyword. 2007-06-28 Al Stone * TODO: update. * bind2nsd/Config.py: 'dest-ip' added as the place to scp files to; search for bind2nsd.conf in '.', $HOME, _and_ /etc/bind2nsd; the default for 'password' file is '/etc/bind2nsd/passwd' _not_ '/etc/secure64/passwd'. * bind2nsd/NsdConf.py: handle multiple 'ip-address' clauses in the 'server' section. * etc/bind2nsd.conf: add 'dest-ip'; add info on all options. * scripts/s64-sync: replace 'ip-address' with 'dest-ip'; make sure zonec output shows up when in verbose mode. * bind2nsd/Utils.py: added isVerbose(). 2007-06-27 Al Stone * TODO: update. * s64-sync: allow for scp to destination when no password needed; clean up demo-mode 'cp -r'. * Config.py: add 'destuser' option. nsd-4.12.0/contrib/bind2nsd/COPYING0000644000175000017500000000206315002373054016174 0ustar mozziemozzieCopyright (c) 2007, Secure64 Software Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nsd-4.12.0/contrib/autocomplete_nsd-control.bash0000644000175000017500000000147415002373054021325 0ustar mozziemozzie# nsd-control(1) completion -*- shell-script -*- _nsdcontrol() { local cur prev words cword _init_completion || return local WORDS case $prev in assoc_tsig|\ changezone|\ delzone|\ force_transfer|\ notify|\ reload|\ transfer|\ write|\ zonestatus) WORDS=$($1 zonestatus |awk '/zone:/ {print $2}' ORS=' ') COMPREPLY=($(compgen -W "$WORDS" -- "$cur")) return 0 ;; esac if [[ $cur == -* ]]; then WORDS=$($1 |awk '/^ -/ {print $1}' ORS=' ') elif ((cword == 1)); then WORDS=$($1 |awk '/^ [^-]/ {print $1}' ORS=' ') fi COMPREPLY=($(compgen -W "$WORDS" -- "$cur")) } && complete -F _nsdcontrol nsd-control # ex: filetype=sh nsd-4.12.0/contrib/README0000644000175000017500000000563215002373054014323 0ustar mozziemozzieThis is NSD contributions directory and it contains various additions to NSD that are not a part of the official distribution but may be helpful. USE AT YOUR OWN RISK. * nsd.spec: a rpm specfile to generate binary and source rpms. Put the source tarball in /usr/src/redhat/SOURCES. Then rpmbuild -ba nsd.spec * nsd.init: a shell script that can start, stop, restart the NSD daemon. It uses signals, and can be used in rc.d init scripts (depends on platform). * nsd.zones2nsd.conf: a python script to convert NSD 2 nsd.zones config files to NSD 3 nsd.conf config files. Do not forget to set nsd_zones_name and key_dir variables at the top of the script. * bind2nsd: a slightly abridged form is included; find the full source at http://bind2nsd.sourceforge.net. The bind2nsd scripts translate DNS information in BIND format to NSD format, and then copy that translation to an NSD server. The goal is to make it simple to run redundant BIND and NSD servers and keep them in sync, using only the BIND configuration files * nsd_munin_ : plugin for munin statistics report You must have given --enable-bind8-stats (default is on) to configure. Copy the file to /usr/share/munin/plugins (or you munin node dir). You may also need to create a number of symbolic links under the names of the graphs you want to create (documented at head of file). * nsd.service : example systemd service script for NSD. * patch_for_s6_startup_and_other_service_supervisors.diff : patch to use -r option for nsd to signal readiness with READY_FD, from Cameron Nemo. Apply with patch -p0 < contrib/patch_for_s6_startup_and_other_service_supervisors.diff * autocomplete_nsd-control.bash : It completes options, all commands and zone arguments for commands. From Christian Weiske. To use it, call: source contrib/autocomplete_nsd-control.bash * bug390.patch: Patch that returns a superfluous NSEC3 RR on wildcard queries This patch exists because there is a bug in the Bind9 resolver, before version 9.9.0. Bind9 before that version can not validate NSEC3 wildcard answer responses, it needs a superfluous NSEC3 RR. This patch will make NSD provide that NSEC3 RR. The patch was useful before there was a fix for the BIND resolver, to work around the issue. It is no longer useful after BIND got fixed in version 9.9.0 around 2013-05-16. * contrib/nsd-tmpfiles.conf.in, contrib/nsd.openrc.conf, contrib/nsd.openrc.in: An OpenRC service script and config file. The service script is integrated with the build system so that the correct paths are obtained from ./configure and do not need to be hard-coded. The nsd-tmpfiles.conf file is for both systemd and OpenRC. If installed, this will create at a boot a temporary "nsd" directory writable by the nsd user. This makes it easier to use a local control socket because the user no longer has to worry about creating the directory where the socket will live. nsd-4.12.0/configure.ac0000644000175000017500000013025515002373054014271 0ustar mozziemozziednl dnl Some global settings dnl sinclude(acx_nlnetlabs.m4) sinclude(dnstap/dnstap.m4) # autoconf-2.70 is needed for @runstatedir@ AC_PREREQ([2.70]) AC_INIT([NSD],[4.12.0],[https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl]) AC_CONFIG_HEADERS([config.h]) # # Setup the standard programs # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Setting-Output-Variables.html AC_ARG_VAR(SED, [location of the sed program]) AC_ARG_VAR(AWK, [location of the awk program]) AC_ARG_VAR(GREP, [location of the grep program]) AC_ARG_VAR(EGREP, [location of the egrep program]) AC_ARG_VAR(LEX, [location of the lex program with GNU extensions (flex)]) AC_ARG_VAR(YACC, [location of the yacc program with GNU extensions (bison)]) cmdln="`echo $@ | sed -e 's/\\\\/\\\\\\\\/g' | sed -e 's/"/\\\\"/'g`" AC_DEFINE_UNQUOTED(CONFCMDLINE, ["$cmdln"], [Command line arguments used with configure]) CFLAGS="$CFLAGS" AC_USE_SYSTEM_EXTENSIONS if test "$ac_cv_header_minix_config_h" = "yes"; then AC_DEFINE(_NETBSD_SOURCE,1, [Enable for compile on Minix]) fi dnl dnl By default set $sysconfdir to /etc and $localstatedir to /var dnl case "$prefix" in NONE) case "$sysconfdir" in '${prefix}/etc') sysconfdir=/etc ;; esac case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac ;; esac # # Determine configuration directory # configdir=$sysconfdir/nsd AC_ARG_WITH([configdir], AS_HELP_STRING([--with-configdir=dir],[NSD configuration directory]), [configdir=$withval]) AC_DEFINE_UNQUOTED(CONFIGDIR, ["`eval echo $configdir`"], [NSD config dir]) AC_SUBST(configdir) # # Determine configuration file nsd_conf_file=${configdir}/nsd.conf AC_ARG_WITH([nsd_conf_file], AS_HELP_STRING([--with-nsd_conf_file=path],[Pathname to the NSD configuration file]), [nsd_conf_file=$withval]) AC_SUBST(nsd_conf_file) # the eval is to evaluate shell expansion twice, once # for $nsd_conf_file and once for the ${prefix} within it. AC_DEFINE_UNQUOTED(CONFIGFILE, ["`eval echo $nsd_conf_file`"], [Pathname to the NSD configuration file]) # # Default logfile # logfile=${localstatedir}/log/nsd.log AC_ARG_WITH([logfile], AS_HELP_STRING([--with-logfile=path],[Pathname to the default log file]), [logfile=$withval]) AC_SUBST(logfile) # # Database directory # dbdir=${localstatedir}/db/nsd # # Determine the pidfile location. Check if /var/run exists, if so set pidfile # to /var/run/nsd.pid by default # if test -d ${localstatedir}/run; then pidfile=${localstatedir}/run/nsd.pid else pidfile=${dbdir}/nsd.pid fi AC_ARG_WITH([pidfile], AS_HELP_STRING([--with-pidfile=path],[Pathname to the NSD pidfile]), [pidfile=$withval]) AC_SUBST(pidfile) AC_DEFINE_UNQUOTED(PIDFILE, ["`eval echo $pidfile`"], [Pathname to the NSD pidfile]) AC_ARG_WITH([dbfile], AS_HELP_STRING([--with-dbfile=path],[Pathname to the NSD database (obsolete)]),[]) piddir=`dirname $pidfile` AC_SUBST(piddir) # # Determine the default directory for the zone files # zonesdir=$configdir AC_ARG_WITH([zonesdir], AS_HELP_STRING([--with-zonesdir=dir],[NSD default location for zone files]), [zonesdir=$withval]) AC_SUBST(zonesdir) AC_DEFINE_UNQUOTED(ZONESDIR, ["`eval echo $zonesdir`"], [NSD default location for zone files. Empty string or NULL to disable.]) # default xfrd file location. xfrdfile=${dbdir}/xfrd.state AC_ARG_WITH([xfrdfile], AS_HELP_STRING([--with-xfrdfile=path],[Pathname to the NSD xfrd zone timer state file]), [xfrdfile=$withval]) AC_DEFINE_UNQUOTED(XFRDFILE, ["`eval echo $xfrdfile`"], [Pathname to the NSD xfrd zone timer state file.]) AC_SUBST(xfrdfile) # default zonelist file location. zonelistfile=${dbdir}/zone.list AC_ARG_WITH([zonelistfile], AS_HELP_STRING([--with-zonelistfile=path],[Pathname to the NSD zone list file]), [zonelistfile=$withval]) AC_DEFINE_UNQUOTED(ZONELISTFILE, ["`eval echo $zonelistfile`"], [Pathname to the NSD zone list file.]) AC_SUBST(zonelistfile) # default cookiesecrets file location. cookiesecretsfile=${dbdir}/cookiesecrets.txt AC_ARG_WITH([cookiesecretsfile], AS_HELP_STRING([--with-cookiesecretsfile=path],[Pathname to the NSD cookie secrets file]), [cookiesecretsfile=$withval]) AC_DEFINE_UNQUOTED(COOKIESECRETSFILE, ["`eval echo $cookiesecretsfile`"], [Pathname to the NSD cookies secrets file.]) AC_SUBST(cookiesecretsfile) # default xfr dir location. xfrdir="/tmp" AC_ARG_WITH([xfrdir], AS_HELP_STRING([--with-xfrdir=path],[Pathname to where the NSD transfer dir is created]), [xfrdir=$withval]) AC_DEFINE_UNQUOTED(XFRDIR, ["`eval echo $xfrdir`"], [Pathname to where the NSD transfer dir is created.]) AC_SUBST(xfrdir) # nsd sbin location. tmpinstantiate execprefix with defaults if not yet done. if test "x${exec_prefix}" = "xNONE"; then if test "x${prefix}" = "xNONE"; then exec_prefix="$ac_default_prefix" else exec_prefix="${prefix}"; fi nsd_start_path="`eval echo $sbindir`/nsd" exec_prefix="NONE" else nsd_start_path="`eval echo $sbindir`/nsd" fi AC_DEFINE_UNQUOTED(NSD_START_PATH, ["$nsd_start_path"], [Pathname to start nsd from nsd-control]) # # Determine default chroot directory # AC_ARG_WITH([chroot], AS_HELP_STRING([--with-chroot=dir],[NSD default chroot directory]), [ chrootdir=$withval AC_DEFINE_UNQUOTED(CHROOTDIR, ["`eval echo $chrootdir`"], [NSD default chroot directory]) ]) AC_SUBST(chrootdir) # # Determine the user name to drop privileges to # user=nsd AC_ARG_WITH([user], AS_HELP_STRING([--with-user=username],[User name or ID to answer the queries with]), [user=$withval]) AC_SUBST(user) AC_DEFINE_UNQUOTED(USER, ["$user"], [the user name to drop privileges to]) m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC]) AC_PROG_SED AC_PROG_AWK AC_PROG_GREP AC_PROG_EGREP AC_PROG_LEX([noyywrap]) AC_PROG_YACC AC_PROG_LN_S AC_PROG_INSTALL if test "$LEX" != ":" -a "$LEX" != ""; then # Solaris provides anemic tools, and they don't offer GNU extensions like # 'flex -i'. Solaris also does not offer GNU replacements in /usr/gnu/bin. AC_MSG_CHECKING([whether lex accepts -i]) AS_IF([echo "%%" | $LEX -i -t >/dev/null 2>&1], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([unable to find a lexer that supports -i. If one is available then set the LEX variable]) ] ) # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, # but later could define it as a macro and then we should not redefine it. AC_MSG_CHECKING(if lex defines yy_current_buffer) cat <conftest.lex %% EOF $LEX -i -t conftest.lex >> conftest.c 2>/dev/null if $GREP "^#define yy_current_buffer" conftest.c >/dev/null; then AC_DEFINE_UNQUOTED(LEX_DEFINES_YY_CURRENT_BUFFER, 1, [If flex defines yy_current_buffer as a macro]) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi rm -f conftest.lex conftest.c fi AC_DEFUN([AC_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute) AC_CACHE_VAL(ac_cv_c_format_attribute, [ac_cv_c_format_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); ]], [[ f ("%s", "str"); ]])],[ac_cv_c_format_attribute="yes"],[ac_cv_c_format_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_format_attribute) if test $ac_cv_c_format_attribute = yes; then AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute]) fi ])dnl AC_DEFUN([AC_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute) AC_CACHE_VAL(ac_cv_c_unused_attribute, [ac_cv_c_unused_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include void f (char *u __attribute__((unused))); ]], [[ f ("x"); ]])],[ac_cv_c_unused_attribute="yes"],[ac_cv_c_unused_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_unused_attribute) if test $ac_cv_c_unused_attribute = yes; then AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) fi ])dnl AC_DEFUN([CHECK_WEAK_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "weak" attribute) AC_CACHE_VAL(ac_cv_c_weak_attribute, [ac_cv_c_weak_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include __attribute__((weak)) void f(int x) { printf("%d", x); } ]], [[ f(1); ]])],[ac_cv_c_weak_attribute="yes"],[ac_cv_c_weak_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_weak_attribute) if test $ac_cv_c_weak_attribute = yes; then AC_DEFINE(HAVE_ATTR_WEAK, 1, [Whether the C compiler accepts the "weak" attribute]) AC_DEFINE(ATTR_WEAK, [__attribute__((weak))], [apply the weak attribute to a symbol]) fi ])dnl End of CHECK_WEAK_ATTRIBUTE AC_DEFUN([CHECK_NORETURN_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "noreturn" attribute) AC_CACHE_VAL(ac_cv_c_noreturn_attribute, [ac_cv_c_noreturn_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include __attribute__((noreturn)) void f(int x) { printf("%d", x); } ]], [[ f(1); ]])],[ac_cv_c_noreturn_attribute="yes"],[ac_cv_c_noreturn_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_noreturn_attribute) if test $ac_cv_c_noreturn_attribute = yes; then AC_DEFINE(HAVE_ATTR_NORETURN, 1, [Whether the C compiler accepts the "noreturn" attribute]) AC_DEFINE(ATTR_NORETURN, [__attribute__((__noreturn__))], [apply the noreturn attribute to a function that exits the program]) fi ])dnl End of CHECK_NORETURN_ATTRIBUTE AC_DEFUN([CHECK_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | $SED 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ echo 'void f(void){}' >conftest.c if test -z "`$CC -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ]) if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $2 else AC_MSG_RESULT(no) : $3 fi ]) AC_DEFUN([AC_CHECK_CTIME_R], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether ctime_r works with two arguments) AC_CACHE_VAL(ac_cv_c_ctime_c, [ac_cv_c_ctime_c=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include void testing (void) { time_t clock; char current_time[40]; ctime_r(&clock, current_time); }]], [[ testing(); ]])],[ac_cv_c_ctime_c="yes"],[ac_cv_c_ctime_c="no"]) ]) AC_MSG_RESULT($ac_cv_c_ctime_c) if test $ac_cv_c_ctime_c = no; then CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" fi ])dnl # Checks for typedefs, structures, and compiler characteristics. # allow user to override the -g -O2 flags. if test "x$CFLAGS" = "x" ; then ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"]) # 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 AC_TYPE_UID_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_OFF_T AC_CHECK_FORMAT_ATTRIBUTE AC_CHECK_UNUSED_ATTRIBUTE CHECK_WEAK_ATTRIBUTE CHECK_NORETURN_ATTRIBUTE ACX_CHECK_MEMCMP_SIGNED AC_CHECK_CTIME_R # Checks for libraries. # Check for SSL, original taken from # http://www.gnu.org/software/ac-archive/htmldoc/check_ssl.html and # modified for NSD. AC_DEFUN([CHECK_SSL], [ AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr /usr/local/opt/openssl)]),[ ],[ withval="yes" ]) if test x_$withval != x_no; then AC_MSG_CHECKING(for SSL) if test -n "$withval"; then dnl look for openssl install with different version, eg. dnl in /usr/include/openssl11/openssl/ssl.h dnl and /usr/lib64/openssl11/libssl.so dnl with the --with-ssl=/usr/include/openssl11 if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then ssldir="$withval" found_ssl="yes" withval="" ssldir_include="$ssldir" CPPFLAGS="$CPPFLAGS -I$ssldir_include"; dnl find the libdir ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else AC_MSG_ERROR([Could not find openssl lib file, $ssldir_lib/libssl.[so,a], pass like "/usr/local" or "/usr/include/openssl11"]) fi fi fi fi if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr /usr/local/opt/openssl" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes"; if test x_$ssldir != x_/usr; then CPPFLAGS="$CPPFLAGS -I$ssldir/include"; fi ssldir_include="$ssldir/include" if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then ssldir_lib="$ssldir/lib64" else ssldir_lib="$ssldir/lib" fi break; fi done if test x_$found_ssl != x_yes; then AC_MSG_ERROR([Cannot find the SSL libraries in $withval]) else AC_MSG_RESULT([found in $ssldir]) HAVE_SSL=yes AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.]) if test x_$ssldir != x_/usr; then LDFLAGS="$LDFLAGS -L$ssldir_lib"; fi if test x_$ssldir = x_/usr/sfw; then LDFLAGS="$LDFLAGS -R$ssldir_lib"; fi fi AC_SUBST(HAVE_SSL) fi ])dnl # check for libevent AC_ARG_WITH(libevent, AS_HELP_STRING([--with-libevent=pathname],[use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr /usr/local/opt/libevent or you can specify an explicit path), useful when the zone count is high.]), [ ],[ withval="yes" ]) if test x_$withval = x_yes -o x_$withval != x_no; then AC_MSG_CHECKING(for libevent) if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr /usr/local/opt/libevent" fi for dir in $withval; do thedir="$dir" if test -f "$dir/include/event.h" -o -f "$dir/include/event2/event.h"; then found_libevent="yes" dnl assume /usr is in default path. if test "$thedir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$thedir/include" fi break; fi done if test x_$found_libevent != x_yes; then if test -f "$dir/event.h" -a \( -f "$dir/libevent.la" -o -f "$dir/libev.la" \) ; then # libevent source directory AC_MSG_RESULT(found in $thedir) CPPFLAGS="$CPPFLAGS -I$thedir -I$thedir/include" # remove evdns from linking ev_files_o=`ls $thedir/*.o | $GREP -v evdns\.o | $GREP -v bufferevent_openssl\.o` cp $ev_files_o . LDFLAGS="$ev_files_o $LDFLAGS -lm" else AC_MSG_ERROR([Cannot find the libevent library. You can restart ./configure --with-libevent=no to use a builtin alternative.]) fi else AC_MSG_RESULT(found in $thedir) dnl if event2 exists and no event lib in dir itself, use subdir if test ! -f $thedir/lib/libevent.a -a ! -f $thedir/lib/libevent.so -a -d "$thedir/lib/event2"; then LDFLAGS="$LDFLAGS -L$thedir/lib/event2" ACX_RUNTIME_PATH_ADD([$thedir/lib/event2]) else dnl assume /usr is in default path, do not add "". if test "$thedir" != "/usr" -a "$thedir" != ""; then LDFLAGS="$LDFLAGS -L$thedir/lib" ACX_RUNTIME_PATH_ADD([$thedir/lib]) fi fi fi # check for library used by libevent after 1.3c AC_SEARCH_LIBS([clock_gettime], [rt]) # is the event.h header libev or libevent? AC_CHECK_HEADERS([event.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_DECL(EV_VERSION_MAJOR, [ AC_SEARCH_LIBS(event_set, [ev]) ],[ AC_SEARCH_LIBS(event_set, [event]) ],[AC_INCLUDES_DEFAULT #include ]) AC_CHECK_FUNCS([event_base_free]) # only in libevent 1.2 and later AC_CHECK_FUNCS([event_base_once]) # only in libevent 1.4.1 and later AC_CHECK_FUNCS([event_base_new]) # only in libevent 1.4.1 and later AC_CHECK_FUNCS([event_base_get_method]) # only in libevent 1.4.3 and later AC_CHECK_FUNCS([ev_loop]) # only in libev. (tested on 3.51) AC_CHECK_FUNCS([ev_default_loop]) # only in libev. (tested on 4.00) # prometheus metrics depend on libevent 2.0 and later, and is therefore # only enabled when the required version is found and used AC_CHECK_FUNCS([evhttp_free], [ AC_DEFINE_UNQUOTED([USE_METRICS], [], [Define this to expose NSD statistics via a prometheus metrics HTTP endpoint.]) AC_DEFINE_UNQUOTED([NSD_METRICS_PORT], [9100], [Define the default metrics HTTP endpoint port.]) ], [ AC_MSG_NOTICE([disabling prometheus metrics]) ]) else AC_DEFINE(USE_MINI_EVENT, 1, [Define if you want to use internal select based events]) AC_MSG_NOTICE([Prometheus metrics are disabled with the builtin libevent alternative]) fi # Checks for header files. AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([time.h arpa/inet.h signal.h string.h strings.h fcntl.h limits.h netinet/in.h netinet/tcp.h stddef.h sys/param.h sys/socket.h sys/un.h syslog.h unistd.h sys/select.h stdarg.h stdint.h netdb.h sys/bitypes.h tcpd.h glob.h grp.h endian.h sys/random.h ifaddrs.h],,, [AC_INCLUDES_DEFAULT]) AC_DEFUN([CHECK_VALIST_DEF], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for double definition of struct va_list) AC_CACHE_VAL(ac_cv_c_va_list_def, [ cat >conftest.c < #include int foo(void); EOF if test -z "`$CC -Werror -D_XOPEN_SOURCE=600 -c conftest.c 2>&1`"; then eval "ac_cv_c_va_list_def=no" else eval "ac_cv_c_va_list_def=yes" fi rm -f conftest* ]) if test $ac_cv_c_va_list_def = yes; then AC_MSG_RESULT(yes) : AC_DEFINE_UNQUOTED([HAVE_VA_LIST_DOUBLE_DEF], [], [Define this if you have double va_list definitions.]) else AC_MSG_RESULT(no) : fi ]) CHECK_VALIST_DEF AC_DEFUN([AC_CHECK_STRPTIME], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether strptime needs defines) AC_CACHE_VAL(ac_cv_c_strptime_needs_defs, [ cat >conftest.c < int testing (void) { struct tm t; const char *timestr="201201"; return strptime(timestr, "%Y%m", &t) != 0; } EOF if test -z "`$CC -Wall -Werror -c conftest.c 2>&1`"; then eval "ac_cv_c_strptime_needs_defs=no" else eval "ac_cv_c_strptime_needs_defs=yes" fi rm -f conftest* ]) AC_MSG_RESULT($ac_cv_c_strptime_needs_defs) if test $ac_cv_c_strptime_needs_defs = yes; then AC_DEFINE_UNQUOTED([STRPTIME_NEEDS_DEFINES], 1, [strptime is available from time.h with some defines.]) fi ])dnl AC_CHECK_STRPTIME # check wether strptime also works AC_DEFUN([AC_CHECK_STRPTIME_WORKS], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether strptime works) if test c${cross_compiling} = cno; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #define _XOPEN_SOURCE 600 #include int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } ]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"], [eval "ac_cv_c_strptime_works=maybe"]) else eval "ac_cv_c_strptime_works=maybe" fi AC_MSG_RESULT($ac_cv_c_strptime_works) if test $ac_cv_c_strptime_works = no; then AC_LIBOBJ(strptime) else AC_DEFINE_UNQUOTED([STRPTIME_WORKS], 1, [use default strptime.]) fi ])dnl AC_SEARCH_LIBS(inet_pton, [nsl]) AC_SEARCH_LIBS(socket, [socket]) AC_CHECK_STRPTIME_WORKS ACX_CHECK_NONBLOCKING_BROKEN ACX_MKDIR_ONE_ARG # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." else CPPFLAGS="-I." fi if test "$srcdir" != "."; then CPPFLAGS="$CPPFLAGS -I$srcdir" if test -f $srcdir/config.h; then AC_MSG_ERROR([$srcdir/config.h is in the way, please remove it]) fi fi dnl LIBGTOP_CHECK_TYPE dnl Stolen from Gnome's anjuta dnl Improved version of AC_CHECK_TYPE which takes into account dnl that we need to #include some other header files on some dnl systems to get some types. dnl AC_LIBGTOP_CHECK_TYPE(TYPE, DEFAULT) AC_DEFUN([AC_LIBGTOP_CHECK_TYPE], [AC_MSG_CHECKING(for $1) AC_CACHE_VAL(ac_cv_type_$1, [AC_EGREP_CPP(dnl changequote(<<,>>)dnl <<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl changequote([,]), [ #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif ], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl AC_MSG_RESULT($ac_cv_type_$1) if test $ac_cv_type_$1 = no; then AC_DEFINE($1, $2, Define "$1" to "$2" if "$1" is missing) fi ]) AC_LIBGTOP_CHECK_TYPE(int8_t, char) AC_LIBGTOP_CHECK_TYPE(int16_t, short) AC_LIBGTOP_CHECK_TYPE(int32_t, int) AC_LIBGTOP_CHECK_TYPE(int64_t, long long) AC_LIBGTOP_CHECK_TYPE(uint8_t, unsigned char) AC_LIBGTOP_CHECK_TYPE(uint16_t, unsigned short) AC_LIBGTOP_CHECK_TYPE(uint32_t, unsigned int) AC_LIBGTOP_CHECK_TYPE(uint64_t, unsigned long long) AC_LIBGTOP_CHECK_TYPE(socklen_t, int) AC_LIBGTOP_CHECK_TYPE(sig_atomic_t, int) AC_LIBGTOP_CHECK_TYPE(ssize_t, int) AC_LIBGTOP_CHECK_TYPE(suseconds_t, time_t) AC_CHECK_TYPE(in_addr_t, [], [AC_DEFINE([in_addr_t], [uint32_t], [in_addr_t])], [ #if HAVE_SYS_TYPES_H # include #endif #if HAVE_NETINET_IN_H # include #endif]) ACX_CHECK_SS_FAMILY AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec]) AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_UN_H #include #endif ]) # Checks for library functions. AC_FUNC_CHOWN AC_FUNC_FORK AC_FUNC_MALLOC AC_DEFINE(RETSIGTYPE,void,[Return type of signal handlers, but autoconf 2.70 says 'your code may safely assume C89 semantics that RETSIGTYPE is void.']) AC_FUNC_FSEEKO AC_SYS_LARGEFILE AC_CHECK_SIZEOF(void*) AC_CHECK_SIZEOF(off_t) AC_CHECK_FUNCS([getrandom arc4random arc4random_uniform]) AC_SEARCH_LIBS([setusercontext],[util],[AC_CHECK_HEADERS([login_cap.h],,, [AC_INCLUDES_DEFAULT])]) AC_CHECK_FUNCS([tzset alarm chroot dup2 endpwent gethostname memset memcpy pwrite socket strcasecmp strchr strdup strerror strncasecmp strtol writev getaddrinfo getnameinfo freeaddrinfo gai_strerror sigaction sigprocmask strptime strftime localtime_r setusercontext glob initgroups setresuid setreuid setresgid setregid getpwnam mmap ppoll clock_gettime accept4 getifaddrs]) AC_CHECK_TYPE([struct mmsghdr], AC_DEFINE(HAVE_MMSGHDR, 1, [If sys/socket.h has a struct mmsghdr.]), [], [ AC_INCLUDES_DEFAULT #include ]) AC_ARG_ENABLE(recvmmsg, AS_HELP_STRING([--enable-recvmmsg],[Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems for IPv6])) case "$enable_recvmmsg" in yes) AC_CHECK_FUNC([recvmmsg], [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_UNISTD_H #include #endif #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = recvmmsg(s, 0, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } ]])], [ AC_DEFINE([HAVE_RECVMMSG], [1], [Define if recvmmsg is implemented])], [ ], [ AC_DEFINE([HAVE_RECVMMSG], [1], [Define if recvmmsg exists])] )]) AC_CHECK_FUNC([sendmmsg], [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_UNISTD_H #include #endif #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = sendmmsg(s, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } ]])], [ AC_DEFINE([HAVE_SENDMMSG], [1], [Define if sendmmsg is implemented])], [ ], [ AC_DEFINE([HAVE_SENDMMSG], [1], [Define if sendmmsg exists])] )]) ;; no|*) ;; esac # check if setreuid en setregid fail, on MacOSX10.4(darwin8). if echo $target_os | $GREP -i darwin8 > /dev/null; then AC_DEFINE(DARWIN_BROKEN_SETREUID, 1, [Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work]) fi # GNU HURD needs _GNU_SOURCE defined for cpu affinity gear if echo $target_os | $EGREP -i 'linux|hurd' > /dev/null; then AC_DEFINE([_GNU_SOURCE, 1, [Define this if on Linux or GNU Hurd for cpu affinity interface]]) fi # see comment on _GNU_SOURCE above AC_CHECK_HEADERS([sched.h sys/cpuset.h],,, [AC_INCLUDES_DEFAULT]) # Check for cpu_set_t (Linux) and cpuset_t (FreeBSD and NetBSD) AC_CHECK_TYPES([cpu_set_t, cpuset_t, cpuid_t],,,[ AC_INCLUDES_DEFAULT #if HAVE_SCHED_H # include #endif #if HAVE_SYS_CPUSET_H # include #endif ]) AC_DEFUN([AC_CHECK_CPU_OR], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether CPU_OR works with three arguments) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SYS_CPUSET_H # include #endif #include #ifdef HAVE_CPUSET_T #define MY_CPUSET_TYPE cpuset_t #endif #ifdef HAVE_CPU_SET_T #define MY_CPUSET_TYPE cpu_set_t #endif void testing (void) { MY_CPUSET_TYPE a, b; memset(&a, 0, sizeof(a)); memset(&b, 0, sizeof(b)); CPU_OR(&a, &a, &b); }]], [[ testing(); ]])],[ AC_MSG_RESULT(yes) AC_DEFINE([CPU_OR_THREE_ARGS], 1, [number of arguments for CPU_OR is three]) ],[ AC_MSG_RESULT(no) ])]) AS_IF([test x"$ac_cv_type_cpuset_t" = xyes -o x"$ac_cv_type_cpu_set_t" = xyes ],[ AC_CHECK_FUNC(cpuset_create) AC_CHECK_FUNC(cpuset_destroy) AC_CHECK_FUNC(cpuset_zero) AC_CHECK_FUNC(cpuset_set) AC_CHECK_FUNC(cpuset_clr) AC_CHECK_FUNC(cpuset_isset) AC_CHECK_FUNC(cpuset_size) AC_LIBOBJ(cpuset) AC_CHECK_FUNCS([sysconf]) AC_CHECK_CPU_OR ]) # # sched_setaffinity must be checked using proper includes. # also needs _GNU_SOURCE on Linux and Hurd; see above. # also see https://github.com/NLnetLabs/nsd/issues/82. # AC_MSG_CHECKING(for sched_setaffinity) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ #ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SYS_CPUSET_H #include #endif #ifdef HAVE_CPUSET_T #define MY_CPUSET_TYPE cpuset_t #endif #ifdef HAVE_CPU_SET_T #define MY_CPUSET_TYPE cpu_set_t #endif void testing (void) { MY_CPUSET_TYPE set; CPU_ZERO(&set); (void)sched_setaffinity(-1, sizeof(set), &set); } ]])], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SCHED_SETAFFINITY, 1, [Define this if sched_setaffinity is available])], [ AC_MSG_RESULT(no)]) # # Checking for missing functions we can replace # AC_REPLACE_FUNCS(basename) AC_REPLACE_FUNCS(inet_aton) AC_REPLACE_FUNCS(inet_pton) AC_REPLACE_FUNCS(inet_ntop) AC_REPLACE_FUNCS(snprintf) AC_REPLACE_FUNCS(strlcat) AC_REPLACE_FUNCS(strlcpy) AC_REPLACE_FUNCS(strptime) AC_REPLACE_FUNCS(b64_pton) AC_REPLACE_FUNCS(b64_ntop) AC_REPLACE_FUNCS(pselect) AC_REPLACE_FUNCS(memmove) AC_REPLACE_FUNCS(setproctitle) AC_REPLACE_FUNCS(explicit_bzero) AC_MSG_CHECKING([for reallocarray]) AC_LINK_IFELSE([AC_LANG_SOURCE( [[ #ifndef _OPENBSD_SOURCE #define _OPENBSD_SOURCE 1 #endif ]] AC_INCLUDES_DEFAULT [[ #include int main(void) { void* p = reallocarray(NULL, 10, 100); free(p); return 0; } ]])], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_REALLOCARRAY, 1, [If we have reallocarray(3)]) AC_CHECK_DECLS([reallocarray], [], [ AC_DEFINE(REALLOCARRAY_NEEDS_DEFINES, 1, [If reallocarray needs defines to appear in the headers]) ], [ AC_INCLUDES_DEFAULT #include ]) ], [ AC_MSG_RESULT(no) AC_LIBOBJ(reallocarray) ]) AC_MSG_CHECKING(for pselect prototype in sys/select.h) AC_EGREP_HEADER([[^a-zA-Z_]*pselect[^a-zA-Z_]], sys/select.h, AC_DEFINE(HAVE_PSELECT_PROTO, 1, [if sys/select.h provides pselect prototype]) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_MSG_CHECKING(for ctime_r prototype in time.h) AC_EGREP_HEADER([[^a-zA-Z_]*ctime_r[^a-zA-Z_]], time.h, AC_DEFINE(HAVE_CTIME_R_PROTO, 1, [if time.h provides ctime_r prototype]) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_CHECK_TYPE([struct timespec], AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1, [If time.h has a struct timespec (for pselect).]), [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_TIME_H #include #endif ]) dnl dnl Some random defines's dnl AC_DEFINE_UNQUOTED([IDENTITY], ["unidentified server"], [Define to the default nsd identity.]) AC_DEFINE_UNQUOTED([VERSION], [PACKAGE_STRING], [Define to the NSD version to answer version.server query.]) AC_DEFINE_UNQUOTED([TCP_BACKLOG], [256], [Define to the backlog to be used with listen.]) AC_DEFINE_UNQUOTED([TCP_PORT], ["53"], [Define to the default tcp port.]) AC_DEFINE_UNQUOTED([TCP_MAX_MESSAGE_LEN], [65535], [Define to the default maximum message length.]) AC_DEFINE_UNQUOTED([UDP_PORT], ["53"], [Define to the default udp port.]) AC_DEFINE_UNQUOTED([UDP_MAX_MESSAGE_LEN], [512], [Define to the default maximum udp message length.]) AC_DEFINE_UNQUOTED([EDNS_MAX_MESSAGE_LEN], [1232], [Define to the default maximum message length with EDNS.]) AC_DEFINE_UNQUOTED([TLS_PORT], ["853"], [Define to the default DNS over TLS port.]) AC_DEFINE_UNQUOTED([MAXSYSLOGMSGLEN], [512], [Define to the maximum message length to pass to syslog.]) AC_DEFINE_UNQUOTED([NSD_CONTROL_PORT], [8952], [Define to the default nsd-control port.]) AC_DEFINE_UNQUOTED([NSD_CONTROL_VERSION], [1], [Define to nsd-control proto version.]) AC_DEFINE_UNQUOTED([VERIFY_PORT], ["5347"], [Define to the default zone verification udp port.]) dnl dnl Determine the syslog facility to use dnl facility=LOG_DAEMON AC_ARG_WITH([facility], AS_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 default tcp timeout dnl tcp_timeout=120 AC_ARG_WITH([tcp_timeout], AS_HELP_STRING([--with-tcp-timeout=number],[Limit the default tcp timeout]), [tcp_timeout=$withval]) AC_DEFINE_UNQUOTED([TCP_TIMEOUT], $tcp_timeout, [Define to the default tcp timeout.]) dnl dnl Features dnl AC_ARG_ENABLE(root-server, AS_HELP_STRING([--enable-root-server],[Configure NSD as a root server (obsolete)])) AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--disable-ipv6],[Disables IPv6 support])) case "$enable_ipv6" in no) ;; yes|*) AC_DEFINE_UNQUOTED([INET6], [], [Define this to enable IPv6 support.]) ;; esac AC_ARG_ENABLE(bind8-stats, AS_HELP_STRING([--enable-bind8-stats],[Enables BIND8 like NSTATS & XSTATS and statistics in nsd-control])) case "$enable_bind8_stats" in yes|'') AC_DEFINE_UNQUOTED([BIND8_STATS], [], [Define this to enable BIND8 like NSTATS & XSTATS.]) ;; no|*) ;; esac AC_ARG_ENABLE(zone-stats, AS_HELP_STRING([--enable-zone-stats],[Enable per-zone statistics gathering (needs --enable-bind8-stats)])) case "$enable_zone_stats" in yes) AC_DEFINE_UNQUOTED([USE_ZONE_STATS], [], [Define this to enable per-zone statistics gathering.]) AC_DEFINE_UNQUOTED([BIND8_STATS], [], [Define this to enable BIND8 like NSTATS & XSTATS.]) ;; no|''|*) ;; esac AC_ARG_ENABLE(checking, AS_HELP_STRING([--enable-checking],[Enable internal runtime checks])) case "$enable_checking" in yes) CHECK_COMPILER_FLAG(W, [ CFLAGS="$CFLAGS -W" ]) CHECK_COMPILER_FLAG(Wall, [ CFLAGS="$CFLAGS -Wall" ]) CHECK_COMPILER_FLAG(Wextra, [ CFLAGS="$CFLAGS -Wextra" ]) CHECK_COMPILER_FLAG(Wdeclaration-after-statement, [ CFLAGS="$CFLAGS -Wdeclaration-after-statement" ]) ;; no|*) AC_DEFINE([NDEBUG], [], [Undefine this to enable internal runtime checks.]) ;; esac AC_ARG_ENABLE(log-role, AS_HELP_STRING([--enable-log-role],[Shows the role of processes in the logfile (enable this only for debugging purposes)])) case "$enable_log_role" in yes) AC_DEFINE_UNQUOTED([USE_LOG_PROCESS_ROLE], [], [Define this to show the role of processes in the logfile for debugging purposes.]) ;; no|*) ;; esac AC_ARG_ENABLE(memclean, AS_HELP_STRING([--enable-memclean],[Cleanup memory (at exit) for eg. valgrind, memcheck])) if test "$enable_memclean" = "yes"; then AC_DEFINE_UNQUOTED([MEMCLEAN], [1], [Define this to cleanup memory at exit (eg. for valgrind, etc.)]) fi AC_ARG_ENABLE(ratelimit, AS_HELP_STRING([--enable-ratelimit],[Enable rate limiting])) case "$enable_ratelimit" in yes) AC_DEFINE_UNQUOTED([RATELIMIT], [], [Define this to enable rate limiting.]) dnl causes awk to not match the exclusion start marker. ratelimit="xx" ;; no|*) ratelimit="" ;; esac AC_SUBST(ratelimit) AC_ARG_ENABLE(ratelimit-default-is-off, AS_HELP_STRING([--enable-ratelimit-default-is-off],[Enable this to set default of ratelimit to off (enable in nsd.conf), otherwise ratelimit is enabled by default if --enable-ratelimit is enabled])) case "$enable_ratelimit_default_is_off" in yes) AC_DEFINE_UNQUOTED([RATELIMIT_DEFAULT_OFF], [], [Define this to set ratelimit to off by default.]) ratelimit_default="off" ;; no|*) ratelimit_default="on" ;; esac AC_SUBST(ratelimit_default) # we need SSL for TSIG (and maybe also for NSEC3). CHECK_SSL if test x$HAVE_SSL = x"yes"; then ACX_LIB_SSL # remove space after -ldl if there. LIBS=`echo "$LIBS" | sed -e 's/ $//'` # Check for -pthread BAKLIBS="$LIBS" LIBS="-lcrypto $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[],[ dnl so link fails for EVP_sha256, try with -pthread. BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pthread" AC_MSG_CHECKING([if libcrypto needs -pthread]) AC_TRY_LINK_FUNC([EVP_sha256], [ AC_MSG_RESULT([yes]) ] , [ AC_MSG_RESULT([no]) dnl restore the nonpthread value CFLAGS="$BAKCFLAGS" ]) ]) LIBS="$BAKLIBS" if test -n "$ssldir"; then AC_CHECK_LIB(crypto, EVP_sha256,, [ AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) ]) fi SSL_LIBS="-lssl" AC_SUBST(SSL_LIBS) AC_CHECK_HEADERS([openssl/ssl.h openssl/err.h openssl/rand.h openssl/ocsp.h openssl/core_names.h openssl/x509v3.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto CRYPTO_memcmp EC_KEY_new_by_curve_name EVP_MAC_CTX_new EVP_MAC_CTX_set_params EVP_MAC_CTX_get_mac_size SHA1_Init ASN1_STRING_get0_data]) if test "$ac_cv_func_SHA1_Init" = "yes"; then ACX_FUNC_DEPRECATED([SHA1_Init], [(void)SHA1_Init(NULL);], [ #include ]) fi AC_CHECK_DECLS([SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_OPENSSL_CONF_H #include #endif #ifdef HAVE_OPENSSL_ENGINE_H #include #endif #include #include #ifdef HAVE_OPENSSL_X509V3_h #include #endif ]) AC_CHECK_DECL([TLS1_3_VERSION], [AC_DEFINE([HAVE_TLS_1_3], [1], [Define if TLS 1.3 is supported by OpenSSL])], [AC_MSG_WARN([No TLS 1.3, therefore XFR-over-TLS is disabled])], [[#include ]]) BAKLIBS="$LIBS" LIBS="-lssl $LIBS" AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_get1_peer_certificate SSL_CTX_set_security_level ERR_load_SSL_strings]) if test "$ac_cv_func_ERR_load_SSL_strings" = "yes"; then ACX_FUNC_DEPRECATED([ERR_load_SSL_strings], [(void)ERR_load_SSL_strings();], [ #include ]) fi LIBS="$BAKLIBS" else AC_MSG_WARN([No SSL, therefore TLS is disabled]) fi AC_ARG_ENABLE(nsec3, AS_HELP_STRING([--disable-nsec3],[Disable NSEC3 support])) case "$enable_nsec3" in no) ;; yes) AC_DEFINE_UNQUOTED([NSEC3], [], [Define this to enable NSEC3 support.]) ;; *) if test x$HAVE_SSL = x"yes"; then AC_DEFINE_UNQUOTED([NSEC3], [], [Define this to enable NSEC3 support.]) else AC_MSG_WARN([No SSL, therefore NSEC3 is disabled]) fi ;; esac AC_ARG_ENABLE(minimal-responses, AS_HELP_STRING([--disable-minimal-responses],[Disable response minimization. More truncation.])) case "$enable_minimal_responses" in no) ;; yes|*) AC_DEFINE_UNQUOTED([MINIMAL_RESPONSES], [], [Define this to enable response minimalization to reduce truncation.]) ;; esac AC_ARG_ENABLE(mmap, AS_HELP_STRING([--enable-mmap],[Use mmap instead of malloc. Experimental.])) case "$enable_mmap" in yes) AC_CHECK_HEADERS([sys/mman.h],,, [AC_INCLUDES_DEFAULT]) AC_LIBGTOP_CHECK_TYPE(uintptr_t, void*) AC_CHECK_FUNCS([mmap munmap]) AC_DEFINE_UNQUOTED([USE_MMAP_ALLOC], [], [Define this to enable mmap instead of malloc. Experimental.]) ;; no|*) ;; esac AC_ARG_ENABLE(radix-tree, AS_HELP_STRING([--disable-radix-tree],[You can disable the radix tree and use the red-black tree for the main lookups, the red-black tree uses less memory, but uses some more CPU.])) case "$enable_radix_tree" in no) ;; yes|*) AC_DEFINE_UNQUOTED([USE_RADIX_TREE], [], [Define this to configure to use the radix tree.]) ;; esac AC_ARG_ENABLE(packed, AS_HELP_STRING([--enable-packed],[Enable packed structure alignment, uses less memory, but unaligned reads.])) case "$enable_packed" in yes) AC_DEFINE_UNQUOTED([PACKED_STRUCTS], [], [Define this to use packed structure alignment.]) ACX_CHECK_COMPILER_FLAG(Wno-address-of-packed-member, [CFLAGS="$CFLAGS -Wno-address-of-packed-member"]) ;; no|*) ;; esac # check for dnstap if requested dt_DNSTAP([${localstatedir}/run/nsd-dnstap.sock], [ AC_DEFINE([USE_DNSTAP], [1], [Define to 1 to enable dnstap support]) AC_SUBST([ENABLE_DNSTAP], [1]) AC_SUBST([opt_dnstap_socket_path]) ACX_ESCAPE_BACKSLASH($opt_dnstap_socket_path, hdr_dnstap_socket_path) AC_DEFINE_UNQUOTED(DNSTAP_SOCKET_PATH, ["$hdr_dnstap_socket_path"], [default dnstap socket path]) AC_SUBST([DNSTAP_SRC], ["dnstap/dnstap.c dnstap/dnstap.pb-c.c dnstap/dnstap_collector.c"]) AC_SUBST([DNSTAP_OBJ], ["dnstap.o dnstap_collector.o dnstap.pb-c.o"]) dnstap_config="dnstap/dnstap_config.h" ], [ AC_SUBST([ENABLE_DNSTAP], [0]) ] ) # Include systemd.m4 - begin sinclude(systemd.m4) # Include systemd.m4 - end AC_ARG_ENABLE(tcp-fastopen, AS_HELP_STRING([--enable-tcp-fastopen],[Enable TCP Fast Open])) case "$enable_tcp_fastopen" in yes) AC_CHECK_DECL([TCP_FASTOPEN], [], [AC_MSG_ERROR([TCP Fast Open is not available: please rerun without --enable-tcp-fastopen])], [AC_INCLUDES_DEFAULT #include ]) AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.]) ;; no|*) ;; esac AH_BOTTOM([ /* define before includes as it specifies what standard to use. */ #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \ || !defined (HAVE_CTIME_R_PROTO) \ || defined (STRPTIME_NEEDS_DEFINES) || defined(REALLOCARRAY_NEEDS_DEFINES) # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 # endif # ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 200112 # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE 1 # endif # ifndef _OPENBSD_SOURCE # define _OPENBSD_SOURCE 1 # endif # ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 # endif # ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 # endif # ifndef _STDC_C99 # define _STDC_C99 1 # endif # ifndef _ALL_SOURCE # define _ALL_SOURCE 1 # endif #endif ]) AH_BOTTOM([ #ifdef HAVE_VA_LIST_DOUBLE_DEF /* workaround double va_list definition on some platforms */ # ifndef _VA_LIST_DEFINED # define _VA_LIST_DEFINED # endif #endif ]) AH_BOTTOM([ #include #include #include #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif ]) AH_BOTTOM([ #ifdef HAVE_ATTR_FORMAT #define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ #define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ #if defined(__cplusplus) #define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) #define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ #define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ ]) AH_BOTTOM([ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ #ifndef AF_INET6 #define AF_INET6 28 #endif /* AF_INET6 */ ]) if test $ac_cv_func_getaddrinfo = no; then AC_LIBOBJ([fake-rfc2553]) fi AH_BOTTOM([ /* maximum nesting of included files */ #define MAXINCLUDES 10 ]) AH_BOTTOM([ #ifndef HAVE_B64_NTOP int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); #endif /* !HAVE_B64_NTOP */ #ifndef HAVE_B64_PTON int b64_pton(char const *src, uint8_t *target, size_t targsize); #endif /* !HAVE_B64_PTON */ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ #ifndef HAVE_SNPRINTF #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ #ifndef HAVE_INET_PTON int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_EXPLICIT_BZERO #define explicit_bzero nsd_explicit_bzero void explicit_bzero(void* buf, size_t len); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_REALLOCARRAY void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif #ifndef HAVE_STRPTIME #define HAVE_STRPTIME 1 char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif #if (HAVE_CPU_SET_T || HAVE_CPUSET_T) #include "compat/cpuset.h" #endif #ifndef HAVE_SETPROCTITLE #ifdef __linux__ #define HAVE_SETPROCTITLE 1 #include void setproctitle(const char *fmt, ...); #endif #endif ]) AH_BOTTOM( AHX_MEMCMP_BROKEN(nsd) AHX_CONFIG_MAXHOSTNAMELEN ) AH_BOTTOM([ /* provide timespec def if not available */ #ifndef CONFIG_DEFINES #define CONFIG_DEFINES #ifndef HAVE_STRUCT_TIMESPEC #ifndef __timespec_defined #define __timespec_defined 1 struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* !__timespec_defined */ #endif /* !HAVE_STRUCT_TIMESPEC */ #endif /* !CONFIG_DEFINES */ #ifdef PACKED_STRUCTS #define ATTR_PACKED __attribute__((packed)) #else #define ATTR_PACKED #endif ]) # big fat warning if test "$enable_checking" = "yes"; then echo "************************************************" echo "* You have activated \"--enable-checking\" *" echo "* *" echo "* This will instruct NSD to be stricter *" echo "* when validating its input. This could lead *" echo "* to a reduced service level. *" echo "* *" echo "************************************************" fi AC_CONFIG_FILES([Makefile $dnstap_config]) # Arguments introduced specifically for simdzone. AC_ARG_ENABLE(westmere, AS_HELP_STRING([--disable-westmere], [Disable Westmere (SSE4.2) parser kernel])) AC_ARG_ENABLE(haswell, AS_HELP_STRING([--disable-haswell], [Disable Haswell (AVX2) parser kernel])) AC_CONFIG_SUBDIRS([simdzone]) AC_OUTPUT nsd-4.12.0/configparser.y0000644000175000017500000011642615002373054014663 0ustar mozziemozzie/* * configparser.y -- yacc grammar for NSD configuration files * * Copyright (c) 2001-2019, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ %{ #include "config.h" #include #include #include #include #include "options.h" #include "util.h" #include "dname.h" #include "tsig.h" #include "rrl.h" int yylex(void); #ifdef __cplusplus extern "C" #endif /* these need to be global, otherwise they cannot be used inside yacc */ extern config_parser_state_type *cfg_parser; static void append_acl(struct acl_options **list, struct acl_options *acl); static void add_to_last_acl(struct acl_options **list, char *ac); static int parse_boolean(const char *str, int *bln); static int parse_catalog_role(const char *str, int *role); static int parse_expire_expr(const char *str, long long *num, uint8_t *expr); static int parse_number(const char *str, long long *num); static int parse_range(const char *str, long long *low, long long *high); struct component { struct component *next; char *str; }; %} %union { char *str; long long llng; int bln; struct ip_address_option *ip; struct range_option *range; struct cpu_option *cpu; char **strv; struct component *comp; int role; } %token STRING %type number %type boolean %type ip_address %type service_cpu_affinity %type cpus %type command %type arguments %type catalog_role /* server */ %token VAR_SERVER %token VAR_SERVER_COUNT %token VAR_IP_ADDRESS %token VAR_IP_TRANSPARENT %token VAR_IP_FREEBIND %token VAR_REUSEPORT %token VAR_SEND_BUFFER_SIZE %token VAR_RECEIVE_BUFFER_SIZE %token VAR_DEBUG_MODE %token VAR_IP4_ONLY %token VAR_IP6_ONLY %token VAR_DO_IP4 %token VAR_DO_IP6 %token VAR_PORT %token VAR_USE_SYSTEMD %token VAR_VERBOSITY %token VAR_USERNAME %token VAR_CHROOT %token VAR_ZONESDIR %token VAR_ZONELISTFILE %token VAR_DATABASE %token VAR_LOGFILE %token VAR_LOG_ONLY_SYSLOG %token VAR_PIDFILE %token VAR_DIFFFILE %token VAR_XFRDFILE %token VAR_XFRDIR %token VAR_HIDE_VERSION %token VAR_HIDE_IDENTITY %token VAR_VERSION %token VAR_IDENTITY %token VAR_NSID %token VAR_TCP_COUNT %token VAR_TCP_REJECT_OVERFLOW %token VAR_TCP_QUERY_COUNT %token VAR_TCP_TIMEOUT %token VAR_TCP_MSS %token VAR_OUTGOING_TCP_MSS %token VAR_IPV4_EDNS_SIZE %token VAR_IPV6_EDNS_SIZE %token VAR_STATISTICS %token VAR_XFRD_RELOAD_TIMEOUT %token VAR_LOG_TIME_ASCII %token VAR_LOG_TIME_ISO %token VAR_ROUND_ROBIN %token VAR_MINIMAL_RESPONSES %token VAR_CONFINE_TO_ZONE %token VAR_REFUSE_ANY %token VAR_RELOAD_CONFIG %token VAR_ZONEFILES_CHECK %token VAR_ZONEFILES_WRITE %token VAR_RRL_SIZE %token VAR_RRL_RATELIMIT %token VAR_RRL_SLIP %token VAR_RRL_IPV4_PREFIX_LENGTH %token VAR_RRL_IPV6_PREFIX_LENGTH %token VAR_RRL_WHITELIST_RATELIMIT %token VAR_TLS_SERVICE_KEY %token VAR_TLS_SERVICE_PEM %token VAR_TLS_SERVICE_OCSP %token VAR_TLS_PORT %token VAR_TLS_AUTH_PORT %token VAR_TLS_AUTH_XFR_ONLY %token VAR_TLS_CERT_BUNDLE %token VAR_PROXY_PROTOCOL_PORT %token VAR_CPU_AFFINITY %token VAR_XFRD_CPU_AFFINITY %token VAR_SERVER_CPU_AFFINITY %token VAR_DROP_UPDATES %token VAR_XFRD_TCP_MAX %token VAR_XFRD_TCP_PIPELINE %token VAR_METRICS_ENABLE %token VAR_METRICS_INTERFACE %token VAR_METRICS_PORT %token VAR_METRICS_PATH /* dnstap */ %token VAR_DNSTAP %token VAR_DNSTAP_ENABLE %token VAR_DNSTAP_SOCKET_PATH %token VAR_DNSTAP_IP %token VAR_DNSTAP_TLS %token VAR_DNSTAP_TLS_SERVER_NAME %token VAR_DNSTAP_TLS_CERT_BUNDLE %token VAR_DNSTAP_TLS_CLIENT_KEY_FILE %token VAR_DNSTAP_TLS_CLIENT_CERT_FILE %token VAR_DNSTAP_SEND_IDENTITY %token VAR_DNSTAP_SEND_VERSION %token VAR_DNSTAP_IDENTITY %token VAR_DNSTAP_VERSION %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES /* remote-control */ %token VAR_REMOTE_CONTROL %token VAR_CONTROL_ENABLE %token VAR_CONTROL_INTERFACE %token VAR_CONTROL_PORT %token VAR_SERVER_KEY_FILE %token VAR_SERVER_CERT_FILE %token VAR_CONTROL_KEY_FILE %token VAR_CONTROL_CERT_FILE /* key */ %token VAR_KEY %token VAR_ALGORITHM %token VAR_SECRET /* xot auth */ %token VAR_TLS_AUTH %token VAR_TLS_AUTH_DOMAIN_NAME %token VAR_TLS_AUTH_CLIENT_CERT %token VAR_TLS_AUTH_CLIENT_KEY %token VAR_TLS_AUTH_CLIENT_KEY_PW /* pattern */ %token VAR_PATTERN %token VAR_NAME %token VAR_ZONEFILE %token VAR_NOTIFY %token VAR_PROVIDE_XFR %token VAR_ALLOW_QUERY %token VAR_AXFR %token VAR_UDP %token VAR_NOTIFY_RETRY %token VAR_ALLOW_NOTIFY %token VAR_REQUEST_XFR %token VAR_ALLOW_AXFR_FALLBACK %token VAR_OUTGOING_INTERFACE %token VAR_ANSWER_COOKIE %token VAR_COOKIE_SECRET %token VAR_COOKIE_SECRET_FILE %token VAR_COOKIE_STAGING_SECRET %token VAR_MAX_REFRESH_TIME %token VAR_MIN_REFRESH_TIME %token VAR_MAX_RETRY_TIME %token VAR_MIN_RETRY_TIME %token VAR_MIN_EXPIRE_TIME %token VAR_MULTI_PRIMARY_CHECK %token VAR_SIZE_LIMIT_XFR %token VAR_ZONESTATS %token VAR_INCLUDE_PATTERN %token VAR_STORE_IXFR %token VAR_IXFR_SIZE %token VAR_IXFR_NUMBER %token VAR_CREATE_IXFR %token VAR_CATALOG %token VAR_CATALOG_MEMBER_PATTERN %token VAR_CATALOG_PRODUCER_ZONE /* zone */ %token VAR_ZONE %token VAR_RRL_WHITELIST /* socket options */ %token VAR_SERVERS %token VAR_BINDTODEVICE %token VAR_SETFIB /* verify */ %token VAR_VERIFY %token VAR_ENABLE %token VAR_VERIFY_ZONE %token VAR_VERIFY_ZONES %token VAR_VERIFIER %token VAR_VERIFIER_COUNT %token VAR_VERIFIER_FEED_ZONE %token VAR_VERIFIER_TIMEOUT %% blocks: /* may be empty */ | blocks block ; block: server | dnstap | remote_control | key | tls_auth | pattern | zone | verify ; server: VAR_SERVER server_block ; server_block: server_block server_option | ; server_option: VAR_IP_ADDRESS ip_address { struct ip_address_option *ip = cfg_parser->opt->ip_addresses; if(ip == NULL) { cfg_parser->opt->ip_addresses = $2; } else { while(ip->next) { ip = ip->next; } ip->next = $2; } cfg_parser->ip = $2; } socket_options { cfg_parser->ip = NULL; } | VAR_SERVER_COUNT number { if ($2 > 0) { cfg_parser->opt->server_count = (int)$2; } else { yyerror("expected a number greater than zero"); } } | VAR_IP_TRANSPARENT boolean { cfg_parser->opt->ip_transparent = $2; } | VAR_IP_FREEBIND boolean { cfg_parser->opt->ip_freebind = $2; } | VAR_SEND_BUFFER_SIZE number { cfg_parser->opt->send_buffer_size = (int)$2; } | VAR_RECEIVE_BUFFER_SIZE number { cfg_parser->opt->receive_buffer_size = (int)$2; } | VAR_DEBUG_MODE boolean { cfg_parser->opt->debug_mode = $2; } | VAR_USE_SYSTEMD boolean { /* ignored, obsolete */ } | VAR_HIDE_VERSION boolean { cfg_parser->opt->hide_version = $2; } | VAR_HIDE_IDENTITY boolean { cfg_parser->opt->hide_identity = $2; } | VAR_DROP_UPDATES boolean { cfg_parser->opt->drop_updates = $2; } | VAR_IP4_ONLY boolean { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } } | VAR_IP6_ONLY boolean { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } } | VAR_DO_IP4 boolean { cfg_parser->opt->do_ip4 = $2; } | VAR_DO_IP6 boolean { cfg_parser->opt->do_ip6 = $2; } | VAR_DATABASE STRING { /* ignored, obsolete */ } | VAR_IDENTITY STRING { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); } | VAR_VERSION STRING { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); } | VAR_NSID STRING { unsigned char* nsid = 0; size_t nsid_len = strlen($2); if (strncasecmp($2, "ascii_", 6) == 0) { nsid_len -= 6; /* discard "ascii_" */ if(nsid_len < 65535) { cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); } else { yyerror("NSID too long"); } } else if (nsid_len % 2 != 0) { yyerror("the NSID must be a hex string of an even length."); } else { nsid_len = nsid_len / 2; if(nsid_len < 65535) { nsid = xalloc(nsid_len); if (hex_pton($2, nsid, nsid_len) == -1) { yyerror("hex string cannot be parsed in NSID."); } else { cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2); } free(nsid); } else { yyerror("NSID too long"); } } } | VAR_LOGFILE STRING { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_LOG_ONLY_SYSLOG boolean { cfg_parser->opt->log_only_syslog = $2; } | VAR_TCP_COUNT number { if ($2 > 0) { cfg_parser->opt->tcp_count = (int)$2; } else { yyerror("expected a number greater than zero"); } } | VAR_TCP_REJECT_OVERFLOW boolean { cfg_parser->opt->tcp_reject_overflow = $2; } | VAR_TCP_QUERY_COUNT number { cfg_parser->opt->tcp_query_count = (int)$2; } | VAR_TCP_TIMEOUT number { cfg_parser->opt->tcp_timeout = (int)$2; } | VAR_TCP_MSS number { cfg_parser->opt->tcp_mss = (int)$2; } | VAR_OUTGOING_TCP_MSS number { cfg_parser->opt->outgoing_tcp_mss = (int)$2; } | VAR_IPV4_EDNS_SIZE number { cfg_parser->opt->ipv4_edns_size = (size_t)$2; } | VAR_IPV6_EDNS_SIZE number { cfg_parser->opt->ipv6_edns_size = (size_t)$2; } | VAR_PIDFILE STRING { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_PORT number { /* port number, stored as a string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", $2); cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf); } | VAR_REUSEPORT boolean { cfg_parser->opt->reuseport = $2; } | VAR_STATISTICS number { cfg_parser->opt->statistics = (int)$2; } | VAR_CHROOT STRING { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); } | VAR_USERNAME STRING { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); } | VAR_ZONESDIR STRING { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); } | VAR_ZONELISTFILE STRING { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_DIFFFILE STRING { /* ignored, obsolete */ } | VAR_XFRDFILE STRING { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_XFRDIR STRING { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); } | VAR_XFRD_RELOAD_TIMEOUT number { cfg_parser->opt->xfrd_reload_timeout = (int)$2; } | VAR_VERBOSITY number { cfg_parser->opt->verbosity = (int)$2; } | VAR_RRL_SIZE number { #ifdef RATELIMIT if ($2 > 0) { cfg_parser->opt->rrl_size = (size_t)$2; } else { yyerror("expected a number greater than zero"); } #endif } | VAR_RRL_RATELIMIT number { #ifdef RATELIMIT cfg_parser->opt->rrl_ratelimit = (size_t)$2; #endif } | VAR_RRL_SLIP number { #ifdef RATELIMIT cfg_parser->opt->rrl_slip = (size_t)$2; #endif } | VAR_RRL_IPV4_PREFIX_LENGTH number { #ifdef RATELIMIT if ($2 > 32) { yyerror("invalid IPv4 prefix length"); } else { cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2; } #endif } | VAR_RRL_IPV6_PREFIX_LENGTH number { #ifdef RATELIMIT if ($2 > 64) { yyerror("invalid IPv6 prefix length"); } else { cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2; } #endif } | VAR_RRL_WHITELIST_RATELIMIT number { #ifdef RATELIMIT cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2; #endif } | VAR_RELOAD_CONFIG boolean { cfg_parser->opt->reload_config = $2; } | VAR_ZONEFILES_CHECK boolean { cfg_parser->opt->zonefiles_check = $2; } | VAR_ZONEFILES_WRITE number { cfg_parser->opt->zonefiles_write = (int)$2; } | VAR_LOG_TIME_ASCII boolean { cfg_parser->opt->log_time_ascii = $2; log_time_asc = cfg_parser->opt->log_time_ascii; } | VAR_LOG_TIME_ISO boolean { cfg_parser->opt->log_time_iso = $2; log_time_iso = cfg_parser->opt->log_time_iso; } | VAR_ROUND_ROBIN boolean { cfg_parser->opt->round_robin = $2; round_robin = cfg_parser->opt->round_robin; } | VAR_MINIMAL_RESPONSES boolean { cfg_parser->opt->minimal_responses = $2; minimal_responses = cfg_parser->opt->minimal_responses; } | VAR_CONFINE_TO_ZONE boolean { cfg_parser->opt->confine_to_zone = $2; } | VAR_REFUSE_ANY boolean { cfg_parser->opt->refuse_any = $2; } | VAR_TLS_SERVICE_KEY STRING { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_SERVICE_OCSP STRING { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_SERVICE_PEM STRING { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_PORT number { /* port number, stored as string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", $2); cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf); } | VAR_TLS_AUTH_PORT number { /* port number, stored as string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", $2); cfg_parser->opt->tls_auth_port = region_strdup(cfg_parser->opt->region, buf); } | VAR_TLS_AUTH_XFR_ONLY boolean { if (!cfg_parser->opt->tls_auth_port) { yyerror("tls-auth-xfr-only set without or before tls-auth-port"); YYABORT; } cfg_parser->opt->tls_auth_xfr_only = $2; } | VAR_TLS_CERT_BUNDLE STRING { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); } | VAR_PROXY_PROTOCOL_PORT number { struct proxy_protocol_port_list* elem = region_alloc_zero( cfg_parser->opt->region, sizeof(*elem)); elem->port = $2; elem->next = cfg_parser->opt->proxy_protocol_port; cfg_parser->opt->proxy_protocol_port = elem; } | VAR_ANSWER_COOKIE boolean { cfg_parser->opt->answer_cookie = $2; } | VAR_COOKIE_SECRET STRING { uint8_t secret[32]; ssize_t len = hex_pton($2, secret, NSD_COOKIE_SECRET_SIZE); if(len != NSD_COOKIE_SECRET_SIZE) { yyerror("expected a 128 bit hex string"); } else { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); } } | VAR_COOKIE_STAGING_SECRET STRING { uint8_t secret[32]; ssize_t len = hex_pton($2, secret, NSD_COOKIE_SECRET_SIZE); if(len != NSD_COOKIE_SECRET_SIZE) { yyerror("expected a 128 bit hex string"); } else { cfg_parser->opt->cookie_staging_secret = region_strdup(cfg_parser->opt->region, $2); } } | VAR_COOKIE_SECRET_FILE STRING { /* Empty filename means explicitly disabled cookies from file, internally * represented as NULL. * Note that after parsing, if no value was configured, then * cookie_secret_file_is_default is still 1, then the default cookie * secret file value will be assigned to cookie_secret_file. */ if(*$2) cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); cfg_parser->opt->cookie_secret_file_is_default = 0; } | VAR_XFRD_TCP_MAX number { cfg_parser->opt->xfrd_tcp_max = (int)$2; } | VAR_XFRD_TCP_PIPELINE number { cfg_parser->opt->xfrd_tcp_pipeline = (int)$2; } | VAR_CPU_AFFINITY cpus { cfg_parser->opt->cpu_affinity = $2; } | service_cpu_affinity number { if($2 < 0) { yyerror("expected a non-negative number"); YYABORT; } else { struct cpu_map_option *opt, *tail; opt = cfg_parser->opt->service_cpu_affinity; while(opt && opt->service != $1) { opt = opt->next; } if(opt) { opt->cpu = $2; } else { opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt)); opt->service = (int)$1; opt->cpu = (int)$2; tail = cfg_parser->opt->service_cpu_affinity; if(tail) { while(tail->next) { tail = tail->next; } tail->next = opt; } else { cfg_parser->opt->service_cpu_affinity = opt; } } } } | VAR_METRICS_ENABLE boolean { #ifdef USE_METRICS cfg_parser->opt->metrics_enable = $2; #endif /* USE_METRICS */ } | VAR_METRICS_INTERFACE ip_address { #ifdef USE_METRICS struct ip_address_option *ip = cfg_parser->opt->metrics_interface; if(ip == NULL) { cfg_parser->opt->metrics_interface = $2; } else { while(ip->next != NULL) { ip = ip->next; } ip->next = $2; } #endif /* USE_METRICS */ } | VAR_METRICS_PORT number { #ifdef USE_METRICS if($2 == 0) { yyerror("metrics port number expected"); } else { cfg_parser->opt->metrics_port = (int)$2; } #endif /* USE_METRICS */ } | VAR_METRICS_PATH STRING { #ifdef USE_METRICS cfg_parser->opt->metrics_path = region_strdup(cfg_parser->opt->region, $2); #endif /* USE_METRICS */ } ; socket_options: | socket_options socket_option ; socket_option: VAR_SERVERS STRING { char *tok, *ptr, *str; struct range_option *servers = NULL; long long first, last; /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */ for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) { struct range_option *opt = region_alloc(cfg_parser->opt->region, sizeof(*opt)); first = last = 0; if(!parse_range(tok, &first, &last)) { yyerror("invalid server range '%s'", tok); YYABORT; } assert(first >= 0); assert(last >= 0); opt->next = NULL; opt->first = (int)first; opt->last = (int)last; if(servers) { servers = servers->next = opt; } else { servers = cfg_parser->ip->servers = opt; } } } | VAR_BINDTODEVICE boolean { cfg_parser->ip->dev = $2; } | VAR_SETFIB number { cfg_parser->ip->fib = $2; } ; cpus: { $$ = NULL; } | cpus STRING { char *tok, *ptr, *str; struct cpu_option *tail; long long cpu; str = $2; $$ = tail = $1; if(tail) { while(tail->next) { tail = tail->next; } } /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */ for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) { struct cpu_option *opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt)); cpu = 0; if(!parse_number(tok, &cpu) || cpu < 0) { yyerror("expected a positive number"); YYABORT; } assert(cpu >=0); opt->cpu = (int)cpu; if(tail) { tail->next = opt; tail = opt; } else { $$ = tail = opt; } } } ; service_cpu_affinity: VAR_XFRD_CPU_AFFINITY { $$ = -1; } | VAR_SERVER_CPU_AFFINITY { if($1 <= 0) { yyerror("invalid server identifier"); YYABORT; } $$ = $1; } ; dnstap: VAR_DNSTAP dnstap_block ; dnstap_block: dnstap_block dnstap_option | ; dnstap_option: VAR_DNSTAP_ENABLE boolean { cfg_parser->opt->dnstap_enable = $2; } | VAR_DNSTAP_SOCKET_PATH STRING { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_IP STRING { cfg_parser->opt->dnstap_ip = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_TLS boolean { cfg_parser->opt->dnstap_tls = $2; } | VAR_DNSTAP_TLS_SERVER_NAME STRING { cfg_parser->opt->dnstap_tls_server_name = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_TLS_CERT_BUNDLE STRING { cfg_parser->opt->dnstap_tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_TLS_CLIENT_KEY_FILE STRING { cfg_parser->opt->dnstap_tls_client_key_file = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_TLS_CLIENT_CERT_FILE STRING { cfg_parser->opt->dnstap_tls_client_cert_file = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_SEND_IDENTITY boolean { cfg_parser->opt->dnstap_send_identity = $2; } | VAR_DNSTAP_SEND_VERSION boolean { cfg_parser->opt->dnstap_send_version = $2; } | VAR_DNSTAP_IDENTITY STRING { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_VERSION STRING { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); } | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean { cfg_parser->opt->dnstap_log_auth_query_messages = $2; } | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean { cfg_parser->opt->dnstap_log_auth_response_messages = $2; } ; remote_control: VAR_REMOTE_CONTROL remote_control_block ; remote_control_block: remote_control_block remote_control_option | ; remote_control_option: VAR_CONTROL_ENABLE boolean { cfg_parser->opt->control_enable = $2; } | VAR_CONTROL_INTERFACE ip_address { struct ip_address_option *ip = cfg_parser->opt->control_interface; if(ip == NULL) { cfg_parser->opt->control_interface = $2; } else { while(ip->next != NULL) { ip = ip->next; } ip->next = $2; } } | VAR_CONTROL_PORT number { if($2 == 0) { yyerror("control port number expected"); } else { cfg_parser->opt->control_port = (int)$2; } } | VAR_SERVER_KEY_FILE STRING { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); } | VAR_SERVER_CERT_FILE STRING { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); } | VAR_CONTROL_KEY_FILE STRING { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); } | VAR_CONTROL_CERT_FILE STRING { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); } ; tls_auth: VAR_TLS_AUTH { tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region); assert(cfg_parser->tls_auth == NULL); cfg_parser->tls_auth = tls_auth; } tls_auth_block { struct tls_auth_options *tls_auth = cfg_parser->tls_auth; if(tls_auth->name == NULL) { yyerror("tls-auth has no name"); } else if(tls_auth->auth_domain_name == NULL) { yyerror("tls-auth %s has no auth-domain-name", tls_auth->name); } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) { yyerror("duplicate tls-auth %s", tls_auth->name); } else { tls_auth_options_insert(cfg_parser->opt, tls_auth); cfg_parser->tls_auth = NULL; } } ; tls_auth_block: tls_auth_block tls_auth_option | ; tls_auth_option: VAR_NAME STRING { dname_type *dname; dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2); cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2); if(dname == NULL) { yyerror("bad tls-auth name %s", $2); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); } } | VAR_TLS_AUTH_DOMAIN_NAME STRING { cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_AUTH_CLIENT_CERT STRING { cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_AUTH_CLIENT_KEY STRING { cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2); } | VAR_TLS_AUTH_CLIENT_KEY_PW STRING { cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2); } ; key: VAR_KEY { key_options_type *key = key_options_create(cfg_parser->opt->region); key->algorithm = region_strdup(cfg_parser->opt->region, "sha256"); assert(cfg_parser->key == NULL); cfg_parser->key = key; } key_block { struct key_options *key = cfg_parser->key; if(key->name == NULL) { yyerror("tsig key has no name"); } else if(key->algorithm == NULL) { yyerror("tsig key %s has no algorithm", key->name); } else if(key->secret == NULL) { yyerror("tsig key %s has no secret blob", key->name); } else if(key_options_find(cfg_parser->opt, key->name)) { yyerror("duplicate tsig key %s", key->name); } else { key_options_insert(cfg_parser->opt, key); cfg_parser->key = NULL; } } ; key_block: key_block key_option | ; key_option: VAR_NAME STRING { dname_type *dname; dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2); cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2); if(dname == NULL) { yyerror("bad tsig key name %s", $2); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); } } | VAR_ALGORITHM STRING { if(tsig_get_algorithm_by_name($2) == NULL) { yyerror("bad tsig key algorithm %s", $2); } else { cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2); } } | VAR_SECRET STRING { uint8_t data[16384]; int size; cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2); size = b64_pton($2, data, sizeof(data)); if(size == -1) { yyerror("cannot base64 decode tsig secret %s", cfg_parser->key->name? cfg_parser->key->name:""); } else if(size != 0) { memset(data, 0xdd, size); /* wipe secret */ } } ; zone: VAR_ZONE { assert(cfg_parser->pattern == NULL); assert(cfg_parser->zone == NULL); cfg_parser->zone = zone_options_create(cfg_parser->opt->region); cfg_parser->zone->part_of_config = 1; cfg_parser->zone->pattern = cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region); cfg_parser->zone->pattern->implicit = 1; } zone_block { assert(cfg_parser->zone != NULL); if(cfg_parser->zone->name == NULL) { yyerror("zone has no name"); } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) { yyerror("duplicate zone %s", cfg_parser->zone->name); } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) { yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname); } cfg_parser->pattern = NULL; cfg_parser->zone = NULL; } ; zone_block: zone_block zone_option | ; zone_option: VAR_NAME STRING { const char *marker = PATTERN_IMPLICIT_MARKER; char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1); memmove(pname, marker, strlen(marker)); memmove(pname + strlen(marker), $2, strlen($2) + 1); cfg_parser->zone->pattern->pname = pname; cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2); if(pattern_options_find(cfg_parser->opt, pname)) { yyerror("zone %s cannot be created because implicit pattern %s " "already exists", $2, pname); } } | pattern_or_zone_option ; pattern: VAR_PATTERN { assert(cfg_parser->pattern == NULL); cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region); } pattern_block { pattern_options_type *pattern = cfg_parser->pattern; if(pattern->pname == NULL) { yyerror("pattern has no name"); } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) { yyerror("duplicate pattern %s", pattern->pname); } cfg_parser->pattern = NULL; } ; pattern_block: pattern_block pattern_option | ; pattern_option: VAR_NAME STRING { if(strchr($2, ' ')) { yyerror("space is not allowed in pattern name: '%s'", $2); } cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2); } | pattern_or_zone_option ; pattern_or_zone_option: VAR_RRL_WHITELIST STRING { #ifdef RATELIMIT cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2); #endif } | VAR_ZONEFILE STRING { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); } | VAR_ZONESTATS STRING { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); } | VAR_SIZE_LIMIT_XFR number { if($2 > 0) { cfg_parser->pattern->size_limit_xfr = (int)$2; } else { yyerror("expected a number greater than zero"); } } | VAR_MULTI_PRIMARY_CHECK boolean { cfg_parser->pattern->multi_primary_check = (int)$2; } | VAR_INCLUDE_PATTERN STRING { config_apply_pattern(cfg_parser->pattern, $2); } | VAR_REQUEST_XFR STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); if(cfg_parser->pattern->catalog_role == CATALOG_ROLE_PRODUCER) yyerror("catalog producer zones cannot be secondary zones"); if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } request_xfr_tlsauth_option { } | VAR_REQUEST_XFR VAR_AXFR STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4); acl->use_axfr_only = 1; if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } request_xfr_tlsauth_option { } | VAR_REQUEST_XFR VAR_UDP STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4); acl->allow_udp = 1; if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) yyerror("address range used for request-xfr"); append_acl(&cfg_parser->pattern->request_xfr, acl); } | VAR_ALLOW_NOTIFY STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); append_acl(&cfg_parser->pattern->allow_notify, acl); } | VAR_NOTIFY STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); if(acl->blocked) yyerror("blocked address used for notify"); if(acl->rangetype != acl_range_single) yyerror("address range used for notify"); append_acl(&cfg_parser->pattern->notify, acl); } | VAR_PROVIDE_XFR STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); append_acl(&cfg_parser->pattern->provide_xfr, acl); } provide_xfr_tlsauth_option { } | VAR_ALLOW_QUERY STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); append_acl(&cfg_parser->pattern->allow_query, acl); } | VAR_OUTGOING_INTERFACE STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY"); append_acl(&cfg_parser->pattern->outgoing_interface, acl); } | VAR_ALLOW_AXFR_FALLBACK boolean { cfg_parser->pattern->allow_axfr_fallback = $2; cfg_parser->pattern->allow_axfr_fallback_is_default = 0; } | VAR_NOTIFY_RETRY number { cfg_parser->pattern->notify_retry = $2; cfg_parser->pattern->notify_retry_is_default = 0; } | VAR_MAX_REFRESH_TIME number { cfg_parser->pattern->max_refresh_time = $2; cfg_parser->pattern->max_refresh_time_is_default = 0; } | VAR_MIN_REFRESH_TIME number { cfg_parser->pattern->min_refresh_time = $2; cfg_parser->pattern->min_refresh_time_is_default = 0; } | VAR_MAX_RETRY_TIME number { cfg_parser->pattern->max_retry_time = $2; cfg_parser->pattern->max_retry_time_is_default = 0; } | VAR_MIN_RETRY_TIME number { cfg_parser->pattern->min_retry_time = $2; cfg_parser->pattern->min_retry_time_is_default = 0; } | VAR_MIN_EXPIRE_TIME STRING { long long num; uint8_t expr; if (!parse_expire_expr($2, &num, &expr)) { yyerror("expected an expire time in seconds or \"refresh+retry+1\""); YYABORT; /* trigger a parser error */ } cfg_parser->pattern->min_expire_time = num; cfg_parser->pattern->min_expire_time_expr = expr; } | VAR_STORE_IXFR boolean { cfg_parser->pattern->store_ixfr = $2; cfg_parser->pattern->store_ixfr_is_default = 0; } | VAR_IXFR_SIZE number { cfg_parser->pattern->ixfr_size = $2; cfg_parser->pattern->ixfr_size_is_default = 0; } | VAR_IXFR_NUMBER number { cfg_parser->pattern->ixfr_number = $2; cfg_parser->pattern->ixfr_number_is_default = 0; } | VAR_CREATE_IXFR boolean { cfg_parser->pattern->create_ixfr = $2; cfg_parser->pattern->create_ixfr_is_default = 0; } | VAR_VERIFY_ZONE boolean { cfg_parser->pattern->verify_zone = $2; } | VAR_VERIFIER command { cfg_parser->pattern->verifier = $2; } | VAR_VERIFIER_FEED_ZONE boolean { cfg_parser->pattern->verifier_feed_zone = $2; } | VAR_VERIFIER_TIMEOUT number { cfg_parser->pattern->verifier_timeout = $2; } | VAR_CATALOG catalog_role { if($2 == CATALOG_ROLE_PRODUCER && cfg_parser->pattern->request_xfr) yyerror("catalog producer zones cannot be secondary zones"); cfg_parser->pattern->catalog_role = $2; cfg_parser->pattern->catalog_role_is_default = 0; } | VAR_CATALOG_MEMBER_PATTERN STRING { cfg_parser->pattern->catalog_member_pattern = region_strdup(cfg_parser->opt->region, $2); } | VAR_CATALOG_PRODUCER_ZONE STRING { dname_type *dname; if(cfg_parser->zone) { yyerror("catalog-producer-zone option is for patterns only and cannot " "be used in a zone clause"); } else if(!(dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2))) { yyerror("bad catalog producer name %s", $2); } else { region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); cfg_parser->pattern->catalog_producer_zone = region_strdup(cfg_parser->opt->region, $2); } }; verify: VAR_VERIFY verify_block ; verify_block: verify_block verify_option | ; verify_option: VAR_ENABLE boolean { cfg_parser->opt->verify_enable = $2; } | VAR_IP_ADDRESS ip_address { struct ip_address_option *ip = cfg_parser->opt->verify_ip_addresses; if(!ip) { cfg_parser->opt->verify_ip_addresses = $2; } else { while(ip->next) { ip = ip->next; } ip->next = $2; } } | VAR_PORT number { /* port number, stored as a string */ char buf[16]; (void)snprintf(buf, sizeof(buf), "%lld", $2); cfg_parser->opt->verify_port = region_strdup(cfg_parser->opt->region, buf); } | VAR_VERIFY_ZONES boolean { cfg_parser->opt->verify_zones = $2; } | VAR_VERIFIER command { cfg_parser->opt->verifier = $2; } | VAR_VERIFIER_COUNT number { cfg_parser->opt->verifier_count = (int)$2; } | VAR_VERIFIER_TIMEOUT number { cfg_parser->opt->verifier_timeout = (int)$2; } | VAR_VERIFIER_FEED_ZONE boolean { cfg_parser->opt->verifier_feed_zone = $2; } ; command: STRING arguments { char **argv; size_t argc = 1; for(struct component *i = $2; i; i = i->next) { argc++; } argv = region_alloc_zero( cfg_parser->opt->region, (argc + 1) * sizeof(char *)); argc = 0; argv[argc++] = $1; for(struct component *j, *i = $2; i; i = j) { j = i->next; argv[argc++] = i->str; region_recycle(cfg_parser->opt->region, i, sizeof(*i)); } $$ = argv; } ; arguments: { $$ = NULL; } | arguments STRING { struct component *comp = region_alloc_zero( cfg_parser->opt->region, sizeof(*comp)); comp->str = region_strdup(cfg_parser->opt->region, $2); if($1) { struct component *tail = $1; while(tail->next) { tail = tail->next; } tail->next = comp; $$ = $1; } else { $$ = comp; } } ; ip_address: STRING { struct ip_address_option *ip = region_alloc_zero( cfg_parser->opt->region, sizeof(*ip)); ip->address = region_strdup(cfg_parser->opt->region, $1); ip->fib = -1; $$ = ip; } ; number: STRING { if(!parse_number($1, &$$)) { yyerror("expected a number"); YYABORT; /* trigger a parser error */ } } ; boolean: STRING { if(!parse_boolean($1, &$$)) { yyerror("expected yes or no"); YYABORT; /* trigger a parser error */ } } ; request_xfr_tlsauth_option: | STRING { char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1); add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ; provide_xfr_tlsauth_option: | STRING { char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1); add_to_last_acl(&cfg_parser->pattern->provide_xfr, tls_auth_name);} ; catalog_role: STRING { if(!parse_catalog_role($1, &$$)) { yyerror("expected consumer or producer"); YYABORT; /* trigger a parser error */ } } ; %% static void append_acl(struct acl_options **list, struct acl_options *acl) { assert(list != NULL); if(*list == NULL) { *list = acl; } else { struct acl_options *tail = *list; while(tail->next != NULL) tail = tail->next; tail->next = acl; } } static void add_to_last_acl(struct acl_options **list, char *tls_auth_name) { struct acl_options *tail = *list; assert(list != NULL); assert(*list != NULL); while(tail->next != NULL) tail = tail->next; tail->tls_auth_name = tls_auth_name; } static int parse_boolean(const char *str, int *bln) { if(strcmp(str, "yes") == 0) { *bln = 1; } else if(strcmp(str, "no") == 0) { *bln = 0; } else { return 0; } return 1; } static int parse_expire_expr(const char *str, long long *num, uint8_t *expr) { if(parse_number(str, num)) { *expr = EXPIRE_TIME_HAS_VALUE; return 1; } if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) { *num = 0; *expr = REFRESHPLUSRETRYPLUS1; return 1; } return 0; } static int parse_number(const char *str, long long *num) { /* ensure string consists entirely of digits */ size_t pos = 0; while(str[pos] >= '0' && str[pos] <= '9') { pos++; } if(pos != 0 && str[pos] == '\0') { *num = strtoll(str, NULL, 10); return 1; } return 0; } static int parse_range(const char *str, long long *low, long long *high) { const char *ptr = str; long long num[2]; /* require range to begin with a number */ if(*ptr < '0' || *ptr > '9') { return 0; } num[0] = strtoll(ptr, (char **)&ptr, 10); /* require number to be followed by nothing at all or a dash */ if(*ptr == '\0') { *low = num[0]; *high = num[0]; return 1; } else if(*ptr != '-') { return 0; } ++ptr; /* require dash to be followed by a number */ if(*ptr < '0' || *ptr > '9') { return 0; } num[1] = strtoll(ptr, (char **)&ptr, 10); /* require number to be followed by nothing at all */ if(*ptr == '\0') { if(num[0] < num[1]) { *low = num[0]; *high = num[1]; } else { *low = num[1]; *high = num[0]; } return 1; } return 0; } static int parse_catalog_role(const char *str, int *role) { if(strcasecmp(str, "consumer") == 0) { *role = CATALOG_ROLE_CONSUMER; } else if(strcmp(str, "producer") == 0) { *role = CATALOG_ROLE_PRODUCER; } else { return 0; } return 1; } nsd-4.12.0/configlexer.lex0000644000175000017500000004363515002373054015027 0ustar mozziemozzie%{ /* * configlexer.lex - lexical analyzer for NSD config file * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif #include #include #include #include #ifdef HAVE_GLOB_H # include #endif #include "options.h" #include "configparser.h" #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif struct inc_state { char* filename; int line; YY_BUFFER_STATE buffer; struct inc_state* next; }; static struct inc_state* config_include_stack = NULL; static int inc_depth = 0; static void config_start_include(const char* filename) { FILE *input; struct inc_state* s; char* nm; if(inc_depth++ > 10000000) { c_error("too many include files"); return; } if(strlen(filename) == 0) { c_error("empty include file name"); return; } s = (struct inc_state*)malloc(sizeof(*s)); if(!s) { c_error("include %s: malloc failure", filename); return; } nm = strdup(filename); if(!nm) { c_error("include %s: strdup failure", filename); free(s); return; } input = fopen(filename, "r"); if(!input) { c_error("cannot open include file '%s': %s", filename, strerror(errno)); free(s); free(nm); return; } LEXOUT(("switch_to_include_file(%s) ", filename)); s->filename = cfg_parser->filename; s->line = cfg_parser->line; s->buffer = YY_CURRENT_BUFFER; s->next = config_include_stack; config_include_stack = s; cfg_parser->filename = nm; cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); } static void config_start_include_glob(const char* filename) { /* check for wildcards */ #ifdef HAVE_GLOB glob_t g; int i, r, flags; #endif /* HAVE_GLOB */ if (cfg_parser->chroot) { int l = strlen(cfg_parser->chroot); /* chroot has trailing slash */ if (strncmp(cfg_parser->chroot, filename, l) != 0) { c_error("include file '%s' is not relative to chroot '%s'", filename, cfg_parser->chroot); return; } filename += l - 1; /* strip chroot without trailing slash */ } #ifdef HAVE_GLOB if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') && !strchr(filename, '{') && !strchr(filename, '~'))) { flags = 0 #ifdef GLOB_ERR | GLOB_ERR #endif /* do not set GLOB_NOSORT so the results are sorted and in a predictable order. */ #ifdef GLOB_BRACE | GLOB_BRACE #endif #ifdef GLOB_TILDE | GLOB_TILDE #endif ; memset(&g, 0, sizeof(g)); r = glob(filename, flags, NULL, &g); if(r) { /* some error */ globfree(&g); if(r == GLOB_NOMATCH) return; /* no matches for pattern */ config_start_include(filename); /* let original deal with it */ return; } /* process files found, if any */ for(i=(int)g.gl_pathc-1; i>=0; i--) { config_start_include(g.gl_pathv[i]); } globfree(&g); return; } #endif /* HAVE_GLOB */ config_start_include(filename); } static void config_end_include(void) { struct inc_state* s = config_include_stack; --inc_depth; if(!s) return; free(cfg_parser->filename); cfg_parser->filename = s->filename; cfg_parser->line = s->line; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(s->buffer); config_include_stack = s->next; free(s); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif %} %option noinput %option nounput %{ #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif %} SPACE [ \t] LETTER [a-zA-Z] UNQUOTEDLETTER [^\"\n\r \t\\]|\\. NEWLINE [\r\n] COMMENT \# COLON \: ANY [^\"\n\r\\]|\\. %x quotedstring include include_quoted %% {SPACE}* { LEXOUT(("SP ")); /* ignore */ } {SPACE}*{COMMENT}.* { LEXOUT(("comment(%s) ", yytext)); /* ignore */ } server{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} name{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;} ip-address{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} ip-transparent{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;} ip-freebind{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;} send-buffer-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SEND_BUFFER_SIZE;} receive-buffer-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RECEIVE_BUFFER_SIZE;} debug-mode{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;} use-systemd{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;} hide-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;} hide-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_IDENTITY;} drop-updates{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DROP_UPDATES; } ip4-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;} ip6-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;} do-ip4{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;} do-ip6{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;} database{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;} identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;} version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;} nsid{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NSID;} logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;} log-only-syslog{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_ONLY_SYSLOG;} server-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;} tcp-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;} tcp-reject-overflow{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_REJECT_OVERFLOW;} tcp-query-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;} tcp-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;} tcp-mss{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;} outgoing-tcp-mss{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;} ipv4-edns-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;} 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;} zonesdir{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;} zonelistfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;} difffile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;} xfrdfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;} xfrdir{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;} xfrd-reload-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;} verbosity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;} zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;} zonefile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;} zonestats{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;} allow-notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;} size-limit-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;} request-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;} notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;} notify-retry{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;} provide-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;} allow-query{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_QUERY;} outgoing-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;} allow-axfr-fallback{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;} tls-auth{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH;} auth-domain-name{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_DOMAIN_NAME;} client-cert{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_CERT;} client-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_KEY;} client-key-pw{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_CLIENT_KEY_PW;} key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_KEY;} algorithm{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;} secret{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;} pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;} include-pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDE_PATTERN;} remote-control{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;} control-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;} control-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;} control-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;} server-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;} server-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;} control-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;} control-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;} metrics-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_ENABLE;} metrics-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_INTERFACE;} metrics-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PORT;} metrics-path{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PATH;} AXFR { LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;} UDP { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} rrl-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} rrl-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;} rrl-slip{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;} rrl-ipv4-prefix-length{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;} rrl-ipv6-prefix-length{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;} rrl-whitelist-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;} rrl-whitelist{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;} reload-config{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RELOAD_CONFIG; } zonefiles-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;} zonefiles-write{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;} dnstap{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;} dnstap-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;} dnstap-socket-path{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; } dnstap-ip{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IP; } dnstap-tls{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS; } dnstap-tls-server-name{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_SERVER_NAME; } dnstap-tls-cert-bundle{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CERT_BUNDLE; } dnstap-tls-client-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CLIENT_KEY_FILE; } dnstap-tls-client-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_TLS_CLIENT_CERT_FILE; } dnstap-send-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; } dnstap-send-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; } dnstap-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; } dnstap-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; } dnstap-log-auth-query-messages{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; } dnstap-log-auth-response-messages{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; } log-time-ascii{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;} log-time-iso{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ISO;} round-robin{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;} minimal-responses{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;} confine-to-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONFINE_TO_ZONE;} refuse-any{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;} max-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;} min-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;} max-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;} min-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;} min-expire-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_EXPIRE_TIME;} store-ixfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_STORE_IXFR;} ixfr-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_SIZE;} ixfr-number{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_NUMBER;} create-ixfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CREATE_IXFR;} multi-master-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} multi-primary-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} tls-service-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;} tls-service-ocsp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;} tls-service-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;} tls-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;} tls-auth-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_PORT;} tls-auth-xfr-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_AUTH_XFR_ONLY;} tls-cert-bundle{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_CERT_BUNDLE; } proxy-protocol-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PROXY_PROTOCOL_PORT; } answer-cookie{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ANSWER_COOKIE;} cookie-secret{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET;} cookie-secret-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET_FILE;} cookie-staging-secret{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_STAGING_SECRET;} xfrd-tcp-max{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_MAX;} xfrd-tcp-pipeline{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_TCP_PIPELINE;} verify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY; } enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ENABLE; } verify-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY_ZONE; } verify-zones{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFY_ZONES; } verifier{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER; } verifier-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_COUNT; } verifier-feed-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_FEED_ZONE; } verifier-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_TIMEOUT; } catalog{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG; } catalog-member-pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_MEMBER_PATTERN; } catalog-producer-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_PRODUCER_ZONE; } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} servers={UNQUOTEDLETTER}* { yyless(yyleng - (yyleng - 8)); LEXOUT(("v(%s) ", yytext)); return VAR_SERVERS; } bindtodevice={UNQUOTEDLETTER}* { yyless(yyleng - (yyleng - 13)); LEXOUT(("v(%s) ", yytext)); return VAR_BINDTODEVICE; } setfib={UNQUOTEDLETTER}* { yyless(yyleng - (yyleng - 7)); LEXOUT(("v(%s) ", yytext)); return VAR_SETFIB; } cpu-affinity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CPU_AFFINITY; } xfrd-cpu-affinity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_CPU_AFFINITY; } server-[1-9][0-9]*-cpu-affinity{COLON} { char *str = yytext; LEXOUT(("v(%s) ", yytext)); /* Skip server- */ while (*str != '\0' && (*str < '0' || *str > '9')) { str++; } c_lval.llng = strtoll(str, NULL, 10); return VAR_SERVER_CPU_AFFINITY; } /* Quoted strings. Strip leading and ending quotes */ \" { BEGIN(quotedstring); LEXOUT(("QS ")); } <> { c_error("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("STR(%s) ", yytext)); yymore(); } \n { cfg_parser->line++; yymore(); } \" { LEXOUT(("QE ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; c_lval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } /* include: directive */ include{COLON} { LEXOUT(("v(%s) ", yytext)); BEGIN(include); } <> { c_error("EOF inside include directive"); BEGIN(INITIAL); } {SPACE}* { LEXOUT(("ISP ")); /* ignore */ } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} \" { LEXOUT(("IQS ")); BEGIN(include_quoted); } {UNQUOTEDLETTER}* { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext); BEGIN(INITIAL); } <> { c_error("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } {NEWLINE} { cfg_parser->line++; yymore(); } \" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; config_start_include_glob(yytext); BEGIN(INITIAL); } <> { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (!config_include_stack) { yyterminate(); } else { fclose(yyin); config_end_include(); } } {UNQUOTEDLETTER}* { LEXOUT(("unquotedstr(%s) ", yytext)); c_lval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } %% nsd-4.12.0/compat/0000755000175000017500000000000015002373054013260 5ustar mozziemozziensd-4.12.0/compat/strptime.c0000644000175000017500000002177715002373054015311 0ustar mozziemozzie/** strptime workaround (for oa macos leopard) * This strptime follows the man strptime (2001-11-12) * conforming to SUSv2, POSIX.1-2001 * * This very simple version of strptime has no: * - E alternatives * - O alternatives * - Glibc additions * - Does not process week numbers * - Does not properly processes year day * * LICENSE * Copyright (c) 2008, NLnet Labs, Matthijs Mekking. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NLnetLabs nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_CONFIG_H #include #endif #ifndef STRPTIME_WORKS #define TM_YEAR_BASE 1900 #include #include static const char *abb_weekdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; static const char *full_weekdays[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL }; static const char *abb_months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static const char *full_months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL }; static const char *ampm[] = { "am", "pm", NULL }; static int match_string(const char **buf, const char **strs) { int i = 0; for (i = 0; strs[i] != NULL; i++) { int len = strlen(strs[i]); if (strncasecmp (*buf, strs[i], len) == 0) { *buf += len; return i; } } return -1; } static int str2int(const char **buf, int max) { int ret=0, count=0; while (*buf[0] != '\0' && isdigit((unsigned char)*buf[0]) && counttm_wday = ret; break; case 'b': /* month name, abbreviated or full */ case 'B': case 'h': ret = match_string(&s, full_months); if (ret < 0) ret = match_string(&s, abb_months); if (ret < 0) { return NULL; } tm->tm_mon = ret; break; case 'c': /* date and time representation */ if (!(s = nsd_strptime(s, "%x %X", tm))) { return NULL; } break; case 'C': /* century number */ ret = str2int(&s, 2); if (ret < 0 || ret > 99) { /* must be in [00,99] */ return NULL; } if (split_year) { tm->tm_year = ret*100 + (tm->tm_year%100); } else { tm->tm_year = ret*100 - TM_YEAR_BASE; split_year = 1; } break; case 'd': /* day of month */ case 'e': ret = str2int(&s, 2); if (ret < 1 || ret > 31) { /* must be in [01,31] */ return NULL; } tm->tm_mday = ret; break; case 'D': /* equivalent to %m/%d/%y */ if (!(s = nsd_strptime(s, "%m/%d/%y", tm))) { return NULL; } break; case 'H': /* hour */ ret = str2int(&s, 2); if (ret < 0 || ret > 23) { /* must be in [00,23] */ return NULL; } tm->tm_hour = ret; break; case 'I': /* 12hr clock hour */ ret = str2int(&s, 2); if (ret < 1 || ret > 12) { /* must be in [01,12] */ return NULL; } if (ret == 12) /* actually [0,11] */ ret = 0; tm->tm_hour = ret; break; case 'j': /* day of year */ ret = str2int(&s, 2); if (ret < 1 || ret > 366) { /* must be in [001,366] */ return NULL; } tm->tm_yday = ret; break; case 'm': /* month */ ret = str2int(&s, 2); if (ret < 1 || ret > 12) { /* must be in [01,12] */ return NULL; } /* months go from 0-11 */ tm->tm_mon = (ret-1); break; case 'M': /* minute */ ret = str2int(&s, 2); if (ret < 0 || ret > 59) { /* must be in [00,59] */ return NULL; } tm->tm_min = ret; break; case 'n': /* arbitrary whitespace */ case 't': while (isspace((unsigned char)*s)) s++; break; case 'p': /* am pm */ ret = match_string(&s, ampm); if (ret < 0) { return NULL; } if (tm->tm_hour < 0 || tm->tm_hour > 11) { /* %I */ return NULL; } if (ret == 1) /* pm */ tm->tm_hour += 12; break; case 'r': /* equivalent of %I:%M:%S %p */ if (!(s = nsd_strptime(s, "%I:%M:%S %p", tm))) { return NULL; } break; case 'R': /* equivalent of %H:%M */ if (!(s = nsd_strptime(s, "%H:%M", tm))) { return NULL; } break; case 'S': /* seconds */ ret = str2int(&s, 2); /* 60 may occur for leap seconds */ /* earlier 61 was also allowed */ if (ret < 0 || ret > 60) { /* must be in [00,60] */ return NULL; } tm->tm_sec = ret; break; case 'T': /* equivalent of %H:%M:%S */ if (!(s = nsd_strptime(s, "%H:%M:%S", tm))) { return NULL; } break; case 'U': /* week number, with the first Sun of Jan being w1 */ ret = str2int(&s, 2); if (ret < 0 || ret > 53) { /* must be in [00,53] */ return NULL; } /** it is hard (and not necessary for nsd) to determine time * data from week number. **/ break; case 'w': /* day of week */ ret = str2int(&s, 1); if (ret < 0 || ret > 6) { /* must be in [0,6] */ return NULL; } tm->tm_wday = ret; break; case 'W': /* week number, with the first Mon of Jan being w1 */ ret = str2int(&s, 2); if (ret < 0 || ret > 53) { /* must be in [00,53] */ return NULL; } /** it is hard (and not necessary for nsd) to determine time * data from week number. **/ break; case 'x': /* date format */ if (!(s = nsd_strptime(s, "%m/%d/%y", tm))) { return NULL; } break; case 'X': /* time format */ if (!(s = nsd_strptime(s, "%H:%M:%S", tm))) { return NULL; } break; case 'y': /* last two digits of a year */ ret = str2int(&s, 2); if (ret < 0 || ret > 99) { /* must be in [00,99] */ return NULL; } if (split_year) { tm->tm_year = ((tm->tm_year/100) * 100) + ret; } else { split_year = 1; /** currently: * if in [0,68] we are in 21th century, * if in [69,99] we are in 20th century. **/ if (ret < 69) /* 2000 */ ret += 100; tm->tm_year = ret; } break; case 'Y': /* year */ ret = str2int(&s, 4); if (ret < 0 || ret > 9999) { return NULL; } tm->tm_year = ret - TM_YEAR_BASE; break; case '\0': default: /* unsupported, cannot match format */ return NULL; break; } } else { /* literal */ /* if input cannot match format, return NULL */ if (*s != c) return NULL; s++; } format++; } /* return pointer to remainder of s */ return (char*) s; } #endif /* STRPTIME_WORKS */ nsd-4.12.0/compat/strlcpy.c0000644000175000017500000000320515002373054015124 0ustar mozziemozzie/* from openssh 4.3p2 compat/strlcpy.c */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ #include #ifndef HAVE_STRLCPY #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ nsd-4.12.0/compat/strlcat.c0000644000175000017500000000461715002373054015110 0ustar mozziemozzie/* compat/strlcat.c */ /*- * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ #include #ifndef HAVE_STRLCAT #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* !HAVE_STRLCAT */ nsd-4.12.0/compat/snprintf.c0000644000175000017500000007131015002373054015271 0ustar mozziemozzie/* snprintf - compatibility implementation of snprintf, vsnprintf * * Copyright (c) 2013, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #include /* for test */ /* #define SNPRINTF_TEST 1 */ #ifdef SNPRINTF_TEST #define snprintf my_snprintf #define vsnprintf my_vsnprintf #endif /* SNPRINTF_TEST */ int snprintf(char* str, size_t size, const char* format, ...); int vsnprintf(char* str, size_t size, const char* format, va_list arg); /** * Very portable snprintf implementation, limited in functionality, * esp. for %[capital] %[nonportable] and so on. Reduced float functionality, * mostly in formatting and range (e+-16), for %f and %g. * * %s, %d, %u, %i, %x, %c, %n and %% are fully supported. * This includes width, precision, flags 0- +, and *(arg for wid,prec). * %f, %g, %m, %p have reduced support, support for wid,prec,flags,*, but * less floating point range, no %e formatting for %g. */ int snprintf(char* str, size_t size, const char* format, ...) { int r; va_list args; va_start(args, format); r = vsnprintf(str, size, format, args); va_end(args); return r; } /** add padding to string */ static void print_pad(char** at, size_t* left, int* ret, char p, int num) { while(num--) { if(*left > 1) { *(*at)++ = p; (*left)--; } (*ret)++; } } /** get negative symbol, 0 if none */ static char get_negsign(int negative, int plus, int space) { if(negative) return '-'; if(plus) return '+'; if(space) return ' '; return 0; } #define PRINT_DEC_BUFSZ 32 /* 20 is enough for 64 bit decimals */ /** print decimal into buffer, returns length */ static int print_dec(char* buf, int max, unsigned int value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print long decimal into buffer, returns length */ static int print_dec_l(char* buf, int max, unsigned long value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print long decimal into buffer, returns length */ static int print_dec_ll(char* buf, int max, unsigned long long value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print hex into buffer, returns length */ static int print_hex(char* buf, int max, unsigned int value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** print long hex into buffer, returns length */ static int print_hex_l(char* buf, int max, unsigned long value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** print long long hex into buffer, returns length */ static int print_hex_ll(char* buf, int max, unsigned long long value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** copy string into result, reversed */ static void spool_str_rev(char** at, size_t* left, int* ret, const char* buf, int len) { int i = len; while(i) { if(*left > 1) { *(*at)++ = buf[--i]; (*left)--; } else --i; (*ret)++; } } /** copy string into result */ static void spool_str(char** at, size_t* left, int* ret, const char* buf, int len) { int i; for(i=0; i 1) { *(*at)++ = buf[i]; (*left)--; } (*ret)++; } } /** print number formatted */ static void print_num(char** at, size_t* left, int* ret, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space, int zero, int negative, char* buf, int len) { int w = len; /* excludes minus sign */ char s = get_negsign(negative, plus, space); if(minus) { /* left adjust the number into the field, space padding */ /* calc numw = [sign][zeroes][number] */ int numw = w; if(precision == 0 && zero) numw = 0; if(numw < precision) numw = precision; if(s) numw++; /* sign */ if(s) print_pad(at, left, ret, s, 1); /* number */ if(precision == 0 && zero) { /* "" for the number */ } else { if(w < precision) print_pad(at, left, ret, '0', precision - w); spool_str_rev(at, left, ret, buf, len); } /* spaces */ if(numw < minw) print_pad(at, left, ret, ' ', minw - numw); } else { /* pad on the left of the number */ /* calculate numw has width of [sign][zeroes][number] */ int numw = w; if(precision == 0 && zero) numw = 0; if(numw < precision) numw = precision; if(!prgiven && zeropad && numw < minw) numw = minw; else if(s) numw++; /* pad with spaces */ if(numw < minw) print_pad(at, left, ret, ' ', minw - numw); /* print sign (and one less zeropad if so) */ if(s) { print_pad(at, left, ret, s, 1); numw--; } /* pad with zeroes */ if(w < numw) print_pad(at, left, ret, '0', numw - w); if(precision == 0 && zero) return; /* print the characters for the value */ spool_str_rev(at, left, ret, buf, len); } } /** print %d and %i */ static void print_num_d(char** at, size_t* left, int* ret, int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec(buf, (int)sizeof(buf), (unsigned int)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %ld and %li */ static void print_num_ld(char** at, size_t* left, int* ret, long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec_l(buf, (int)sizeof(buf), (unsigned long)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lld and %lli */ static void print_num_lld(char** at, size_t* left, int* ret, long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec_ll(buf, (int)sizeof(buf), (unsigned long long)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %u */ static void print_num_u(char** at, size_t* left, int* ret, unsigned int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lu */ static void print_num_lu(char** at, size_t* left, int* ret, unsigned long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec_l(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llu */ static void print_num_llu(char** at, size_t* left, int* ret, unsigned long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec_ll(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %x */ static void print_num_x(char** at, size_t* left, int* ret, unsigned int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lx */ static void print_num_lx(char** at, size_t* left, int* ret, unsigned long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex_l(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llx */ static void print_num_llx(char** at, size_t* left, int* ret, unsigned long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex_ll(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llp */ static void print_num_llp(char** at, size_t* left, int* ret, void* value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX) /* avoid warning about upcast on 32bit systems */ unsigned long long llvalue = (unsigned long)value; #else unsigned long long llvalue = (unsigned long long)value; #endif int len = print_hex_ll(buf, (int)sizeof(buf), llvalue); if(zero) { buf[0]=')'; buf[1]='l'; buf[2]='i'; buf[3]='n'; buf[4]='('; len = 5; } else { /* put '0x' in front of the (reversed) buffer result */ if(len < PRINT_DEC_BUFSZ) buf[len++] = 'x'; if(len < PRINT_DEC_BUFSZ) buf[len++] = '0'; } print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } #define PRINT_FLOAT_BUFSZ 64 /* xx.yy with 20.20 about the max */ /** spool remainder after the decimal point to buffer, in reverse */ static int print_remainder(char* buf, int max, double r, int prec) { unsigned long long cap = 1; unsigned long long value; int len, i; if(prec > 19) prec = 19; /* max we can do */ if(max < prec) return 0; for(i=0; i= 5) { value++; /* that might carry to numbers before the comma, if so, * just ignore that rounding. failure because 64bitprintout */ if(value >= cap) value = cap-1; } len = print_dec_ll(buf, max, value); while(len < prec) { /* pad with zeroes, e.g. if 0.0012 */ buf[len++] = '0'; } if(len < max) buf[len++] = '.'; return len; } /** spool floating point to buffer */ static int print_float(char* buf, int max, double value, int prec) { /* as xxx.xxx if prec==0, no '.', with prec decimals after . */ /* no conversion for NAN and INF, because we do not want to require linking with -lm. */ /* Thus, the conversions use 64bit integers to convert the numbers, * which makes 19 digits before and after the decimal point the max */ unsigned long long whole = (unsigned long long)value; double remain = value - (double)whole; int len = 0; if(prec != 0) len = print_remainder(buf, max, remain, prec); len += print_dec_ll(buf+len, max-len, whole); return len; } /** print %f */ static void print_num_f(char** at, size_t* left, int* ret, double value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_FLOAT_BUFSZ]; int negative = (value < 0); int zero = 0; int len; if(!prgiven) precision = 6; len = print_float(buf, (int)sizeof(buf), negative?-value:value, precision); print_num(at, left, ret, minw, 1, 0, zeropad, minus, plus, space, zero, negative, buf, len); } /* rudimentary %g support */ static int print_float_g(char* buf, int max, double value, int prec) { unsigned long long whole = (unsigned long long)value; double remain = value - (double)whole; int before = 0; int len = 0; /* number of digits before the decimal point */ while(whole > 0) { before++; whole /= 10; } whole = (unsigned long long)value; if(prec > before && remain != 0.0) { /* see if the last decimals are zero, if so, skip them */ len = print_remainder(buf, max, remain, prec-before); while(len > 0 && buf[0]=='0') { memmove(buf, buf+1, --len); } } len += print_dec_ll(buf+len, max-len, whole); return len; } /** print %g */ static void print_num_g(char** at, size_t* left, int* ret, double value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_FLOAT_BUFSZ]; int negative = (value < 0); int zero = 0; int len; if(!prgiven) precision = 6; if(precision == 0) precision = 1; len = print_float_g(buf, (int)sizeof(buf), negative?-value:value, precision); print_num(at, left, ret, minw, 1, 0, zeropad, minus, plus, space, zero, negative, buf, len); } /** strnlen (compat implementation) */ static int my_strnlen(const char* s, int max) { int i; for(i=0; i 1) { *at++ = *fmt++; left--; } else fmt++; ret++; } /* see if we are at end */ if(!*fmt) break; /* fetch next argument % designation from format string */ fmt++; /* skip the '%' */ /********************************/ /* get the argument designation */ /********************************/ /* we must do this vararg stuff inside this function for * portability. Hence, get_designation, and print_designation * are not their own functions. */ /* printout designation: * conversion specifier: x, d, u, s, c, n, m, p * flags: # not supported * 0 zeropad (on the left) * - left adjust (right by default) * ' ' printspace for positive number (in - position). * + alwayssign * fieldwidth: [1-9][0-9]* minimum field width. * if this is * then type int next argument specifies the minwidth. * if this is negative, the - flag is set (with positive width). * precision: period[digits]*, %.2x. * if this is * then type int next argument specifies the precision. * just '.' or negative value means precision=0. * this is mindigits to print for d, i, u, x * this is aftercomma digits for f * this is max number significant digits for g * maxnumber characters to be printed for s * length: 0-none (int), 1-l (long), 2-ll (long long) * notsupported: hh (char), h (short), L (long double), q, j, z, t * Does not support %m$ and *m$ argument designation as array indices. * Does not support %#x * */ minw = 0; precision = 1; prgiven = 0; zeropad = 0; minus = 0; plus = 0; space = 0; length = 0; /* get flags in any order */ for(;;) { if(*fmt == '0') zeropad = 1; else if(*fmt == '-') minus = 1; else if(*fmt == '+') plus = 1; else if(*fmt == ' ') space = 1; else break; fmt++; } /* field width */ if(*fmt == '*') { fmt++; /* skip char */ minw = va_arg(arg, int); if(minw < 0) { minus = 1; minw = -minw; } } else while(*fmt >= '0' && *fmt <= '9') { minw = minw*10 + (*fmt++)-'0'; } /* precision */ if(*fmt == '.') { fmt++; /* skip period */ prgiven = 1; precision = 0; if(*fmt == '*') { fmt++; /* skip char */ precision = va_arg(arg, int); if(precision < 0) precision = 0; } else while(*fmt >= '0' && *fmt <= '9') { precision = precision*10 + (*fmt++)-'0'; } } /* length */ if(*fmt == 'l') { fmt++; /* skip char */ length = 1; if(*fmt == 'l') { fmt++; /* skip char */ length = 2; } } /* get the conversion */ if(!*fmt) conv = 0; else conv = *fmt++; /***********************************/ /* print that argument designation */ /***********************************/ switch(conv) { case 'i': case 'd': if(length == 0) print_num_d(&at, &left, &ret, va_arg(arg, int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_ld(&at, &left, &ret, va_arg(arg, long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_lld(&at, &left, &ret, va_arg(arg, long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'u': if(length == 0) print_num_u(&at, &left, &ret, va_arg(arg, unsigned int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_lu(&at, &left, &ret, va_arg(arg, unsigned long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_llu(&at, &left, &ret, va_arg(arg, unsigned long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'x': if(length == 0) print_num_x(&at, &left, &ret, va_arg(arg, unsigned int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_lx(&at, &left, &ret, va_arg(arg, unsigned long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_llx(&at, &left, &ret, va_arg(arg, unsigned long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 's': print_str(&at, &left, &ret, va_arg(arg, char*), minw, precision, prgiven, minus); break; case 'c': print_char(&at, &left, &ret, va_arg(arg, int), minw, minus); break; case 'n': *va_arg(arg, int*) = ret; break; case 'm': print_str(&at, &left, &ret, strerror(errno), minw, precision, prgiven, minus); break; case 'p': print_num_llp(&at, &left, &ret, va_arg(arg, void*), minw, precision, prgiven, zeropad, minus, plus, space); break; case '%': print_pad(&at, &left, &ret, '%', 1); break; case 'f': print_num_f(&at, &left, &ret, va_arg(arg, double), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'g': print_num_g(&at, &left, &ret, va_arg(arg, double), minw, precision, prgiven, zeropad, minus, plus, space); break; /* unknown */ default: case 0: break; } } /* zero terminate */ if(left > 0) *at = 0; return ret; } #ifdef SNPRINTF_TEST /** do tests */ #undef snprintf #define DOTEST(bufsz, result, retval, ...) do { \ char buf[bufsz]; \ printf("now test %s\n", #__VA_ARGS__); \ int r=my_snprintf(buf, sizeof(buf), __VA_ARGS__); \ if(r != retval || strcmp(buf, result) != 0) { \ printf("error test(%s) was \"%s\":%d\n", \ ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ buf, r); \ exit(1); \ } \ r=snprintf(buf, sizeof(buf), __VA_ARGS__); \ if(r != retval || strcmp(buf, result) != 0) { \ printf("error test(%s) differs with system, \"%s\":%d\n", \ ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ buf, r); \ exit(1); \ } \ printf("test(\"%s\":%d) passed\n", buf, r); \ } while(0); /** test program */ int main(void) { int x = 0; /* bufsize, expectedstring, expectedretval, snprintf arguments */ DOTEST(1024, "hello", 5, "hello"); DOTEST(1024, "h", 1, "h"); /* warning from gcc for format string, but it does work * DOTEST(1024, "", 0, ""); */ DOTEST(3, "he", 5, "hello"); DOTEST(1, "", 7, "%d", 7823089); /* test positive numbers */ DOTEST(1024, "0", 1, "%d", 0); DOTEST(1024, "1", 1, "%d", 1); DOTEST(1024, "9", 1, "%d", 9); DOTEST(1024, "15", 2, "%d", 15); DOTEST(1024, "ab15cd", 6, "ab%dcd", 15); DOTEST(1024, "167", 3, "%d", 167); DOTEST(1024, "7823089", 7, "%d", 7823089); DOTEST(1024, " 12", 3, "%3d", 12); DOTEST(1024, "012", 3, "%.3d", 12); DOTEST(1024, "012", 3, "%3.3d", 12); DOTEST(1024, "012", 3, "%03d", 12); DOTEST(1024, " 012", 4, "%4.3d", 12); DOTEST(1024, "", 0, "%.0d", 0); /* test negative numbers */ DOTEST(1024, "-1", 2, "%d", -1); DOTEST(1024, "-12", 3, "%3d", -12); DOTEST(1024, " -2", 3, "%3d", -2); DOTEST(1024, "-012", 4, "%.3d", -12); DOTEST(1024, "-012", 4, "%3.3d", -12); DOTEST(1024, "-012", 4, "%4.3d", -12); DOTEST(1024, " -012", 5, "%5.3d", -12); DOTEST(1024, "-12", 3, "%03d", -12); DOTEST(1024, "-02", 3, "%03d", -2); DOTEST(1024, "-15", 3, "%d", -15); DOTEST(1024, "-7307", 5, "%d", -7307); DOTEST(1024, "-12 ", 5, "%-5d", -12); DOTEST(1024, "-00012", 6, "%-.5d", -12); /* test + and space flags */ DOTEST(1024, "+12", 3, "%+d", 12); DOTEST(1024, " 12", 3, "% d", 12); /* test %u */ DOTEST(1024, "12", 2, "%u", 12); DOTEST(1024, "0", 1, "%u", 0); DOTEST(1024, "4294967295", 10, "%u", 0xffffffff); /* test %x */ DOTEST(1024, "0", 1, "%x", 0); DOTEST(1024, "c", 1, "%x", 12); DOTEST(1024, "12ab34cd", 8, "%x", 0x12ab34cd); /* test %llu, %lld */ DOTEST(1024, "18446744073709551615", 20, "%llu", (long long)0xffffffffffffffff); DOTEST(1024, "-9223372036854775808", 20, "%lld", (long long)0x8000000000000000); DOTEST(1024, "9223372036854775808", 19, "%llu", (long long)0x8000000000000000); /* test %s */ DOTEST(1024, "hello", 5, "%s", "hello"); DOTEST(1024, " hello", 10, "%10s", "hello"); DOTEST(1024, "hello ", 10, "%-10s", "hello"); DOTEST(1024, "he", 2, "%.2s", "hello"); DOTEST(1024, " he", 4, "%4.2s", "hello"); DOTEST(1024, " h", 4, "%4.2s", "h"); /* test %c */ DOTEST(1024, "a", 1, "%c", 'a'); /* warning from gcc for format string, but it does work DOTEST(1024, " a", 5, "%5c", 'a'); DOTEST(1024, "a", 1, "%.0c", 'a'); */ /* test %n */ DOTEST(1024, "hello", 5, "hello%n", &x); if(x != 5) { printf("the %%n failed\n"); exit(1); } /* test %m */ errno = 0; DOTEST(1024, "Success", 7, "%m"); /* test %p */ DOTEST(1024, "0x10", 4, "%p", (void*)0x10); DOTEST(1024, "(nil)", 5, "%p", (void*)0x0); /* test %% */ DOTEST(1024, "%", 1, "%%"); /* test %f */ DOTEST(1024, "0.000000", 8, "%f", 0.0); DOTEST(1024, "0.00", 4, "%.2f", 0.0); /* differs, "-0.00" DOTEST(1024, "0.00", 4, "%.2f", -0.0); */ DOTEST(1024, "234.00", 6, "%.2f", 234.005); DOTEST(1024, "8973497.1246", 12, "%.4f", 8973497.12456); DOTEST(1024, "-12.000000", 10, "%f", -12.0); DOTEST(1024, "6", 1, "%.0f", 6.0); DOTEST(1024, "6", 1, "%g", 6.0); DOTEST(1024, "6.1", 3, "%g", 6.1); DOTEST(1024, "6.15", 4, "%g", 6.15); /* These format strings are from the code of NSD, Unbound, ldns */ DOTEST(1024, "abcdef", 6, "%s", "abcdef"); DOTEST(1024, "005", 3, "%03u", 5); DOTEST(1024, "12345", 5, "%03u", 12345); DOTEST(1024, "5", 1, "%d", 5); DOTEST(1024, "(nil)", 5, "%p", NULL); DOTEST(1024, "12345", 5, "%ld", (long)12345); DOTEST(1024, "12345", 5, "%lu", (long)12345); DOTEST(1024, " 12345", 12, "%12u", (unsigned)12345); DOTEST(1024, "12345", 5, "%u", (unsigned)12345); DOTEST(1024, "12345", 5, "%llu", (unsigned long long)12345); DOTEST(1024, "12345", 5, "%x", 0x12345); DOTEST(1024, "12345", 5, "%llx", (long long)0x12345); DOTEST(1024, "012345", 6, "%6.6d", 12345); DOTEST(1024, "012345", 6, "%6.6u", 12345); DOTEST(1024, "1234.54", 7, "%g", 1234.54); DOTEST(1024, "123456789.54", 12, "%.12g", 123456789.54); DOTEST(1024, "3456789123456.54", 16, "%.16g", 3456789123456.54); /* %24g does not work with 24 digits, not enough accuracy, * the first 16 digits are correct */ DOTEST(1024, "12345", 5, "%3.3d", 12345); DOTEST(1024, "000", 3, "%3.3d", 0); DOTEST(1024, "001", 3, "%3.3d", 1); DOTEST(1024, "012", 3, "%3.3d", 12); DOTEST(1024, "-012", 4, "%3.3d", -12); DOTEST(1024, "he", 2, "%.2s", "hello"); DOTEST(1024, "helloworld", 10, "%s%s", "hello", "world"); DOTEST(1024, "he", 2, "%.*s", 2, "hello"); DOTEST(1024, " hello", 7, "%*s", 7, "hello"); DOTEST(1024, "hello ", 7, "%*s", -7, "hello"); DOTEST(1024, "0", 1, "%c", '0'); DOTEST(1024, "A", 1, "%c", 'A'); DOTEST(1024, "", 1, "%c", 0); DOTEST(1024, "\010", 1, "%c", 8); DOTEST(1024, "%", 1, "%%"); DOTEST(1024, "0a", 2, "%02x", 0x0a); DOTEST(1024, "bd", 2, "%02x", 0xbd); DOTEST(1024, "12", 2, "%02ld", (long)12); DOTEST(1024, "02", 2, "%02ld", (long)2); DOTEST(1024, "02", 2, "%02u", (unsigned)2); DOTEST(1024, "765432", 6, "%05u", (unsigned)765432); DOTEST(1024, "10.234", 6, "%0.3f", 10.23421); DOTEST(1024, "123456.234", 10, "%0.3f", 123456.23421); DOTEST(1024, "123456789.234", 13, "%0.3f", 123456789.23421); DOTEST(1024, "123456.23", 9, "%.2f", 123456.23421); DOTEST(1024, "123456", 6, "%.0f", 123456.23421); DOTEST(1024, "0123", 4, "%.4x", 0x0123); DOTEST(1024, "00000123", 8, "%.8x", 0x0123); DOTEST(1024, "ffeb0cde", 8, "%.8x", 0xffeb0cde); DOTEST(1024, " 987654321", 10, "%10lu", (unsigned long)987654321); DOTEST(1024, " 987654321", 12, "%12lu", (unsigned long)987654321); DOTEST(1024, "987654321", 9, "%i", 987654321); DOTEST(1024, "-87654321", 9, "%i", -87654321); DOTEST(1024, "hello ", 16, "%-16s", "hello"); DOTEST(1024, " ", 16, "%-16s", ""); DOTEST(1024, "a ", 16, "%-16s", "a"); DOTEST(1024, "foobarfoobar ", 16, "%-16s", "foobarfoobar"); DOTEST(1024, "foobarfoobarfoobar", 18, "%-16s", "foobarfoobarfoobar"); /* combined expressions */ DOTEST(1024, "foo 1.0 size 512 edns", 21, "foo %s size %d %s%s", "1.0", 512, "", "edns"); DOTEST(15, "foo 1.0 size 5", 21, "foo %s size %d %s%s", "1.0", 512, "", "edns"); DOTEST(1024, "packet 1203ceff id", 18, "packet %2.2x%2.2x%2.2x%2.2x id", 0x12, 0x03, 0xce, 0xff); DOTEST(1024, "/tmp/testbound_123abcd.tmp", 26, "/tmp/testbound_%u%s%s.tmp", 123, "ab", "cd"); return 0; } #endif /* SNPRINTF_TEST */ nsd-4.12.0/compat/setproctitle.c0000644000175000017500000000322015002373054016142 0ustar mozziemozzie/* * setproctitle.c -- mimic setproctitle * * Copyright (c) 2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #if defined(__linux) #include #include #ifndef HAVE_CONFIG_H #include #endif #include #include #include #include #include static char *executable(void) { char *ptr, *buf = NULL; size_t len = 0; ssize_t cnt = 0; buf = NULL; do { len += 32; ptr = realloc(buf, len); if (ptr == NULL) { if (buf != NULL) { free(buf); } return NULL; } buf = ptr; cnt = readlink("/proc/self/exe", buf, len); } while (cnt >= 0 && (size_t)cnt == len); if (cnt >= 0) { buf[cnt] = '\0'; return buf; } free(buf); return NULL; } void setproctitle(const char *fmt, ...) { va_list ap; char buf[32]; int cnt = 0, off = 0; /* prepend executable name if fmt does not start with '-' */ if (fmt == NULL || fmt[0] != '-' || fmt[(off = 1)] == '\0') { char *exe; const char *sep = (fmt && fmt[off] != '\0') ? ": " : ""; if ((exe = executable()) != NULL) { cnt = snprintf(buf, sizeof(buf), "%s%s", basename(exe), sep); if ((size_t)cnt >= sizeof(buf)) { cnt = 31; /* leave room for '\0' */ } free(exe); } } if (fmt != NULL && fmt[off] != '\0') { va_start(ap, fmt); cnt = vsnprintf( buf+(size_t)cnt, sizeof(buf)-(size_t)cnt, fmt+(size_t)off, ap); va_end(ap); } if (cnt > 0) { assert(cnt > 0 && (size_t)cnt < sizeof(buf)); (void)prctl(PR_SET_NAME, buf, 0, 0, 0); } } #endif /* __linux */ nsd-4.12.0/compat/reallocarray.c0000644000175000017500000000262615002373054016112 0ustar mozziemozzie/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ /* * Copyright (c) 2008 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #include #ifdef HAVE_STDINT_H #include #endif #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * reallocarray(void *optr, size_t nmemb, size_t size) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return realloc(optr, size * nmemb); } nsd-4.12.0/compat/pselect.c0000644000175000017500000000174515002373054015072 0ustar mozziemozzie/* * Like select(2) but set the signals to block while waiting in * select. This version is not entirely race condition safe. Only * operating system support can make it so. */ #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include #include int pselect (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { int result; sigset_t saved_sigmask; struct timeval saved_timeout; if (sigmask && sigprocmask(SIG_SETMASK, sigmask, &saved_sigmask) == -1) return -1; if (timeout) { saved_timeout.tv_sec = timeout->tv_sec; saved_timeout.tv_usec = timeout->tv_nsec / 1000; result = select(n, readfds, writefds, exceptfds, &saved_timeout); } else { result = select(n, readfds, writefds, exceptfds, NULL); } if (sigmask && sigprocmask(SIG_SETMASK, &saved_sigmask, NULL) == -1) return -1; return result; } nsd-4.12.0/compat/memmove.c0000644000175000017500000000166515002373054015101 0ustar mozziemozzie/* * memmove.c: memmove compat implementation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #include #include void *memmove(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n) { uint8_t* from = (uint8_t*) src; uint8_t* to = (uint8_t*) dest; if (from == to || n == 0) return dest; if (to > from && to-from < (int)n) { /* to overlaps with from */ /* */ /* */ /* copy in reverse, to avoid overwriting from */ int i; for(i=n-1; i>=0; i--) to[i] = from[i]; return dest; } if (from > to && from-to < (int)n) { /* to overlaps with from */ /* */ /* */ /* copy forwards, to avoid overwriting from */ size_t i; for(i=0; i int memcmp(const void *x, const void *y, size_t n); int memcmp(const void *x, const void *y, size_t n) { const uint8_t* x8 = (const uint8_t*)x; const uint8_t* y8 = (const uint8_t*)y; size_t i; for(i=0; i y8[i]) return 1; } return 0; } nsd-4.12.0/compat/malloc.c0000644000175000017500000000060015002373054014667 0ustar mozziemozzie/* Just a replacement, if the original malloc is not GNU-compliant. See autoconf documentation. */ #if HAVE_CONFIG_H #include #endif #undef malloc #include void *malloc (); /* Allocate an N-byte block of memory from the heap. If N is zero, allocate a 1-byte block. */ void * rpl_malloc (size_t n) { if (n == 0) n = 1; return malloc (n); } nsd-4.12.0/compat/inet_pton.c0000644000175000017500000001214215002373054015423 0ustar mozziemozzie/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4 (const char *src, uint8_t *dst); static int inet_pton6 (const char *src, uint8_t *dst); /* * * The definitions we might miss. * */ #ifndef NS_INT16SZ #define NS_INT16SZ 2 #endif #ifndef NS_IN6ADDRSZ #define NS_IN6ADDRSZ 16 #endif #ifndef NS_INADDRSZ #define NS_INADDRSZ 4 #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(af, src, dst) int af; const char *src; void *dst; { switch (af) { case AF_INET: return (inet_pton4(src, dst)); case AF_INET6: return (inet_pton6(src, dst)); default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(src, dst) const char *src; uint8_t *dst; { static const char digits[] = "0123456789"; int saw_digit, octets, ch; uint8_t tmp[NS_INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { uint32_t new = *tp * 10 + (pch - digits); if (new > 255) return (0); *tp = new; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ static int inet_pton6(src, dst) const char *src; uint8_t *dst; { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; uint32_t val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } nsd-4.12.0/compat/inet_ntop.c0000644000175000017500000001253315002373054015427 0ustar mozziemozzie/* From openssh 4.3p2 compat/inet_ntop.c */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */ #include #ifndef HAVE_INET_NTOP #include #include #include #include #include #include #include #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ #endif #ifndef INT16SZ #define INT16SZ 2 /* for systems without 16-bit ints */ #endif /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static const char *inet_ntop4(const u_char *src, char *dst, size_t size); static const char *inet_ntop6(const u_char *src, char *dst, size_t size); /* char * * inet_ntop(af, src, dst, size) * convert a network format address to presentation format. * return: * pointer to presentation format address (`dst'), or NULL (see errno). * author: * Paul Vixie, 1996. */ const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET: return (inet_ntop4(src, dst, size)); case AF_INET6: return (inet_ntop6(src, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address, more or less like inet_ntoa() * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a u_char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char * inet_ntop4(const u_char *src, char *dst, size_t size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; int l; l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); if (l <= 0 || l >= (int)size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } /* const char * * inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ static const char * inet_ntop6(const u_char *src, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; char *tp, *ep; struct { int base, len; } best, cur; u_int words[IN6ADDRSZ / INT16SZ]; int i; int advance; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; ep = tmp + sizeof(tmp); for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) return (NULL); tp += strlen(tp); break; } advance = snprintf(tp, ep - tp, "%x", words[i]); if (advance <= 0 || advance >= ep - tp) return (NULL); tp += advance; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } if (tp + 1 >= ep) return (NULL); *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } #endif /* !HAVE_INET_NTOP */ nsd-4.12.0/compat/inet_aton.c0000644000175000017500000001253015002373054015405 0ustar mozziemozzie/* From openssh4.3p2 compat/inet_aton.c */ /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - * --Copyright-- */ /* OPENBSD ORIGINAL: lib/libc/net/inet_addr.c */ #include #if !defined(HAVE_INET_ATON) #include #include #include #include #include #if 0 /* * Ascii internet address interpretation routine. * The value returned is in network order. */ in_addr_t inet_addr(const char *cp) { struct in_addr val; if (inet_aton(cp, &val)) return (val.s_addr); return (INADDR_NONE); } #endif /* * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which * cannot distinguish between failure and a local broadcast address. */ int inet_aton(const char *cp, struct in_addr *addr) { uint32_t val; int base, n; char c; unsigned int parts[4]; unsigned int *pp = parts; c = *cp; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, isdigit=decimal. */ if (!isdigit((unsigned char)c)) return (0); val = 0; base = 10; if (c == '0') { c = *++cp; if (c == 'x' || c == 'X') base = 16, c = *++cp; else base = 8; } for (;;) { if (isascii((unsigned char)c) && isdigit((unsigned char)c)) { val = (val * base) + (c - '0'); c = *++cp; } else if (base == 16 && isascii((unsigned char)c) && isxdigit((unsigned char)c)) { val = (val << 4) | (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); c = *++cp; } else break; } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3) return (0); *pp++ = val; c = *++cp; } else break; } /* * Check for trailing characters. */ if (c != '\0' && (!isascii((unsigned char)c) || !isspace((unsigned char)c))) return (0); /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 0: return (0); /* initial nondigit */ case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if ((val > 0xffffff) || (parts[0] > 0xff)) return (0); val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr) addr->s_addr = htonl(val); return (1); } #endif /* !defined(HAVE_INET_ATON) */ nsd-4.12.0/compat/fake-rfc2553.h0000644000175000017500000001241215002373054015426 0ustar mozziemozzie/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */ /* * Copyright (C) 2000-2003 Damien Miller. All rights reserved. * Copyright (C) 1999 WIDE Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Pseudo-implementation of RFC2553 name / address resolution functions * * But these functions are not implemented correctly. The minimum subset * is implemented for ssh use only. For example, this routine assumes * that ai_family is AF_INET. Don't use it for another purpose. */ #ifndef FAKE_RFC2553_H #define FAKE_RFC2553_H #include #include #include #include #include /* * First, socket and INET6 related definitions */ #ifndef HAVE_STRUCT_SOCKADDR_STORAGE # define _SS_MAXSIZE 128 /* Implementation specific max size */ # define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr)) struct sockaddr_storage { struct sockaddr ss_sa; char __ss_pad2[_SS_PADSIZE]; }; # define ss_family ss_sa.sa_family #endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ #ifndef IN6_IS_ADDR_LOOPBACK # define IN6_IS_ADDR_LOOPBACK(a) \ (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ ((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == htonl(1)) #endif /* !IN6_IS_ADDR_LOOPBACK */ #ifndef HAVE_STRUCT_IN6_ADDR struct in6_addr { uint8_t s6_addr[16]; }; #endif /* !HAVE_STRUCT_IN6_ADDR */ #ifndef HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 { unsigned short sin6_family; uint16_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; }; #endif /* !HAVE_STRUCT_SOCKADDR_IN6 */ #ifndef AF_INET6 /* Define it to something that should never appear */ #define AF_INET6 AF_MAX #endif #ifndef PF_INET #define PF_INET AF_INET #endif #ifndef PF_INET6 #define PF_INET6 AF_INET6 #endif /* * Next, RFC2553 name / address resolution API */ #ifndef NI_NUMERICHOST # define NI_NUMERICHOST (1) #endif #ifndef NI_NAMEREQD # define NI_NAMEREQD (1<<1) #endif #ifndef NI_NUMERICSERV # define NI_NUMERICSERV (1<<2) #endif #ifndef AI_PASSIVE # define AI_PASSIVE (1) #endif #ifndef AI_CANONNAME # define AI_CANONNAME (1<<1) #endif #ifndef AI_NUMERICHOST # define AI_NUMERICHOST (1<<2) #endif #ifndef NI_MAXSERV # define NI_MAXSERV 32 #endif /* !NI_MAXSERV */ #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif /* !NI_MAXHOST */ #ifndef INT_MAX #define INT_MAX 0xffffffff #endif #ifndef EAI_NODATA # define EAI_NODATA (INT_MAX - 1) #endif #ifndef EAI_MEMORY # define EAI_MEMORY (INT_MAX - 2) #endif #ifndef EAI_NONAME # define EAI_NONAME (INT_MAX - 3) #endif #ifndef EAI_SYSTEM # define EAI_SYSTEM (INT_MAX - 4) #endif #ifndef HAVE_STRUCT_ADDRINFO struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif /* !HAVE_STRUCT_ADDRINFO */ #ifndef HAVE_GETADDRINFO #ifdef getaddrinfo # undef getaddrinfo #endif #define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d)) int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); #endif /* !HAVE_GETADDRINFO */ #if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO) #define gai_strerror(a) (ssh_gai_strerror(a)) char *gai_strerror(int); #endif /* !HAVE_GAI_STRERROR */ #ifndef HAVE_FREEADDRINFO #define freeaddrinfo(a) (ssh_freeaddrinfo(a)) void freeaddrinfo(struct addrinfo *); #endif /* !HAVE_FREEADDRINFO */ #ifndef HAVE_GETNAMEINFO #define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g)) int getnameinfo(const struct sockaddr *, size_t, char *, size_t, char *, size_t, int); #endif /* !HAVE_GETNAMEINFO */ #endif /* !FAKE_RFC2553_H */ nsd-4.12.0/compat/fake-rfc2553.c0000644000175000017500000001373315002373054015430 0ustar mozziemozzie/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */ /* * Copyright (C) 2000-2003 Damien Miller. All rights reserved. * Copyright (C) 1999 WIDE Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Pseudo-implementation of RFC2553 name / address resolution functions * * But these functions are not implemented correctly. The minimum subset * is implemented for ssh use only. For example, this routine assumes * that ai_family is AF_INET. Don't use it for another purpose. */ #include #include #include #include #include "compat/fake-rfc2553.h" #ifndef HAVE_GETNAMEINFO int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host, size_t hostlen, char *serv, size_t servlen, int flags) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; struct hostent *hp; char tmpserv[16]; if (serv != NULL) { snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); if (strlcpy(serv, tmpserv, servlen) >= servlen) return (EAI_MEMORY); } if (host != NULL) { if (flags & NI_NUMERICHOST) { if (strlcpy(host, inet_ntoa(sin->sin_addr), hostlen) >= hostlen) return (EAI_MEMORY); else return (0); } else { hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); if (hp == NULL) return (EAI_NODATA); if (strlcpy(host, hp->h_name, hostlen) >= hostlen) return (EAI_MEMORY); else return (0); } } return (0); } #endif /* !HAVE_GETNAMEINFO */ #ifndef HAVE_GAI_STRERROR #ifdef HAVE_CONST_GAI_STRERROR_PROTO const char * #else char * #endif gai_strerror(int err) { switch (err) { case EAI_NODATA: return ("no address associated with name"); case EAI_MEMORY: return ("memory allocation failure."); case EAI_NONAME: return ("nodename nor servname provided, or not known"); default: return ("unknown/invalid error."); } } #endif /* !HAVE_GAI_STRERROR */ #ifndef HAVE_FREEADDRINFO void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next; for(; ai != NULL;) { next = ai->ai_next; free(ai); ai = next; } } #endif /* !HAVE_FREEADDRINFO */ #ifndef HAVE_GETADDRINFO static struct addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints) { struct addrinfo *ai; ai = calloc(1, sizeof(*ai) + sizeof(struct sockaddr_in)); if (ai == NULL) return (NULL); ai->ai_addr = (struct sockaddr *)(ai + 1); /* XXX -- ssh doesn't use sa_len */ ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr->sa_family = ai->ai_family = AF_INET; ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; /* XXX: the following is not generally correct, but does what we want */ if (hints->ai_socktype) ai->ai_socktype = hints->ai_socktype; else ai->ai_socktype = SOCK_STREAM; if (hints->ai_protocol) ai->ai_protocol = hints->ai_protocol; return (ai); } int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *hp; struct servent *sp; struct in_addr in; int i; long int port; u_long addr; port = 0; if (servname != NULL) { char *cp; port = strtol(servname, &cp, 10); if (port > 0 && port <= 65535 && *cp == '\0') port = htons(port); else if ((sp = getservbyname(servname, NULL)) != NULL) port = sp->s_port; else port = 0; } if (hints && hints->ai_flags & AI_PASSIVE) { addr = htonl(0x00000000); if (hostname && inet_aton(hostname, &in) != 0) addr = in.s_addr; *res = malloc_ai(port, addr, hints); if (*res == NULL) return (EAI_MEMORY); return (0); } if (!hostname) { *res = malloc_ai(port, htonl(0x7f000001), hints); if (*res == NULL) return (EAI_MEMORY); return (0); } if (inet_aton(hostname, &in)) { *res = malloc_ai(port, in.s_addr, hints); if (*res == NULL) return (EAI_MEMORY); return (0); } /* Don't try DNS if AI_NUMERICHOST is set */ if (hints && hints->ai_flags & AI_NUMERICHOST) return (EAI_NONAME); hp = gethostbyname(hostname); if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { struct addrinfo *cur, *prev; cur = prev = *res = NULL; for (i = 0; hp->h_addr_list[i]; i++) { struct in_addr *in = (struct in_addr *)hp->h_addr_list[i]; cur = malloc_ai(port, in->s_addr, hints); if (cur == NULL) { if (*res != NULL) freeaddrinfo(*res); return (EAI_MEMORY); } if (prev) prev->ai_next = cur; else *res = cur; prev = cur; } return (0); } return (EAI_NODATA); } #endif /* !HAVE_GETADDRINFO */ nsd-4.12.0/compat/explicit_bzero.c0000644000175000017500000000064115002373054016447 0ustar mozziemozzie/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */ /* * Public domain. * Written by Matthew Dempsky. */ #include "config.h" #include #ifdef HAVE_ATTR_WEAK __attribute__((weak)) void #else void #endif __explicit_bzero_hook(void *ATTR_UNUSED(buf), size_t ATTR_UNUSED(len)) { } void explicit_bzero(void *buf, size_t len) { memset(buf, 0, len); __explicit_bzero_hook(buf, len); } nsd-4.12.0/compat/cpuset.h0000644000175000017500000000327615002373054014744 0ustar mozziemozzie/* * cpuset.h -- CPU affinity. * * Copyright (c) 2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef CPUSET_H #define CPUSET_H #ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SYS_CPUSET_H # include #endif /* * CPU affinity is currently only supported on Linux and FreeBSD. Other * operating systems may be supported in the future, but not all operating * systems offer the same functionality. OpenBSD for example does not support * any kind of CPU affinity, while Solaris offers specifying a set of * processors, but a processor can only be part of a single set. * * NOTE: On macOS Mojave, processor_set_create returned KERN_FAILURE which * indicates processor allocation is not supported by the operating * system. */ #ifndef HAVE_CPUSET_T #ifdef HAVE_CPU_SET_T #define HAVE_CPUSET_T 1 typedef cpu_set_t cpuset_t; #endif #endif #ifndef HAVE_CPUID_T #ifdef __linux__ typedef int cpuid_t; #elif defined(__FreeBSD__) || defined(__gnu_hurd__) || defined(__DragonFly__) typedef size_t cpuid_t; #else typedef size_t cpuid_t; #endif #endif #ifndef HAVE_CPUSET_CREATE cpuset_t *cpuset_create(void); #endif #ifndef HAVE_CPUSET_DESTROY void cpuset_destroy(cpuset_t *set); #endif #ifndef HAVE_CPUSET_ZERO void cpuset_zero(cpuset_t *set); #endif #ifndef HAVE_CPUSET_SET int cpuset_set(cpuid_t cpu, cpuset_t *set); #endif #ifndef HAVE_CPUSET_CLR int cpuset_clr(cpuid_t cpu, cpuset_t *set); #endif #ifndef HAVE_CPUSET_ISSET int cpuset_isset(cpuid_t cpu, const cpuset_t *set); #endif #ifndef HAVE_CPUSET_SIZE size_t cpuset_size(const cpuset_t *set); #endif void cpuset_or(cpuset_t *destset, const cpuset_t *srcset); #endif /* CPUSET_H */ nsd-4.12.0/compat/cpuset.c0000644000175000017500000000265415002373054014736 0ustar mozziemozzie/* * cpuset.c -- CPU affinity. * * Copyright (c) 2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include "cpuset.h" #include #include #include #ifndef HAVE_CPUSET_CREATE cpuset_t *cpuset_create(void) { cpuset_t *set = calloc(1, sizeof(*set)); return set; } #endif /* !HAVE_CPUSET_CREATE */ #ifndef HAVE_CPUSET_DESTROY void cpuset_destroy(cpuset_t *set) { free(set); } #endif /* !HAVE_CPUSET_DESTROY */ #ifndef HAVE_CPUSET_ZERO void cpuset_zero(cpuset_t *set) { CPU_ZERO(set); } #endif /* !HAVE_CPUSET_ZERO */ #ifndef HAVE_CPUSET_SET int cpuset_set(cpuid_t cpu, cpuset_t *set) { CPU_SET(cpu, set); return 0; } #endif /* !HAVE_CPUSET_SET */ #ifndef HAVE_CPUSET_CLR int cpuset_clr(cpuid_t cpu, cpuset_t *set) { CPU_CLR(cpu, set); return 0; } #endif /* !HAVE_CPUSET_CLR */ #ifndef HAVE_CPUSET_ISSET int cpuset_isset(cpuid_t cpu, const cpuset_t *set) { return CPU_ISSET(cpu, set); } #endif /* !HAVE_CPUSET_ISSET */ #ifndef HAVE_CPUSET_SIZE size_t cpuset_size(const cpuset_t *set) { return sizeof(*set); } #endif /* !HAVE_CPUSET_SIZE */ #ifdef CPU_OR_THREE_ARGS /* for Linux, use three arguments */ void cpuset_or(cpuset_t *destset, const cpuset_t *srcset) { CPU_OR(destset, destset, srcset); } #else /* for FreeBSD, use two arguments */ void cpuset_or(cpuset_t *destset, const cpuset_t *srcset) { CPU_OR(destset, srcset); } #endif nsd-4.12.0/compat/basename.c0000644000175000017500000000044215002373054015177 0ustar mozziemozzie/* Return the basename of a pathname. This file is in the public domain. */ char * basename (name) const char *name; { const char *base; for (base = name; *name; name++) { if (*name == '/') { base = name + 1; } } return (char *) base; } nsd-4.12.0/compat/b64_pton.c0000644000175000017500000002637515002373054015074 0ustar mozziemozzie/* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include #include #include #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static int b64rmap_initialized = 0; static uint8_t b64rmap[256]; static const uint8_t b64rmap_special = 0xf0; static const uint8_t b64rmap_end = 0xfd; static const uint8_t b64rmap_space = 0xfe; static const uint8_t b64rmap_invalid = 0xff; /** * Initializing the reverse map is not thread safe. * Which is fine for NSD. For now... **/ static void b64_initialize_rmap () { int i; /* Null: end of string, stop parsing */ b64rmap[0] = b64rmap_end; for (i = 1; i < 256; ++i) { /* Whitespaces */ if (isspace(i)) b64rmap[i] = b64rmap_space; /* Padding: stop parsing */ else if (i == (unsigned char)Pad64) b64rmap[i] = b64rmap_end; /* Non-base64 char */ else b64rmap[i] = b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) b64rmap[(uint8_t)Base64[i]] = i; b64rmap_initialized = 1; } static int b64_pton_do(unsigned char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = ofs << 2; state = 1; break; case 1: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex+1] = (ofs & 0x0f) << 4 ; tarindex++; state = 2; break; case 2: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex+1] = (ofs & 0x03) << 6; tarindex++; state = 3; break; case 3: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int b64_pton_len(unsigned char const *src) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int b64_pton(char const *src, uint8_t *target, size_t targsize) { if (!b64rmap_initialized) b64_initialize_rmap (); if (target) return b64_pton_do ((unsigned char const*)src, target, targsize); else return b64_pton_len ((unsigned char const*)src); } nsd-4.12.0/compat/b64_ntop.c0000644000175000017500000001641615002373054015067 0ustar mozziemozzie/* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include #include #include #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); Assert(output[3] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } nsd-4.12.0/buffer.h0000644000175000017500000002722415002373054013426 0ustar mozziemozzie/* * buffer.h -- generic memory buffer. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The buffer module implements a generic buffer. The API is based on * the java.nio.Buffer interface. */ #ifndef BUFFER_H #define BUFFER_H #include #include #include #include "region-allocator.h" #include "util.h" typedef struct buffer buffer_type; struct buffer { /* * The current position used for reading/writing. */ size_t _position; /* * The read/write limit. */ size_t _limit; /* * The amount of data the buffer can contain. */ size_t _capacity; /* * The data contained in the buffer. */ uint8_t *_data; /* * If the buffer is fixed it cannot be resized. */ unsigned _fixed : 1; }; #ifdef NDEBUG static inline void buffer_invariant(buffer_type *ATTR_UNUSED(buffer)) { } #else static inline void buffer_invariant(buffer_type *buffer) { assert(buffer); assert(buffer->_position <= buffer->_limit); assert(buffer->_limit <= buffer->_capacity); assert(buffer->_data); } #endif /* * Create a new buffer with the specified capacity. */ buffer_type *buffer_create(region_type *region, size_t capacity); /* * Create a buffer with the specified data. The data is not copied * and no memory allocations are done. The buffer is fixed and cannot * be resized using buffer_reserve(). */ void buffer_create_from(buffer_type *buffer, const void *data, size_t size); /* * Clear the buffer and make it ready for writing. The buffer's limit * is set to the capacity and the position is set to 0. */ void buffer_clear(buffer_type *buffer); /* * Make the buffer ready for reading the data that has been written to * the buffer. The buffer's limit is set to the current position and * the position is set to 0. */ void buffer_flip(buffer_type *buffer); /* * Make the buffer ready for re-reading the data. The buffer's * position is reset to 0. */ void buffer_rewind(buffer_type *buffer); static inline size_t buffer_position(buffer_type *buffer) { return buffer->_position; } /* * Set the buffer's position to MARK. The position must be less than * or equal to the buffer's limit. */ static inline void buffer_set_position(buffer_type *buffer, size_t mark) { assert(mark <= buffer->_limit); buffer->_position = mark; } /* * Change the buffer's position by COUNT bytes. The position must not * be moved behind the buffer's limit or before the beginning of the * buffer. */ static inline void buffer_skip(buffer_type *buffer, ssize_t count) { assert(buffer->_position + count <= buffer->_limit); buffer->_position += count; } static inline size_t buffer_limit(buffer_type *buffer) { return buffer->_limit; } /* * Change the buffer's limit. If the buffer's position is greater * than the new limit the position is set to the limit. */ static inline void buffer_set_limit(buffer_type *buffer, size_t limit) { assert(limit <= buffer->_capacity); buffer->_limit = limit; if (buffer->_position > buffer->_limit) buffer->_position = buffer->_limit; } static inline size_t buffer_capacity(buffer_type *buffer) { return buffer->_capacity; } /* * Change the buffer's capacity. The data is reallocated so any * pointers to the data may become invalid. The buffer's limit is set * to the buffer's new capacity. */ void buffer_set_capacity(buffer_type *buffer, size_t capacity); /* * Ensure BUFFER can contain at least AMOUNT more bytes. The buffer's * capacity is increased if necessary using buffer_set_capacity(). * * The buffer's limit is always set to the (possibly increased) * capacity. */ void buffer_reserve(buffer_type *buffer, size_t amount); /* * Return a pointer to the data at the indicated position. */ static inline uint8_t * buffer_at(buffer_type *buffer, size_t at) { assert(at <= buffer->_limit); return buffer->_data + at; } /* * Return a pointer to the beginning of the buffer (the data at * position 0). */ static inline uint8_t * buffer_begin(buffer_type *buffer) { return buffer_at(buffer, 0); } /* * Return a pointer to the end of the buffer (the data at the buffer's * limit). */ static inline uint8_t * buffer_end(buffer_type *buffer) { return buffer_at(buffer, buffer->_limit); } /* * Return a pointer to the data at the buffer's current position. */ static inline uint8_t * buffer_current(buffer_type *buffer) { return buffer_at(buffer, buffer->_position); } /* * The number of bytes remaining between the indicated position and * the limit. */ static inline size_t buffer_remaining_at(buffer_type *buffer, size_t at) { buffer_invariant(buffer); assert(at <= buffer->_limit); return buffer->_limit - at; } /* * The number of bytes remaining between the buffer's position and * limit. */ static inline size_t buffer_remaining(buffer_type *buffer) { return buffer_remaining_at(buffer, buffer->_position); } /* * Check if the buffer has at least COUNT more bytes available. * Before reading or writing the caller needs to ensure enough space * is available! */ static inline int buffer_available_at(buffer_type *buffer, size_t at, size_t count) { return count <= buffer_remaining_at(buffer, at); } static inline int buffer_available(buffer_type *buffer, size_t count) { return buffer_available_at(buffer, buffer->_position, count); } static inline void buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) { assert(buffer_available_at(buffer, at, count)); memcpy(buffer->_data + at, data, count); } static inline void buffer_write(buffer_type *buffer, const void *data, size_t count) { buffer_write_at(buffer, buffer->_position, data, count); buffer->_position += count; } static inline int try_buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) { if(!buffer_available_at(buffer, at, count)) return 0; memcpy(buffer->_data + at, data, count); return 1; } static inline int try_buffer_write(buffer_type *buffer, const void *data, size_t count) { if(!try_buffer_write_at(buffer, buffer->_position, data, count)) return 0; buffer->_position += count; return 1; } static inline void buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) { buffer_write_at(buffer, at, str, strlen(str)); } static inline void buffer_write_string(buffer_type *buffer, const char *str) { buffer_write(buffer, str, strlen(str)); } static inline int try_buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) { return try_buffer_write_at(buffer, at, str, strlen(str)); } static inline int try_buffer_write_string(buffer_type *buffer, const char *str) { return try_buffer_write(buffer, str, strlen(str)); } static inline void buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); buffer->_data[at] = data; } static inline void buffer_write_u8(buffer_type *buffer, uint8_t data) { buffer_write_u8_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint16(buffer->_data + at, data); } static inline void buffer_write_u16(buffer_type *buffer, uint16_t data) { buffer_write_u16_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint32(buffer->_data + at, data); } static inline void buffer_write_u32(buffer_type *buffer, uint32_t data) { buffer_write_u32_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint64(buffer->_data + at, data); } static inline void buffer_write_u64(buffer_type *buffer, uint64_t data) { buffer_write_u64_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline int try_buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) { if(!buffer_available_at(buffer, at, sizeof(data))) return 0; buffer->_data[at] = data; return 1; } static inline int try_buffer_write_u8(buffer_type *buffer, uint8_t data) { if(!try_buffer_write_u8_at(buffer, buffer->_position, data)) return 0; buffer->_position += sizeof(data); return 1; } static inline int try_buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) { if(!buffer_available_at(buffer, at, sizeof(data))) return 0; write_uint16(buffer->_data + at, data); return 1; } static inline int try_buffer_write_u16(buffer_type *buffer, uint16_t data) { if(!try_buffer_write_u16_at(buffer, buffer->_position, data)) return 0; buffer->_position += sizeof(data); return 1; } static inline int try_buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) { if(!buffer_available_at(buffer, at, sizeof(data))) return 0; write_uint32(buffer->_data + at, data); return 1; } static inline int try_buffer_write_u32(buffer_type *buffer, uint32_t data) { if(!try_buffer_write_u32_at(buffer, buffer->_position, data)) return 0; buffer->_position += sizeof(data); return 1; } static inline int try_buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) { if(!buffer_available_at(buffer, at, sizeof(data))) return 0; write_uint64(buffer->_data + at, data); return 1; } static inline int try_buffer_write_u64(buffer_type *buffer, uint64_t data) { if(!try_buffer_write_u64_at(buffer, buffer->_position, data)) return 0; buffer->_position += sizeof(data); return 1; } static inline void buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) { assert(buffer_available_at(buffer, at, count)); memcpy(data, buffer->_data + at, count); } static inline void buffer_read(buffer_type *buffer, void *data, size_t count) { buffer_read_at(buffer, buffer->_position, data, count); buffer->_position += count; } static inline uint8_t buffer_read_u8_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint8_t))); return buffer->_data[at]; } static inline uint8_t buffer_read_u8(buffer_type *buffer) { uint8_t result = buffer_read_u8_at(buffer, buffer->_position); buffer->_position += sizeof(uint8_t); return result; } static inline uint16_t buffer_read_u16_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint16_t))); return read_uint16(buffer->_data + at); } static inline uint16_t buffer_read_u16(buffer_type *buffer) { uint16_t result = buffer_read_u16_at(buffer, buffer->_position); buffer->_position += sizeof(uint16_t); return result; } static inline uint32_t buffer_read_u32_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint32_t))); return read_uint32(buffer->_data + at); } static inline uint32_t buffer_read_u32(buffer_type *buffer) { uint32_t result = buffer_read_u32_at(buffer, buffer->_position); buffer->_position += sizeof(uint32_t); return result; } static inline uint64_t buffer_read_u64_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint64_t))); return read_uint64(buffer->_data + at); } static inline uint64_t buffer_read_u64(buffer_type *buffer) { uint64_t result = buffer_read_u64_at(buffer, buffer->_position); buffer->_position += sizeof(uint64_t); return result; } /* * Print to the buffer, increasing the capacity if required using * buffer_reserve(). The buffer's position is set to the terminating * '\0'. Returns the number of characters written (not including the * terminating '\0'). */ int buffer_printf(buffer_type *buffer, const char *format, ...) ATTR_FORMAT(printf, 2, 3); #endif /* BUFFER_H */ nsd-4.12.0/buffer.c0000644000175000017500000000523115002373054013413 0ustar mozziemozzie/* * buffer.c -- generic memory buffer . * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "buffer.h" static void buffer_cleanup(void *arg) { buffer_type *buffer = (buffer_type *) arg; assert(!buffer->_fixed); free(buffer->_data); } buffer_type * buffer_create(region_type *region, size_t capacity) { buffer_type *buffer = (buffer_type *) region_alloc(region, sizeof(buffer_type)); if (!buffer) return NULL; buffer->_data = (uint8_t *) xalloc(capacity); buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; buffer_invariant(buffer); region_add_cleanup(region, buffer_cleanup, buffer); return buffer; } void buffer_create_from(buffer_type *buffer, const void *data, size_t size) { assert(data); buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_data = (uint8_t *) data; buffer->_fixed = 1; buffer_invariant(buffer); } void buffer_clear(buffer_type *buffer) { buffer_invariant(buffer); buffer->_position = 0; buffer->_limit = buffer->_capacity; } void buffer_flip(buffer_type *buffer) { buffer_invariant(buffer); buffer->_limit = buffer->_position; buffer->_position = 0; } void buffer_rewind(buffer_type *buffer) { buffer_invariant(buffer); buffer->_position = 0; } void buffer_set_capacity(buffer_type *buffer, size_t capacity) { buffer_invariant(buffer); assert(buffer->_position <= capacity); buffer->_data = (uint8_t *) xrealloc(buffer->_data, capacity); buffer->_limit = buffer->_capacity = capacity; } void buffer_reserve(buffer_type *buffer, size_t amount) { buffer_invariant(buffer); assert(!buffer->_fixed); if (buffer->_capacity < buffer->_position + amount) { size_t new_capacity = buffer->_capacity * 3 / 2; if (new_capacity < buffer->_position + amount) { new_capacity = buffer->_position + amount; } buffer_set_capacity(buffer, new_capacity); } buffer->_limit = buffer->_capacity; } int buffer_printf(buffer_type *buffer, const char *format, ...) { va_list args; int written; size_t remaining; buffer_invariant(buffer); assert(buffer->_limit == buffer->_capacity); remaining = buffer_remaining(buffer); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), remaining, format, args); va_end(args); if (written >= 0 && (size_t) written >= remaining) { buffer_reserve(buffer, written + 1); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), buffer_remaining(buffer), format, args); va_end(args); } buffer->_position += written; return written; } nsd-4.12.0/bitset.h0000644000175000017500000000151215002373054013437 0ustar mozziemozzie/* * bitset.h -- Dynamic bitset. * * Copyright (c) 2001-2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef BITSET_H #define BITSET_H #include #include #include typedef struct nsd_bitset nsd_bitset_type; struct nsd_bitset { size_t size; /** Number of available bits in the set */ unsigned char bits[]; }; size_t nsd_bitset_size(size_t bits); void nsd_bitset_zero(struct nsd_bitset *bset); void nsd_bitset_init(struct nsd_bitset *bset, size_t bits); int nsd_bitset_isset(struct nsd_bitset *bset, size_t bit); void nsd_bitset_set(struct nsd_bitset *bset, size_t bit); void nsd_bitset_unset(struct nsd_bitset *bset, size_t bit); void nsd_bitset_or( struct nsd_bitset *destset, struct nsd_bitset *srcset1, struct nsd_bitset *srcset2); #endif /* BITSET_H */ nsd-4.12.0/bitset.c0000644000175000017500000000420615002373054013435 0ustar mozziemozzie/* * bitset.h -- Dynamic bitset. * * Copyright (c) 2001-2020, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include "bitset.h" #include #include #include size_t nsd_bitset_size(size_t bits) { if(bits == 0) bits++; return (bits / CHAR_BIT) + ((bits % CHAR_BIT) != 0) + sizeof(size_t); } void nsd_bitset_zero(struct nsd_bitset *bset) { size_t sz; assert(bset != NULL); sz = nsd_bitset_size(bset->size) - sizeof(bset->size); assert(sz > 0); memset(bset->bits, 0, sz); } void nsd_bitset_init(struct nsd_bitset *bset, size_t bits) { assert(bset != NULL); if (bits == 0) bits++; bset->size = bits; nsd_bitset_zero(bset); } int nsd_bitset_isset(struct nsd_bitset *bset, size_t bit) { assert(bset != NULL); if(bit >= bset->size) return 0; return (bset->bits[ (bit / CHAR_BIT) ] & (1 << (bit % CHAR_BIT))) != 0; } void nsd_bitset_set(struct nsd_bitset *bset, size_t bit) { assert(bset != NULL); assert(bset->size > bit); bset->bits[ (bit / CHAR_BIT) ] |= (1 << (bit % CHAR_BIT)); } void nsd_bitset_unset(struct nsd_bitset *bset, size_t bit) { assert(bset != NULL); assert(bset->size > bit); bset->bits[ (bit / CHAR_BIT) ] &= ~(1 << (bit % CHAR_BIT)); } void nsd_bitset_or( struct nsd_bitset *destset, struct nsd_bitset *srcset1, struct nsd_bitset *srcset2) { size_t i, n, size, bytes; unsigned char bits; unsigned int mask; assert(destset != NULL); assert(srcset1 != NULL); assert(srcset2 != NULL); size = destset->size; bytes = (size / CHAR_BIT) + ((size % CHAR_BIT) != 0); for(i = 0; i < bytes; i++) { bits = 0; n = (srcset1->size / CHAR_BIT); if (n > i) { bits |= srcset1->bits[i]; } else { n += ((srcset1->size % CHAR_BIT) != 0); mask = (1 << ((srcset1->size % CHAR_BIT) + 1)) - 1; if (n > i) { bits |= (srcset1->bits[i] & mask); } } n = (srcset2->size / CHAR_BIT); if (n > i) { bits |= srcset2->bits[i]; } else { n += ((srcset2->size % CHAR_BIT) != 0); mask = (1 << ((srcset2->size % CHAR_BIT) + 1)) - 1; if (n > i) { bits |= (srcset2->bits[i] & mask); } } destset->bits[i] = bits; } } nsd-4.12.0/axfr.h0000644000175000017500000000104215002373054013103 0ustar mozziemozzie/* * axfr.h -- generating AXFR responses. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef AXFR_H #define AXFR_H #include "nsd.h" #include "query.h" /* * For optimal compression AXFR response packets are limited in size * to MAX_COMPRESSION_OFFSET. */ #define AXFR_MAX_MESSAGE_LEN MAX_COMPRESSION_OFFSET query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q); query_state_type query_axfr(struct nsd *nsd, struct query *query, int wstats); #endif /* AXFR_H */ nsd-4.12.0/axfr.c0000644000175000017500000002161215002373054013103 0ustar mozziemozzie/* * axfr.c -- generating AXFR responses. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include "axfr.h" #include "dns.h" #include "packet.h" #include "options.h" #include "ixfr.h" /* draft-ietf-dnsop-rfc2845bis-06, section 5.3.1 says to sign every packet */ #define AXFR_TSIG_SIGN_EVERY_NTH 0 /* tsig sign every N packets. */ query_state_type query_axfr(struct nsd *nsd, struct query *query, int wstats) { domain_type *closest_match; domain_type *closest_encloser; int exact; int added; uint16_t total_added = 0; if (query->axfr_is_done) return QUERY_PROCESSED; if (query->maxlen > AXFR_MAX_MESSAGE_LEN) query->maxlen = AXFR_MAX_MESSAGE_LEN; assert(!query_overflow(query)); /* only keep running values for most packets */ query->tsig_prepare_it = 0; query->tsig_update_it = 1; if(query->tsig_sign_it) { /* prepare for next updates */ query->tsig_prepare_it = 1; query->tsig_sign_it = 0; } if (query->axfr_zone == NULL) { domain_type* qdomain; /* Start AXFR. */ if(wstats) { STATUP(nsd, raxfr); } exact = namedb_lookup(nsd->db, query->qname, &closest_match, &closest_encloser); qdomain = closest_encloser; query->axfr_zone = domain_find_zone(nsd->db, closest_encloser); if (!exact || query->axfr_zone == NULL || query->axfr_zone->apex != qdomain || query->axfr_zone->soa_rrset == NULL) { /* No SOA no transfer */ RCODE_SET(query->packet, RCODE_NOTAUTH); return QUERY_PROCESSED; } if(wstats) { ZTATUP(nsd, query->axfr_zone, raxfr); } query->axfr_current_domain = qdomain; query->axfr_current_rrset = NULL; query->axfr_current_rr = 0; if(query->tsig.status == TSIG_OK) { query->tsig_sign_it = 1; /* sign first packet in stream */ } query_add_compression_domain(query, qdomain, QHEADERSZ); assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (!added) { /* XXX: This should never happen... generate error code? */ abort(); } ++total_added; } else { /* * Query name and EDNS need not be repeated after the * first response packet. */ query->edns.status = EDNS_NOT_PRESENT; buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); query_prepare_response(query); } /* Add zone RRs until answer is full. */ while (query->axfr_current_domain != NULL && domain_is_subdomain(query->axfr_current_domain, query->axfr_zone->apex)) { if (!query->axfr_current_rrset) { query->axfr_current_rrset = domain_find_any_rrset( query->axfr_current_domain, query->axfr_zone); query->axfr_current_rr = 0; } while (query->axfr_current_rrset) { if (query->axfr_current_rrset != query->axfr_zone->soa_rrset && query->axfr_current_rrset->zone == query->axfr_zone) { while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { size_t oldmaxlen = query->maxlen; if(total_added == 0) /* RR > 16K can be first RR */ query->maxlen = (query->tcp?TCP_MAX_MESSAGE_LEN:UDP_MAX_MESSAGE_LEN); added = packet_encode_rr( query, query->axfr_current_domain, &query->axfr_current_rrset->rrs[query->axfr_current_rr], query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); if(total_added == 0) { query->maxlen = oldmaxlen; if(query_overflow(query)) { if(added) { ++total_added; ++query->axfr_current_rr; goto return_answer; } } } if (!added) goto return_answer; ++total_added; ++query->axfr_current_rr; } } query->axfr_current_rrset = query->axfr_current_rrset->next; query->axfr_current_rr = 0; } assert(query->axfr_current_domain); query->axfr_current_domain = domain_next(query->axfr_current_domain); } /* Add terminating SOA RR. */ assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (added) { ++total_added; query->tsig_sign_it = 1; /* sign last packet */ query->axfr_is_done = 1; } return_answer: AA_SET(query->packet); ANCOUNT_SET(query->packet, total_added); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); /* check if it needs tsig signatures */ if(query->tsig.status == TSIG_OK) { #if AXFR_TSIG_SIGN_EVERY_NTH > 0 if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { #endif query->tsig_sign_it = 1; #if AXFR_TSIG_SIGN_EVERY_NTH > 0 } #endif } query_clear_compression_tables(query); return QUERY_IN_AXFR; } /* See if the query can be admitted. */ static int axfr_ixfr_can_admit_query(struct nsd* nsd, struct query* q) { struct acl_options *acl = NULL; struct zone_options* zone_opt; #ifdef HAVE_SSL /* tls-auth-xfr-only is set and this is not an authenticated TLS */ if (nsd->options->tls_auth_xfr_only && !q->tls_auth) { if (verbosity >= 2) { char address[128], proxy[128]; addr2str(&q->client_addr, address, sizeof(address)); addr2str(&q->remote_addr, proxy, sizeof(proxy)); VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused tls-auth-xfr-only", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), address)); } RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; return 0; } #endif zone_opt = zone_options_find(nsd->options, q->qname); if(zone_opt && q->is_proxied && acl_check_incoming_block_proxy( zone_opt->pattern->provide_xfr, q, &acl) == -1) { /* the proxy address is blocked */ if (verbosity >= 2) { char address[128], proxy[128]; addr2str(&q->client_addr, address, sizeof(address)); addr2str(&q->remote_addr, proxy, sizeof(proxy)); VERBOSITY(2, (LOG_INFO, "%s for %s from %s via proxy %s refused because of proxy, %s %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), address, proxy, (acl?acl->ip_address_spec:"."), (acl ? ( acl->nokey ? "NOKEY" : acl->blocked ? "BLOCKED" : acl->key_name ) : "no acl matches"))); } RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; return 0; } if(!zone_opt || acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) { if (verbosity >= 2) { char a[128]; addr2str(&q->client_addr, a, sizeof(a)); VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused, %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s refused, %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), acl?"blocked":"no acl matches")); if (!zone_opt) { RCODE_SET(q->packet, RCODE_NOTAUTH); } else { RCODE_SET(q->packet, RCODE_REFUSE); /* RFC8914 - Extended DNS Errors * 4.19. Extended DNS Error Code 18 - Prohibited */ q->edns.ede = EDE_PROHIBITED; } return 0; } #ifdef HAVE_SSL DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s admitted acl %s %s %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY", (q->tls||q->tls_auth)?(q->tls?"tls":"tls-auth"):"")); #else DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s admitted acl %s %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); #endif if (verbosity >= 1) { char a[128]; addr2str(&q->client_addr, a, sizeof(a)); #ifdef HAVE_SSL VERBOSITY(1, (LOG_INFO, "%s for %s from %s %s %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a, (q->tls||q->tls_auth)?(q->tls?"tls":"tls-auth"):"", q->cert_cn?q->cert_cn:"not-verified")); #else VERBOSITY(1, (LOG_INFO, "%s for %s from %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a)); #endif } return 1; } /* * Answer if this is an AXFR or IXFR query. */ query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q) { /* Is it AXFR? */ switch (q->qtype) { case TYPE_AXFR: if (q->tcp) { if(!axfr_ixfr_can_admit_query(nsd, q)) return QUERY_PROCESSED; return query_axfr(nsd, q, 1); } /* AXFR over UDP queries are discarded. */ RCODE_SET(q->packet, RCODE_IMPL); return QUERY_PROCESSED; case TYPE_IXFR: if(!axfr_ixfr_can_admit_query(nsd, q)) { /* get rid of authority section, if present */ NSCOUNT_SET(q->packet, 0); ARCOUNT_SET(q->packet, 0); if(QDCOUNT(q->packet) > 0 && (size_t)QHEADERSZ+4+ q->qname->name_size <= buffer_limit(q->packet)) { buffer_set_position(q->packet, QHEADERSZ+4+ q->qname->name_size); } return QUERY_PROCESSED; } return query_ixfr(nsd, q); default: return QUERY_DISCARDED; } } nsd-4.12.0/answer.h0000644000175000017500000000175515002373054013455 0ustar mozziemozzie/* * answer.h -- manipulating query answers and encoding them. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef ANSWER_H #define ANSWER_H #include #include "dns.h" #include "namedb.h" #include "packet.h" #include "query.h" /* * Structure used to keep track of RRsets that need to be stored in * the answer packet. */ typedef struct answer answer_type; struct answer { size_t rrset_count; rrset_type *rrsets[MAXRRSPP]; domain_type *domains[MAXRRSPP]; rr_section_type section[MAXRRSPP]; }; void encode_answer(query_type *q, const answer_type *answer); void answer_init(answer_type *answer); /* * Add the specified RRset to the answer in the specified section. If * the RRset is already present and in the same (or "higher") section * return 0, otherwise return 1. */ int answer_add_rrset(answer_type *answer, rr_section_type section, domain_type *domain, rrset_type *rrset); #endif /* ANSWER_H */ nsd-4.12.0/answer.c0000644000175000017500000000513615002373054013445 0ustar mozziemozzie/* * answer.c -- manipulating query answers and encoding them. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include "answer.h" #include "packet.h" #include "query.h" void answer_init(answer_type *answer) { answer->rrset_count = 0; } int answer_add_rrset(answer_type *answer, rr_section_type section, domain_type *domain, rrset_type *rrset) { size_t i; assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT); assert(domain); assert(rrset); /* Don't add an RRset multiple times. */ for (i = 0; i < answer->rrset_count; ++i) { if (answer->rrsets[i] == rrset && answer->domains[i]->number == domain->number) { if (section < answer->section[i]) { answer->section[i] = section; return 1; } else { return 0; } } } if (answer->rrset_count >= MAXRRSPP) { /* XXX: Generate warning/error? */ return 0; } answer->section[answer->rrset_count] = section; answer->domains[answer->rrset_count] = domain; answer->rrsets[answer->rrset_count] = rrset; ++answer->rrset_count; return 1; } void encode_answer(query_type *q, const answer_type *answer) { uint16_t counts[RR_SECTION_COUNT]; rr_section_type section; size_t i; int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE; int done = 0; #if defined(INET6) && defined(MINIMAL_RESPONSES) if (q->client_addr.ss_family == AF_INET6) minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE; #endif for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) { counts[section] = 0; } for (section = ANSWER_SECTION; !TC(q->packet) && section < RR_SECTION_COUNT; ++section) { for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) { if (answer->section[i] == section) { counts[section] += packet_encode_rrset( q, answer->domains[i], answer->rrsets[i], section, minimal_respsize, &done); } } #ifdef MINIMAL_RESPONSES /** * done is set prematurely, because the minimal response size * has been reached. No need to try adding RRsets in following * sections. */ if (done) { /* delegations should have a usable address in it */ if(section == ADDITIONAL_A_SECTION && counts[ADDITIONAL_A_SECTION] == 0 && q->delegation_domain) TC_SET(q->packet); break; } #endif } ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]); NSCOUNT_SET(q->packet, counts[AUTHORITY_SECTION] + counts[OPTIONAL_AUTHORITY_SECTION]); ARCOUNT_SET(q->packet, counts[ADDITIONAL_A_SECTION] + counts[ADDITIONAL_AAAA_SECTION] + counts[ADDITIONAL_OTHER_SECTION]); } nsd-4.12.0/acx_nlnetlabs.m40000644000175000017500000013216315002373054015062 0ustar mozziemozzie# acx_nlnetlabs.m4 - common macros for configure checks # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # # Version 48 # 2024-01-16 fix to add -l:libssp.a to -lcrypto link check. # and check for getaddrinfo with only header. # 2024-01-15 fix to add crypt32 to -lcrypto link check when checking for gdi32. # 2023-05-04 fix to remove unused whitespace. # 2023-01-26 fix -Wstrict-prototypes. # 2022-09-01 fix checking if nonblocking sockets work on OpenBSD. # 2021-08-17 fix sed script in ssldir split handling. # 2021-08-17 fix for openssl to detect split version, with ssldir_include # and ssldir_lib output directories. # 2021-07-30 fix for openssl use of lib64 directory. # 2021-06-14 fix nonblocking test to use host instead of target for mingw test. # 2021-05-17 fix nonblocking socket test from grep on mingw32 to mingw for # 64bit compatibility. # 2021-03-24 fix ACX_FUNC_DEPRECATED to use CPPFLAGS and CFLAGS. # 2021-01-05 fix defun for aclocal # 2021-01-05 autoconf 2.70 autoupdate and fixes, no AC_TRY_COMPILE # 2020-08-24 Use EVP_sha256 instead of HMAC_Update (for openssl-3.0.0). # 2016-03-21 Check -ldl -pthread for libcrypto for ldns and openssl 1.1.0. # 2016-03-21 Use HMAC_Update instead of HMAC_CTX_Init (for openssl-1.1.0). # 2016-01-04 -D_DEFAULT_SOURCE defined with -D_BSD_SOURCE for Linux glibc 2.20 # 2015-12-11 FLTO check for new OSX, clang. # 2015-11-18 spelling check fix. # 2015-11-05 ACX_SSL_CHECKS no longer adds -ldl needlessly. # 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 # 2013-06-25 FLTO has --disable-flto option. # 2013-05-03 Update W32_SLEEP for newer mingw that links but not defines it. # 2013-03-22 Fix ACX_RSRC_VERSION for long version numbers. # 2012-02-09 Fix AHX_MEMCMP_BROKEN with undef in compat/memcmp.h. # 2012-01-20 Fix COMPILER_FLAGS_UNBOUND for gcc 4.6.2 assigned-not-used-warns. # 2011-12-05 Fix getaddrinfowithincludes on windows with fedora16 mingw32-gcc. # Fix ACX_MALLOC for redefined malloc error. # Fix GETADDRINFO_WITH_INCLUDES to add -lws2_32 # 2011-11-10 Fix FLTO test to not drop a.out in current directory. # 2011-11-01 Fix FLTO test for llvm on Lion. # 2011-08-01 Fix nonblock test (broken at v13). # 2011-08-01 Fix autoconf 2.68 warnings # 2011-06-23 Add ACX_CHECK_FLTO to check -flto. # 2010-08-16 Fix FLAG_OMITTED for AS_TR_CPP changes in autoconf-2.66. # 2010-07-02 Add check for ss_family (for minix). # 2010-04-26 Fix to use CPPFLAGS for CHECK_COMPILER_FLAGS. # 2010-03-01 Fix RPATH using CONFIG_COMMANDS to run at the very end. # 2010-02-18 WITH_SSL outputs the LIBSSL_LDFLAGS, LIBS, CPPFLAGS separate, -ldl # 2010-02-01 added ACX_CHECK_MEMCMP_SIGNED, AHX_MEMCMP_BROKEN # 2010-01-20 added AHX_COONFIG_STRLCAT # 2009-07-14 U_CHAR detection improved for windows crosscompile. # added ACX_FUNC_MALLOC # fixup some #if to #ifdef # NONBLOCKING test for mingw crosscompile. # 2009-07-13 added ACX_WITH_SSL_OPTIONAL # 2009-07-03 fixup LDFLAGS for empty ssl dir. # # Automates some of the checking constructs. Aims at portability for POSIX. # Documentation for functions is below. # # the following macro's are provided in this file: # (see below for details on each macro). # # ACX_ESCAPE_BACKSLASH - escape backslashes in var for C-preproc. # ACX_RSRC_VERSION - create windows resource version number. # ACX_CHECK_COMPILER_FLAG - see if cc supports a flag. # ACX_CHECK_ERROR_FLAGS - see which flag is -werror (used below). # ACX_CHECK_COMPILER_FLAG_NEEDED - see if flags make the code compile cleanly. # ACX_DEPFLAG - find cc dependency flags. # ACX_DETERMINE_EXT_FLAGS_UNBOUND - find out which flags enable BSD and POSIX. # ACX_CHECK_FORMAT_ATTRIBUTE - find cc printf format syntax. # ACX_CHECK_UNUSED_ATTRIBUTE - find cc variable unused syntax. # ACX_CHECK_FLTO - see if cc supports -flto and use it if so. # ACX_LIBTOOL_C_ONLY - create libtool for C only, improved. # ACX_TYPE_U_CHAR - u_char type. # ACX_TYPE_RLIM_T - rlim_t type. # ACX_TYPE_SOCKLEN_T - socklen_t type. # ACX_TYPE_IN_ADDR_T - in_addr_t type. # ACX_TYPE_IN_PORT_T - in_port_t type. # ACX_ARG_RPATH - add --disable-rpath option. # ACX_WITH_SSL - add --with-ssl option, link -lcrypto. # ACX_WITH_SSL_OPTIONAL - add --with-ssl option, link -lcrypto, # where --without-ssl is also accepted # ACX_LIB_SSL - setup to link -lssl. # ACX_SYS_LARGEFILE - improved sys_largefile, fseeko, >2G files. # ACX_CHECK_GETADDRINFO_WITH_INCLUDES - find getaddrinfo, portably. # ACX_FUNC_DEPRECATED - see if func is deprecated. # ACX_CHECK_NONBLOCKING_BROKEN - see if nonblocking sockets really work. # ACX_MKDIR_ONE_ARG - determine mkdir(2) number of arguments. # ACX_FUNC_IOCTLSOCKET - find ioctlsocket, portably. # ACX_FUNC_MALLOC - check malloc, define replacement . # AHX_CONFIG_FORMAT_ATTRIBUTE - config.h text for format. # AHX_CONFIG_UNUSED_ATTRIBUTE - config.h text for unused. # AHX_CONFIG_FSEEKO - define fseeko, ftello fallback. # AHX_CONFIG_RAND_MAX - define RAND_MAX if needed. # AHX_CONFIG_MAXHOSTNAMELEN - define MAXHOSTNAMELEN if needed. # AHX_CONFIG_IPV6_MIN_MTU - define IPV6_MIN_MTU if needed. # AHX_CONFIG_SNPRINTF - snprintf compat prototype # AHX_CONFIG_INET_PTON - inet_pton compat prototype # AHX_CONFIG_INET_NTOP - inet_ntop compat prototype # AHX_CONFIG_INET_ATON - inet_aton compat prototype # AHX_CONFIG_MEMMOVE - memmove compat prototype # AHX_CONFIG_STRLCAT - strlcat compat prototype # AHX_CONFIG_STRLCPY - strlcpy compat prototype # AHX_CONFIG_GMTIME_R - gmtime_r compat prototype # AHX_CONFIG_W32_SLEEP - w32 compat for sleep # AHX_CONFIG_W32_USLEEP - w32 compat for usleep # AHX_CONFIG_W32_RANDOM - w32 compat for random # AHX_CONFIG_W32_SRANDOM - w32 compat for srandom # AHX_CONFIG_W32_FD_SET_T - w32 detection of FD_SET_T. # ACX_CFLAGS_STRIP - strip one flag from CFLAGS # ACX_STRIP_EXT_FLAGS - strip extension flags from CFLAGS # AHX_CONFIG_FLAG_OMITTED - define omitted flag # AHX_CONFIG_FLAG_EXT - define omitted extension flag # AHX_CONFIG_EXT_FLAGS - define the stripped extension flags # 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. dnl for example, ACX_ESCAPE_BACKSLASH($from_var, to_var) dnl $1: the text to change. dnl $2: the result. AC_DEFUN([ACX_ESCAPE_BACKSLASH], [$2="`echo $1 | sed -e 's/\\\\/\\\\\\\\/g'`" ]) dnl Calculate comma separated windows-resource numbers from package version. dnl Picks the first three(,0) or four numbers out of the name. dnl $1: variable for the result AC_DEFUN([ACX_RSRC_VERSION], [$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9]*$/\1,\2,\3,0/' `] ]) dnl Routine to help check for compiler flags. dnl Checks if the compiler will accept the flag. dnl $1: the flag without a - in front, so g to check -g. dnl $2: executed if yes dnl $3: executed if no AC_DEFUN([ACX_CHECK_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c ]) if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $2 else AC_MSG_RESULT(no) : $3 fi ]) dnl setup flags for ACX_CHECK_COMPILER_FLAG_NEEDED dnl ERRFLAG: result, compiler flag to turn warnings into errors AC_DEFUN([ACX_CHECK_ERROR_FLAGS], [ ACX_CHECK_COMPILER_FLAG(Werror, [ERRFLAG="-Werror"], [ERRFLAG="-errwarn"]) ACX_CHECK_COMPILER_FLAG(Wall, [ERRFLAG="$ERRFLAG -Wall"], [ERRFLAG="$ERRFLAG -errfmt"]) ]) dnl Routine to help check for needed compiler flags. dnl $1: flags for CC dnl $2: the includes and code dnl $3: if the given code only compiles with the flag, execute argument 3 dnl $4: if the given code compiles without the flag, execute argument 4 dnl $5: with and without flag the compile fails, execute argument 5. AC_DEFUN([ACX_CHECK_COMPILER_FLAG_NEEDED], [ AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([ACX_CHECK_ERROR_FLAGS]) AC_MSG_CHECKING(whether we need $1 as a flag for $CC) cache=AS_TR_SH($1) dnl cache=`echo $1 | sed 'y%.=/+- %___p__%'` AC_CACHE_VAL(cv_prog_cc_flag_needed_$cache, [ echo '$2' > conftest.c echo 'void f(void){}' >>conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS $ERRFLAG -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_needed_$cache=no" else [ if test -z "`$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_needed_$cache=yes" else eval "cv_prog_cc_flag_needed_$cache=fail" #echo 'Test with flag fails too!' #cat conftest.c #echo "$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1" #echo `$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1` #exit 1 fi ] fi rm -f conftest conftest.c conftest.o ]) if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $3 else if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = no"; then AC_MSG_RESULT(no) #echo 'Test with flag is no!' #cat conftest.c #echo "$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1" #echo `$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1` #exit 1 : $4 else AC_MSG_RESULT(failed) : $5 fi fi ]) dnl Check for CC dependency flag dnl DEPFLAG: set to flag that generates dependencies. AC_DEFUN([ACX_DEPFLAG], [ AC_MSG_CHECKING([$CC dependency flag]) echo 'void f(void){}' >conftest.c if test "`$CC -MM conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-MM" else if test "`$CC -xM1 conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-xM1" else DEPFLAG="-MM" # dunno do something fi fi AC_MSG_RESULT($DEPFLAG) rm -f conftest.c AC_SUBST(DEPFLAG) ]) dnl Determine flags that gives POSIX and BSD functionality. dnl CFLAGS is modified for the result. AC_DEFUN([ACX_DETERMINE_EXT_FLAGS_UNBOUND], [ ACX_CHECK_COMPILER_FLAG(std=c99, [C99FLAG="-std=c99"]) ACX_CHECK_COMPILER_FLAG(xc99, [C99FLAG="-xc99"]) AC_CHECK_HEADERS([getopt.h time.h],,, [AC_INCLUDES_DEFAULT]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #include #ifdef HAVE_GETOPT_H #include #endif int test(void) { int a; char **opts = NULL; struct timeval tv; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; struct msghdr msg; msg.msg_control = 0; t = ctime_r(&time, buf); tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); str = gai_strerror(0); if(str && t && tv.tv_usec && msg.msg_control) a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #include #ifdef HAVE_GETOPT_H #include #endif int test(void) { int a; char **opts = NULL; struct timeval tv; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; struct msghdr msg; msg.msg_control = 0; t = ctime_r(&time, buf); tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); str = gai_strerror(0); if(str && t && tv.tv_usec && msg.msg_control) a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG, [ #include #include int test(void) { int a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_BSD_SOURCE -D_DEFAULT_SOURCE, [ #include int test(void) { int a; a = isascii(32); return a; } ], [CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE, [ #include int test(void) { struct in6_pktinfo inf; int a = (int)sizeof(inf); return a; } ], [CFLAGS="$CFLAGS -D_GNU_SOURCE"]) # check again for GNU_SOURCE for setresgid. May fail if setresgid # is not available at all. -D_FRSRESGID is to make this check unique. # otherwise we would get the previous cached result. ACX_CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE -D_FRSRESGID, [ #include int test(void) { int a = setresgid(0,0,0); a = setresuid(0,0,0); return a; } ], [CFLAGS="$CFLAGS -D_GNU_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_POSIX_C_SOURCE=200112, [ #include "confdefs.h" #ifdef HAVE_TIME_H #include #endif #include int test(void) { int a = 0; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; t = ctime_r(&time, buf); str = gai_strerror(0); if(t && str) a = 0; return a; } ], [CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D__EXTENSIONS__, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #ifdef HAVE_GETOPT_H #include #endif int test(void) { int a; char **opts = NULL; struct timeval tv; tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); if(tv.tv_usec) a = 0; return a; } ], [CFLAGS="$CFLAGS -D__EXTENSIONS__"]) ])dnl End of ACX_DETERMINE_EXT_FLAGS_UNBOUND dnl Check if CC supports -flto. dnl in a way that supports clang and suncc (that flag does something else, dnl but fails to link). It sets it in CFLAGS if it works. AC_DEFUN([ACX_CHECK_FLTO], [ AC_ARG_ENABLE([flto], AS_HELP_STRING([--disable-flto], [Disable link-time optimization (gcc specific option)])) AS_IF([test "x$enable_flto" != "xno"], [ AC_MSG_CHECKING([if $CC supports -flto]) BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -flto" AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ if $CC $CFLAGS -o conftest conftest.c 2>&1 | $GREP -e "warning: no debug symbols in executable" -e "warning: object" >/dev/null; then CFLAGS="$BAKCFLAGS" AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi rm -f conftest conftest.c conftest.o ], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) ]) ]) dnl Check the printf-format attribute (if any) dnl result in HAVE_ATTR_FORMAT. dnl Make sure you also include the AHX_CONFIG_FORMAT_ATTRIBUTE. AC_DEFUN([ACX_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute) AC_CACHE_VAL(ac_cv_c_format_attribute, [ac_cv_c_format_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); ]], [[ f ("%s", "str"); ]])],[ac_cv_c_format_attribute="yes"],[ac_cv_c_format_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_format_attribute) if test $ac_cv_c_format_attribute = yes; then AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute]) fi ])dnl End of ACX_CHECK_FORMAT_ATTRIBUTE dnl Setup ATTR_FORMAT config.h parts. dnl make sure you call ACX_CHECK_FORMAT_ATTRIBUTE also. AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE], [ #ifdef HAVE_ATTR_FORMAT # define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ # define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ ]) dnl Check how to mark function arguments as unused. dnl result in HAVE_ATTR_UNUSED. dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also. AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute) AC_CACHE_VAL(ac_cv_c_unused_attribute, [ac_cv_c_unused_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include void f (char *u __attribute__((unused))); ]], [[ f ("x"); ]])],[ac_cv_c_unused_attribute="yes"],[ac_cv_c_unused_attribute="no"]) ]) dnl Setup ATTR_UNUSED config.h parts. dnl make sure you call ACX_CHECK_UNUSED_ATTRIBUTE also. AC_DEFUN([AHX_CONFIG_UNUSED_ATTRIBUTE], [ #if defined(DOXYGEN) # define ATTR_UNUSED(x) x #elif defined(__cplusplus) # define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) # define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ ]) AC_MSG_RESULT($ac_cv_c_unused_attribute) if test $ac_cv_c_unused_attribute = yes; then AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) fi ])dnl dnl Pre-fun for ACX_LIBTOOL_C_ONLY AC_DEFUN([ACX_LIBTOOL_C_PRE], [ # skip these tests, we do not need them. AC_DEFUN([AC_PROG_F77], [:]) AC_DEFUN([AC_PROG_FC], [:]) AC_DEFUN([AC_PROG_CXX], [:]) AC_DEFUN([AC_PROG_CXXCPP], [:]) AC_DEFUN([AC_PROG_OBJC], [:]) AC_DEFUN([AC_PROG_OBJCCPP], [:]) AC_DEFUN([AC_LIBTOOL_CXX], [:]) AC_DEFUN([AC_LIBTOOL_F77], [:]) # always use ./libtool unless override from commandline (libtool=mylibtool) if test -z "$libtool"; then libtool="./libtool" fi AC_SUBST(libtool) # avoid libtool max commandline length test on systems that fork slowly. AC_CANONICAL_HOST if echo "$host_os" | grep "sunos4" >/dev/null; then lt_cv_sys_max_cmd_len=32750; fi AC_PATH_TOOL(AR, ar, [false]) if test $AR = false; then AC_MSG_ERROR([Cannot find 'ar', please extend PATH to include it]) fi ]) dnl Perform libtool check, portably, only for C AC_DEFUN([ACX_LIBTOOL_C_ONLY], [ dnl as a requirement so that is gets called before LIBTOOL dnl because libtools 'AC_REQUIRE' names are right after this one, before dnl this function contents. AC_REQUIRE([ACX_LIBTOOL_C_PRE]) LT_INIT ]) dnl Detect if u_char type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_U_CHAR], [AC_CHECK_TYPE([u_char], , [AC_DEFINE([u_char], [unsigned char], [Define to 'unsigned char if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_WINSOCK2_H # include #endif ]) ]) dnl Detect if rlim_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_RLIM_T], [AC_CHECK_TYPE(rlim_t, , [AC_DEFINE([rlim_t], [unsigned long], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_RESOURCE_H # include #endif ]) ]) dnl Detect if socklen_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_SOCKLEN_T], [ AC_CHECK_TYPE(socklen_t, , [AC_DEFINE([socklen_t], [int], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_WS2TCPIP_H # include #endif ]) ]) dnl Detect if in_addr_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_IN_ADDR_T], [ AC_CHECK_TYPE(in_addr_t, [], [AC_DEFINE([in_addr_t], [uint32_t], [in_addr_t])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif ]) ]) dnl Detect if in_port_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_IN_PORT_T], [ AC_CHECK_TYPE(in_port_t, [], [AC_DEFINE([in_port_t], [uint16_t], [in_port_t])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif ]) ]) dnl Add option to disable the evil rpath. Check whether to use rpath or not. dnl Adds the --disable-rpath option. Uses trick to edit the ./libtool. AC_DEFUN([ACX_ARG_RPATH], [ AC_ARG_ENABLE(rpath, [ --disable-rpath disable hardcoded rpath (default=enabled)], enable_rpath=$enableval, enable_rpath=yes) if test "x$enable_rpath" = xno; then dnl AC_MSG_RESULT([Fixing libtool for -rpath problems.]) AC_CONFIG_COMMANDS([disable-rpath], [ sed < libtool > libtool-2 \ 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_RPATH_SED__ "/' mv libtool-2 libtool chmod 755 libtool libtool="./libtool" ]) fi ]) dnl Add a -R to the RUNTIME_PATH. Only if rpath is enabled and it is dnl an absolute path. dnl $1: the pathname to add. AC_DEFUN([ACX_RUNTIME_PATH_ADD], [ if test "x$enable_rpath" = xyes; then if echo "$1" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$1" fi fi ]) dnl Common code for both ACX_WITH_SSL and ACX_WITH_SSL_OPTIONAL dnl Takes one argument; the withval checked in those 2 functions dnl sets up the environment for the given openssl path AC_DEFUN([ACX_SSL_CHECKS], [ withval=$1 if test x_$withval != x_no; then AC_MSG_CHECKING(for SSL) if test -n "$withval"; then dnl look for openssl install with different version, eg. dnl in /usr/include/openssl11/openssl/ssl.h dnl and /usr/lib64/openssl11/libssl.so dnl with the --with-ssl=/usr/include/openssl11 if test ! -f "$withval/include/openssl/ssl.h" -a -f "$withval/openssl/ssl.h"; then ssldir="$withval" found_ssl="yes" withval="" ssldir_include="$ssldir" dnl find the libdir ssldir_lib=`echo $ssldir | sed -e 's/include/lib/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else ssldir_lib=`echo $ssldir | sed -e 's/include/lib64/'` if test -f "$ssldir_lib/libssl.a" -o -f "$ssldir_lib/libssl.so"; then : # found here else AC_MSG_ERROR([Could not find openssl lib file, $ssldir_lib/libssl.[so,a], pass like "/usr/local" or "/usr/include/openssl11"]) fi fi fi fi if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes" ssldir_include="$ssldir/include" if test ! -d "$ssldir/lib" -a -d "$ssldir/lib64"; then ssldir_lib="$ssldir/lib64" else ssldir_lib="$ssldir/lib" fi break; fi done if test x_$found_ssl != x_yes; then AC_MSG_ERROR(Cannot find the SSL libraries in $withval) else AC_MSG_RESULT(found in $ssldir) AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.]) HAVE_SSL=yes dnl assume /usr is already in the include, lib and dynlib paths. if test "$ssldir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$ssldir_include" LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir_include" LDFLAGS="$LDFLAGS -L$ssldir_lib" LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir_lib" ACX_RUNTIME_PATH_ADD([$ssldir_lib]) fi AC_MSG_CHECKING([for EVP_sha256 in -lcrypto]) LIBS="$LIBS -lcrypto" LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_MSG_RESULT(yes) AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) ],[ AC_MSG_RESULT(no) # check if -lwsock32 or -lgdi32 are needed. BAKLIBS="$LIBS" BAKSSLLIBS="$LIBSSL_LIBS" LIBS="$LIBS -lgdi32 -lws2_32" LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32" AC_MSG_CHECKING([if -lcrypto needs -lgdi32]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32" LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32" AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a" LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a" AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -ldl" LIBSSL_LIBS="$LIBSSL_LIBS -ldl" AC_MSG_CHECKING([if -lcrypto needs -ldl]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -ldl -pthread" LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread" AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int EVP_sha256(void); (void)EVP_sha256(); ]])],[ AC_DEFINE([HAVE_EVP_SHA256], 1, [If you have EVP_sha256]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) ]) ]) ]) ]) ]) ]) fi AC_SUBST(HAVE_SSL) AC_SUBST(RUNTIME_PATH) fi AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT]) ])dnl End of ACX_SSL_CHECKS dnl Check for SSL, where SSL is mandatory dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. dnl Checks main header files of SSL. dnl AC_DEFUN([ACX_WITH_SSL], [ AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[ ],[ withval="yes" ]) if test x_$withval = x_no; then AC_MSG_ERROR([Need SSL library to do digital signature cryptography]) fi ACX_SSL_CHECKS($withval) ])dnl End of ACX_WITH_SSL dnl Check for SSL, where ssl is optional (--without-ssl is allowed) dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. dnl Checks main header files of SSL. dnl AC_DEFUN([ACX_WITH_SSL_OPTIONAL], [ AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr or specify like /usr/include/openssl11)]),[ ],[ withval="yes" ]) ACX_SSL_CHECKS($withval) ])dnl End of ACX_WITH_SSL_OPTIONAL dnl Setup to use -lssl dnl To use -lcrypto, use the ACX_WITH_SSL setup (before this one). AC_DEFUN([ACX_LIB_SSL], [ # check if libssl needs libdl BAKLIBS="$LIBS" LIBS="-lssl $LIBS" AC_MSG_CHECKING([if libssl needs libdl]) AC_TRY_LINK_FUNC([SSL_CTX_new], [ AC_MSG_RESULT([no]) LIBS="$BAKLIBS" ] , [ AC_MSG_RESULT([yes]) LIBS="$BAKLIBS" AC_SEARCH_LIBS([dlopen], [dl]) ]) ])dnl End of ACX_LIB_SSL dnl Setup to use very large files (>2Gb). dnl setups fseeko and its own AC_DEFUN([ACX_SYS_LARGEFILE], [ AC_SYS_LARGEFILE dnl try to see if an additional _LARGEFILE_SOURCE 1 is needed to get fseeko ACX_CHECK_COMPILER_FLAG_NEEDED(-D_LARGEFILE_SOURCE=1, [ #include int test(void) { int a = fseeko(stdin, 0, 0); return a; } ], [CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE=1"]) ]) dnl Check getaddrinfo. dnl Works on linux, solaris, bsd and windows(links winsock). dnl defines HAVE_GETADDRINFO, USE_WINSOCK. AC_DEFUN([ACX_CHECK_GETADDRINFO_WITH_INCLUDES], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for getaddrinfo) ac_cv_func_getaddrinfo=no AC_LINK_IFELSE( [AC_LANG_SOURCE([[ #ifdef __cplusplus extern "C" { #endif char* getaddrinfo(); char* (*f) () = getaddrinfo; #ifdef __cplusplus } #endif int main(void) { ; return 0; } ]])], dnl this case on linux, solaris, bsd [ac_cv_func_getaddrinfo="yes" dnl see if on windows if test "$ac_cv_header_windows_h" = "yes"; then AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" if echo "$LIBS" | grep 'lws2_32' >/dev/null; then : else LIBS="$LIBS -lws2_32" fi fi ], dnl no quick getaddrinfo, try mingw32 and winsock2 library. dnl perhaps getaddrinfo needs only the include AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #ifdef HAVE_WS2TCPIP_H #include #endif ], [ (void)getaddrinfo(NULL, NULL, NULL, NULL); ] )], [ ac_cv_func_getaddrinfo="yes" AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" ], ORIGLIBS="$LIBS" LIBS="$LIBS -lws2_32" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #ifdef HAVE_WS2TCPIP_H #include #endif ], [ (void)getaddrinfo(NULL, NULL, NULL, NULL); ] )], [ ac_cv_func_getaddrinfo="yes" dnl already: LIBS="$LIBS -lws2_32" AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" ], [ ac_cv_func_getaddrinfo="no" LIBS="$ORIGLIBS" ]) ) ) AC_MSG_RESULT($ac_cv_func_getaddrinfo) if test $ac_cv_func_getaddrinfo = yes; then AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether getaddrinfo is available]) fi ])dnl Endof AC_CHECK_GETADDRINFO_WITH_INCLUDES dnl check if a function is deprecated. defines DEPRECATED_func in config.h. dnl $1: function name dnl $2: C-statement that calls the function. dnl $3: includes for the program. dnl $4: executes if yes dnl $5: executes if no AC_DEFUN([ACX_FUNC_DEPRECATED], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(if $1 is deprecated) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_cc_deprecated_$cache, [ echo '$3' >conftest.c echo 'void f(void){ $2 }' >>conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then eval "cv_cc_deprecated_$cache=no" else eval "cv_cc_deprecated_$cache=yes" fi rm -f conftest conftest.o conftest.c ]) if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then AC_MSG_RESULT(yes) AC_DEFINE_UNQUOTED(AS_TR_CPP([DEPRECATED_$1]), 1, [Whether $1 is deprecated]) : $4 else AC_MSG_RESULT(no) : $5 fi ])dnl end of ACX_FUNC_DEPRECATED dnl check if select and nonblocking sockets actually work. dnl Needs fork(2) and select(2). dnl defines NONBLOCKING_IS_BROKEN, and if that is true multiple reads from dnl a nonblocking socket do not work, a new call to select is necessary. AC_DEFUN([ACX_CHECK_NONBLOCKING_BROKEN], [ AC_MSG_CHECKING([if nonblocking sockets work]) if echo $host | grep mingw >/dev/null; then AC_MSG_RESULT([no (windows)]) AC_DEFINE([NONBLOCKING_IS_BROKEN], 1, [Define if the network stack does not fully support nonblocking io (causes lower performance).]) else AC_RUN_IFELSE([ AC_LANG_SOURCE([[ #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif int main(void) { int port; int sfd, cfd; int num = 10; int i, p; struct sockaddr_in a; /* test if select and nonblocking reads work well together */ /* open port. fork child to send 10 messages. select to read. then try to nonblocking read the 10 messages then, nonblocking read must give EAGAIN */ port = 12345 + (time(0)%32); sfd = socket(PF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket"); return 1; } memset(&a, 0, sizeof(a)); a.sin_family = AF_INET; a.sin_port = htons(port); a.sin_addr.s_addr = inet_addr("127.0.0.1"); if(bind(sfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("bind"); return 1; } if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) { perror("fcntl"); return 1; } cfd = socket(PF_INET, SOCK_DGRAM, 0); if(cfd == -1) { perror("client socket"); return 1; } a.sin_port = 0; if(bind(cfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("client bind"); return 1; } a.sin_port = htons(port); /* no handler, causes exit in 10 seconds */ alarm(10); /* send and receive on the socket */ if((p=fork()) == 0) { for(i=0; i #include #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif ]], [[ (void)mkdir("directory"); ]])],[AC_MSG_RESULT(yes) AC_DEFINE(MKDIR_HAS_ONE_ARG, 1, [Define if mkdir has one argument.]) ],[AC_MSG_RESULT(no) ]) ])dnl end of ACX_MKDIR_ONE_ARG dnl Check for ioctlsocket function. works on mingw32 too. AC_DEFUN([ACX_FUNC_IOCTLSOCKET], [ # check ioctlsocket AC_MSG_CHECKING(for ioctlsocket) AC_LINK_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_WINSOCK2_H #include #endif ], [ (void)ioctlsocket(0, 0, NULL); ])], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_IOCTLSOCKET, 1, [if the function 'ioctlsocket' is available]) ],[AC_MSG_RESULT(no)]) ])dnl end of ACX_FUNC_IOCTLSOCKET dnl detect malloc and provide malloc compat prototype. dnl $1: unique name for compat code AC_DEFUN([ACX_FUNC_MALLOC], [ AC_MSG_CHECKING([for GNU libc compatible malloc]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [[#if defined STDC_HEADERS || defined HAVE_STDLIB_H #include #else char *malloc (); #endif ]], [ if(malloc(0) != 0) return 1;]) ], [AC_MSG_RESULT([no]) AC_LIBOBJ(malloc) AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] , [AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])], [AC_MSG_RESULT([no (crosscompile)]) AC_LIBOBJ(malloc) AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] ) ]) dnl Define fallback for fseeko and ftello if needed. AC_DEFUN([AHX_CONFIG_FSEEKO], [ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ ]) dnl Define RAND_MAX if not defined AC_DEFUN([AHX_CONFIG_RAND_MAX], [ #ifndef RAND_MAX #define RAND_MAX 2147483647 #endif ]) dnl Define MAXHOSTNAMELEN if not defined AC_DEFUN([AHX_CONFIG_MAXHOSTNAMELEN], [ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif ]) dnl Define IPV6_MIN_MTU if not defined AC_DEFUN([AHX_CONFIG_IPV6_MIN_MTU], [ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ ]) dnl provide snprintf, vsnprintf compat prototype dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_SNPRINTF], [ #ifndef HAVE_SNPRINTF #define snprintf snprintf_$1 #define vsnprintf vsnprintf_$1 #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ ]) dnl provide inet_pton compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_PTON], [ #ifndef HAVE_INET_PTON #define inet_pton inet_pton_$1 int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ ]) dnl provide inet_ntop compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_NTOP], [ #ifndef HAVE_INET_NTOP #define inet_ntop inet_ntop_$1 const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif ]) dnl provide inet_aton compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_ATON], [ #ifndef HAVE_INET_ATON #define inet_aton inet_aton_$1 int inet_aton(const char *cp, struct in_addr *addr); #endif ]) dnl provide memmove compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_MEMMOVE], [ #ifndef HAVE_MEMMOVE #define memmove memmove_$1 void *memmove(void *dest, const void *src, size_t n); #endif ]) dnl provide strlcat compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_STRLCAT], [ #ifndef HAVE_STRLCAT #define strlcat strlcat_$1 size_t strlcat(char *dst, const char *src, size_t siz); #endif ]) dnl provide strlcpy compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_STRLCPY], [ #ifndef HAVE_STRLCPY #define strlcpy strlcpy_$1 size_t strlcpy(char *dst, const char *src, size_t siz); #endif ]) dnl provide gmtime_r compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_GMTIME_R], [ #ifndef HAVE_GMTIME_R #define gmtime_r gmtime_r_$1 struct tm *gmtime_r(const time_t *timep, struct tm *result); #endif ]) dnl provide reallocarray compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_REALLOCARRAY], [ #ifndef HAVE_REALLOCARRAY #define reallocarray reallocarray$1 void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif ]) dnl provide w32 compat definition for sleep AC_DEFUN([AHX_CONFIG_W32_SLEEP], [ #if !defined(HAVE_SLEEP) || defined(HAVE_WINDOWS_H) #define sleep(x) Sleep((x)*1000) /* on win32 */ #endif /* HAVE_SLEEP */ ]) dnl provide w32 compat definition for usleep AC_DEFUN([AHX_CONFIG_W32_USLEEP], [ #ifndef HAVE_USLEEP #define usleep(x) Sleep((x)/1000 + 1) /* on win32 */ #endif /* HAVE_USLEEP */ ]) dnl provide w32 compat definition for random AC_DEFUN([AHX_CONFIG_W32_RANDOM], [ #ifndef HAVE_RANDOM #define random rand /* on win32, for tests only (bad random) */ #endif /* HAVE_RANDOM */ ]) dnl provide w32 compat definition for srandom AC_DEFUN([AHX_CONFIG_W32_SRANDOM], [ #ifndef HAVE_SRANDOM #define srandom(x) srand(x) /* on win32, for tests only (bad random) */ #endif /* HAVE_SRANDOM */ ]) dnl provide w32 compat definition for FD_SET_T AC_DEFUN([AHX_CONFIG_W32_FD_SET_T], [ /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ #ifdef HAVE_WINSOCK2_H #define FD_SET_T (u_int) #else #define FD_SET_T #endif ]) dnl Remove an extension flag from CFLAGS, define replacement to be made. dnl Used by ACX_STRIP_EXT_FLAGS. dnl $1: the name of the flag, for example -D_GNU_SOURCE. AC_DEFUN([ACX_CFLAGS_STRIP], [ if echo $CFLAGS | grep " $1" >/dev/null 2>&1; then CFLAGS="`echo $CFLAGS | sed -e 's/ $1//g'`" AC_DEFINE(m4_bpatsubst(OMITTED_$1,[[-=]],_), 1, Put $1 define in config.h) fi ]) dnl Remove EXT flags from the CFLAGS and set them to be defined in config.h dnl use with ACX_DETERMINE_EXT_FLAGS. AC_DEFUN([ACX_STRIP_EXT_FLAGS], [ AC_MSG_NOTICE([Stripping extension flags...]) ACX_CFLAGS_STRIP(-D_GNU_SOURCE) ACX_CFLAGS_STRIP(-D_BSD_SOURCE) ACX_CFLAGS_STRIP(-D_DEFAULT_SOURCE) ACX_CFLAGS_STRIP(-D__EXTENSIONS__) ACX_CFLAGS_STRIP(-D_POSIX_C_SOURCE=200112) ACX_CFLAGS_STRIP(-D_XOPEN_SOURCE=600) ACX_CFLAGS_STRIP(-D_XOPEN_SOURCE_EXTENDED=1) ACX_CFLAGS_STRIP(-D_ALL_SOURCE) ACX_CFLAGS_STRIP(-D_LARGEFILE_SOURCE=1) ]) dnl End of ACX_STRIP_EXT_FLAGS dnl define one omitted flag for config.h dnl $1: flag name. -D_GNU_SOURCE dnl $2: replacement define. _GNU_SOURCE dnl $3: define value, 1 AC_DEFUN([AHX_CONFIG_FLAG_OMITTED], [#if defined($1) && !defined($2) #define $2 $3 [#]endif]) dnl Wrapper for AHX_CONFIG_FLAG_OMITTED for -D style flags dnl $1: the -DNAME or -DNAME=value string. AC_DEFUN([AHX_CONFIG_FLAG_EXT], [AHX_CONFIG_FLAG_OMITTED(m4_bpatsubst(OMITTED_$1,[[-=]],_),m4_bpatsubst(m4_bpatsubst($1,-D,),=.*$,),m4_if(m4_bregexp($1,=),-1,1,m4_bpatsubst($1,^.*=,))) ]) dnl config.h part to define omitted cflags, use with ACX_STRIP_EXT_FLAGS. AC_DEFUN([AHX_CONFIG_EXT_FLAGS], [AHX_CONFIG_FLAG_EXT(-D_GNU_SOURCE) AHX_CONFIG_FLAG_EXT(-D_BSD_SOURCE) AHX_CONFIG_FLAG_EXT(-D_DEFAULT_SOURCE) AHX_CONFIG_FLAG_EXT(-D__EXTENSIONS__) AHX_CONFIG_FLAG_EXT(-D_POSIX_C_SOURCE=200112) AHX_CONFIG_FLAG_EXT(-D_XOPEN_SOURCE=600) AHX_CONFIG_FLAG_EXT(-D_XOPEN_SOURCE_EXTENDED=1) AHX_CONFIG_FLAG_EXT(-D_ALL_SOURCE) AHX_CONFIG_FLAG_EXT(-D_LARGEFILE_SOURCE=1) ]) dnl check if memcmp is using signed characters and replace if so. AC_DEFUN([ACX_CHECK_MEMCMP_SIGNED], [AC_MSG_CHECKING([if memcmp compares unsigned]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include int main(void) { char a = 255, b = 0; if(memcmp(&a, &b, 1) < 0) return 1; return 0; } ]])], [AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) AC_DEFINE([MEMCMP_IS_BROKEN], [1], [Define if memcmp() does not compare unsigned bytes]) AC_LIBOBJ([memcmp]) ], [ AC_MSG_RESULT([cross-compile no]) AC_DEFINE([MEMCMP_IS_BROKEN], [1], [Define if memcmp() does not compare unsigned bytes]) AC_LIBOBJ([memcmp]) ]) ]) dnl define memcmp to its replacement, pass unique id for program as arg AC_DEFUN([AHX_MEMCMP_BROKEN], [ #ifdef MEMCMP_IS_BROKEN #include "compat/memcmp.h" #define memcmp memcmp_$1 int memcmp(const void *x, const void *y, size_t n); #endif ]) dnl ACX_CHECK_SS_FAMILY - check for sockaddr_storage.ss_family AC_DEFUN([ACX_CHECK_SS_FAMILY], [AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], [], [ AC_CHECK_MEMBER([struct sockaddr_storage.__ss_family], [ AC_DEFINE([ss_family], [__ss_family], [Fallback member name for socket family in struct sockaddr_storage]) ],, [AC_INCLUDES_DEFAULT #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif ]) ], [AC_INCLUDES_DEFAULT #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #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 nsd-4.12.0/SECURITY.md0000644000175000017500000000232215002373054013565 0ustar mozziemozzie# Security Policy ## Supported Versions NLnet Labs adheres to the straightforward, semantic versioning scheme that is commonly used in the software industry. Support is provided in respect of the latest release, i.e. releases with the highest minor and patch version level. We do not backport security fixes to older (minor) versions. In the event a new major version is released (e.g. from 3.2.18 to 4.0.0), support will also be provided on the latest minor version of the previous major version (3.2.18) for a period of one year from the release of the new major version (4.0.0). In the event that, during this period, a new patch or minor version of the previous major version is released, then support on these versions will only be provided for the remainder of the one-year-period. You can find detailed information on our software support policy here: https://www.nlnetlabs.nl/support/software-support-policy/ ## Reporting a Vulnerability We take security very seriously. If you have discovered a security vulnerability in one of our projects and you would like to report it to us, you can send an encrypted message to our Security Entry Point. Details are described here: https://www.nlnetlabs.nl/security-report/ nsd-4.12.0/README.md0000644000175000017500000000507715002373054013265 0ustar mozziemozzie# NSD [![GitHub Build Status](https://github.com/NLnetLabs/nsd/actions/workflows/build-test.yml/badge.svg?branch=master)](https://github.com/NLnetLabs/nsd/actions) [![Coverity Scan Status](https://scan.coverity.com/projects/18867/badge.svg)](https://scan.coverity.com/projects/nlnetlabs-nsd) [![Packaging status](https://repology.org/badge/tiny-repos/nsd.svg)](https://repology.org/project/nsd/versions) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1462/badge)](https://bestpractices.coreinfrastructure.org/projects/1462) [![Mastodon Follow](https://img.shields.io/mastodon/follow/109262826617293067?domain=https%3A%2F%2Ffosstodon.org&style=social)](https://fosstodon.org/@nlnetlabs) The NLnet Labs Name Server Daemon (NSD) is an authoritative DNS name server. It has been developed for operations in environments where speed, reliability, stability and security are of high importance. If you have any feedback, we would love to hear from you. Don’t hesitate to [create an issue on Github](https://github.com/NLnetLabs/nsd/issues/new) or post a message on the [NSD mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/nsd-users). You can learn more about NSD by reading our [documentation](https://nsd.docs.nlnetlabs.nl/). ## Building Make sure you have the following installed: * C toolchain (the set of tools to compile C such as a compiler, linker, and assembler) * OpenSSL, with its include files (usually these are included in the "dev" version of the library) * libevent, with its include files (usually these are included in the "dev" version of the library) * flex * bison When building from Git, the `configure` script and [simdzone][simdzone] sources are missing, use the following commands to get started (note that the `configure` script and sources are included in release tarballs and do not need to be generated/downloaded): ``` $ git submodule update --init $ autoreconf -fi ``` > `autoreconf` should install the required auxiliary files (e.g. `config.sub` > and `config.guess`). Older versions of `autoreconf` may not do so, try > running `libtoolize -fi -c` first in that case. Compile and install using: ``` $ ./configure && make && make install ``` ## NSD configuration The configuration options for NSD are described in the man pages, which are installed (use `man nsd.conf`) and are available on the NSD [documentation page](https://nsd.docs.nlnetlabs.nl/). An example configuration file is located in [nsd.conf.sample](https://github.com/NLnetLabs/nsd/blob/master/nsd.conf.sample.in). [simdzone]: https://github.com/NLnetLabs/simdzone nsd-4.12.0/Makefile.in0000644000175000017500000011720615002373054014051 0ustar mozziemozzie# # Makefile -- one file to make them all, nsd(8) # # Copyright (c) 2001-2006, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # Standard installation pathnames SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ mandir = @mandir@ datarootdir = @datarootdir@ runstatedir = @runstatedir@ # NSD specific pathnames configdir = @configdir@ piddir = @piddir@ pidfile = @pidfile@ logfile = @logfile@ xfrdir = @xfrdir@ xfrdfile = @xfrdfile@ zonelistfile = @zonelistfile@ cookiesecretsfile = @cookiesecretsfile@ nsdconfigfile = @nsd_conf_file@ zonesdir = @zonesdir@ chrootdir= @chrootdir@ user = @user@ DNSTAP_SRC=@DNSTAP_SRC@ DNSTAP_OBJ=@DNSTAP_OBJ@ # override $U variable which is used by autotools for deansification (for # K&R C compilers), but causes problems if $U is defined in the env). U= CC = @CC@ CPPFLAGS = @CPPFLAGS@ -Isimdzone/include -I@srcdir@/simdzone/include CFLAGS = @CFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ SSL_LIBS = @SSL_LIBS@ LIBOBJS = @LIBOBJS@ INSTALL = $(srcdir)/install-sh -c INSTALL_PROGRAM = $(INSTALL) INSTALL_DATA = $(INSTALL) -m 644 SED = @SED@ AWK = @AWK@ GREP = @GREP@ EGREP = @EGREP@ YACC = @YACC@ LEX = @LEX@ PROTOC_C = @PROTOC_C@ DATE != date +'%b %e, %y' PROJECT = @PACKAGE_NAME@ VERSION = @PACKAGE_VERSION@ COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) LINK = $(CC) $(CFLAGS) $(LDFLAGS) EDIT = $(SED) \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix\@,$(exec_prefix),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@configdir\@,$(configdir),g' \ -e 's,@zonesdir\@,$(zonesdir),g' \ -e 's,@chrootdir\@,$(chrootdir),g' \ -e 's,@runstatedir\@,$(runstatedir),g' \ -e 's,@pidfile\@,$(pidfile),g' \ -e 's,@logfile\@,$(logfile),g' \ -e 's,@xfrdir\@,$(xfrdir),g' \ -e 's,@xfrdfile\@,$(xfrdfile),g' \ -e 's,@zonelistfile\@,$(zonelistfile),g' \ -e 's,@cookiesecretsfile\@,$(cookiesecretsfile),g' \ -e 's,@nsdconfigfile\@,$(nsdconfigfile),g' \ -e 's,@shell\@,$(SHELL),g' \ -e 's,@ratelimit_default\@,@ratelimit_default@,g' \ -e 's,@dnstap_socket_path\@,@opt_dnstap_socket_path@,g' \ -e 's,@user\@,$(user),g' \ -e 's/@project\@/$(PROJECT)/g' \ -e 's/@version\@/$(VERSION)/g' \ -e 's/@date\@/$(DATE)/g' TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control-setup.sh contrib/nsd.openrc contrib/nsd-tmpfiles.conf MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 COMMON_OBJ=answer.o axfr.o ixfr.o ixfrcreate.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o siphash.o tsig.o tsig-openssl.o udb.o util.o bitset.o popen3.o proxy_protocol.o XFRD_OBJ=xfrd-catalog-zones.o xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o metrics.o $(DNSTAP_OBJ) NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zonec.o verify.o ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o xfr-inspect.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o NSD_CHECKZONE_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o nsd-checkzone.o verify.o NSD_CONTROL_OBJ=$(COMMON_OBJ) nsd-control.o CUTEST_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o verify.o zonec.o cutest_dname.o cutest_dns.o cutest_iterated_hash.o cutest_run.o cutest_radtree.o cutest_rbtree.o cutest_namedb.o cutest_options.o cutest_region.o cutest_rrl.o cutest_udb.o cutest_util.o cutest_bitset.o cutest_popen3.o cutest_iter.o cutest_event.o cutest.o qtest.o NSD_MEM_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o verify.o server.o zonec.o nsd-mem.o .PHONY: all html all: $(TARGETS) $(MANUALS) doc/manual/conf.py: doc/manual/conf.py.in $(EDIT) $(srcdir)/doc/manual/conf.py.in > $@ doc/manual/manpages/nsd.conf.5.html: nsd.conf.5 mandoc -T html -O fragment nsd.conf.5 > $@ sed -i '//,/<\/table>/ d' $@ doc/manual/manpages/nsd.8.html: nsd.8 mandoc -T html -O fragment nsd.8 > $@ sed -i '/
/,/<\/table>/ d' $@ doc/manual/manpages/nsd-checkconf.8.html: nsd-checkconf.8 mandoc -T html -O fragment nsd-checkconf.8 > $@ sed -i '/
/,/<\/table>/ d' $@ doc/manual/manpages/nsd-checkzone.8.html: nsd-checkzone.8 mandoc -T html -O fragment nsd-checkzone.8 > $@ sed -i '/
/,/<\/table>/ d' $@ doc/manual/manpages/nsd-control.8.html: nsd-control.8 mandoc -T html -O fragment nsd-control.8 > $@ sed -i '/
/,/<\/table>/ d' $@ html: doc/manual/conf.py doc/manual/manpages/nsd.conf.5.html doc/manual/manpages/nsd.8.html doc/manual/manpages/nsd-checkconf.8.html doc/manual/manpages/nsd-checkzone.8.html doc/manual/manpages/nsd-control.8.html sphinx-build -M html $(srcdir)/doc/manual doc/manual -N -q $(ALL_OBJ): $(COMPILE) -c $< nsd-control-setup.sh: $(srcdir)/nsd-control-setup.sh.in config.h rm -f nsd-control-setup.sh $(EDIT) $(srcdir)/nsd-control-setup.sh.in > nsd-control-setup.sh chmod +x nsd-control-setup.sh nsd.conf.sample: $(srcdir)/nsd.conf.sample.in config.h rm -f nsd.conf.sample $(EDIT) $(srcdir)/nsd.conf.sample.in | $(AWK) '/RRLconfig'@ratelimit@'/ { while($$0 !~ /.*RRLend.*/) { getline; } getline; } {print} ' > nsd.conf.sample nsd.conf.5: $(srcdir)/nsd.conf.5.in config.h $(EDIT) $(srcdir)/nsd.conf.5.in | $(AWK) '/rrlstart'@ratelimit@'/ { while($$0 !~ /.*rrlend.*/) { getline; } getline; } {print} ' > $@ nsd.8: $(srcdir)/nsd.8.in config.h $(EDIT) $(srcdir)/nsd.8.in > $@ nsd-checkconf.8: $(srcdir)/nsd-checkconf.8.in config.h $(EDIT) $(srcdir)/nsd-checkconf.8.in > $@ nsd-checkzone.8: $(srcdir)/nsd-checkzone.8.in config.h $(EDIT) $(srcdir)/nsd-checkzone.8.in > $@ nsd-control.8: $(srcdir)/nsd-control.8.in config.h $(EDIT) $(srcdir)/nsd-control.8.in > $@ contrib/nsd.openrc: $(srcdir)/contrib/nsd.openrc.in mkdir -p contrib $(EDIT) $(srcdir)/contrib/nsd.openrc.in > $@ contrib/nsd-tmpfiles.conf: $(srcdir)/contrib/nsd-tmpfiles.conf.in mkdir -p contrib $(EDIT) $(srcdir)/contrib/nsd-tmpfiles.conf.in > $@ install: all $(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) -d $(DESTDIR)$(configdir) if test -n "$(piddir)"; then $(INSTALL) -d $(DESTDIR)$(piddir); fi $(INSTALL) -d $(DESTDIR)$(xfrdir) $(INSTALL) -d `dirname $(DESTDIR)$(xfrdfile)` $(INSTALL) -d `dirname $(DESTDIR)$(zonelistfile)` $(INSTALL) -d `dirname $(DESTDIR)$(cookiesecretsfile)` $(INSTALL) -d $(DESTDIR)$(mandir) $(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(mandir)/man5 $(INSTALL) nsd $(DESTDIR)$(sbindir)/nsd $(INSTALL) nsd-control-setup.sh $(DESTDIR)$(sbindir)/nsd-control-setup $(INSTALL) nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkconf $(INSTALL) nsd-checkzone $(DESTDIR)$(sbindir)/nsd-checkzone $(INSTALL) nsd-control $(DESTDIR)$(sbindir)/nsd-control $(INSTALL_DATA) nsd.8 $(DESTDIR)$(mandir)/man8 $(INSTALL_DATA) nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(INSTALL_DATA) nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(INSTALL_DATA) nsd-control.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 $(INSTALL_DATA) nsd.conf.5 $(DESTDIR)$(mandir)/man5/nsd.conf.5 $(INSTALL_DATA) nsd.conf.sample $(DESTDIR)$(nsdconfigfile).sample uninstall: @echo rm -f -- $(DESTDIR)$(sbindir)/nsd $(DESTDIR)$(sbindir)/nsd-control-setup $(DESTDIR)$(sbindir)/nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkzone $(DESTDIR)$(sbindir)/nsd-control rm -f -- $(DESTDIR)$(mandir)/man8/nsd.8 $(DESTDIR)$(mandir)/man5/nsd.conf.5 rm -f -- $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 rm -f -- $(DESTDIR)$(pidfile) @echo @echo "You still need to remove $(DESTDIR)$(configdir), $(DESTDIR)$(piddir), $(DESTDIR)$(xfrdfile), $(DESTDIR)$(zonelistfile) $(DESTDIR)$(cookiesecretsfile) directory by hand." test: simdzone/libzone.a: $(MAKE) -C simdzone simdzone/include/zone/export.h: simdzone/libzone.a nsd: simdzone/libzone.a $(NSD_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_OBJ) $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) nsd-checkconf: simdzone/libzone.a $(NSD_CHECKCONF_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CHECKCONF_OBJ) simdzone/libzone.a $(LIBOBJS) $(SSL_LIBS) $(LIBS) nsd-checkzone: simdzone/libzone.a $(NSD_CHECKZONE_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CHECKZONE_OBJ) $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) nsd-control: simdzone/libzone.a $(NSD_CONTROL_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CONTROL_OBJ) $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) nsd-mem: simdzone/libzone.a $(NSD_MEM_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_MEM_OBJ) $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) cutest: simdzone/libzone.a $(CUTEST_OBJ) $(LIBOBJS) popen3_echo $(LINK) -o $@ $(CUTEST_OBJ) $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) xfr-inspect: simdzone/libzone.a xfr-inspect.o $(COMMON_OBJ) zonec.o $(LIBOBJS) $(LINK) -o $@ xfr-inspect.o $(COMMON_OBJ) zonec.o $(LIBOBJS) simdzone/libzone.a $(SSL_LIBS) $(LIBS) popen3_echo: popen3.o popen3_echo.o $(LINK) -o $@ popen3.o popen3_echo.o checksec: wget -q -O checksec https://raw.githubusercontent.com/slimm609/checksec.sh/master/checksec -chmod a+x checksec && xattr -d com.apple.quarantine checksec 2>/dev/null audit: nsd nsd-checkconf nsd-checkzone nsd-control nsd-mem checksec ./checksec --file=nsd ./checksec --file=nsd-checkconf ./checksec --file=nsd-checkzone ./checksec --file=nsd-control ./checksec --file=nsd-mem .clean: rm -f *.o $(TARGETS) $(MANUALS) cutest popen3_echo xfr-inspect nsd-mem rm -f doc/manual/conf.py doc/manual/manpages/nsd.conf.5.html doc/manual/manpages/nsd.8.html doc/manual/manpages/nsd-checkconf.8.html doc/manual/manpages/nsd-checkzone.8.html doc/manual/manpages/nsd-control.8.html rm -rf doc/manual/doctrees doc/manual/html .distclean: .clean rm -f Makefile config.h config.log config.status dnstap/dnstap_config.h .realclean: .distclean rm -rf autom4te* rm -f configlexer.c configparser.h configparser.c configparser.stamp clean: .clean $(MAKE) -C simdzone clean distclean: .distclean $(MAKE) -C simdzone distclean realclean: .realclean $(MAKE) -C simdzone realclean maintainer-clean: realclean devclean: .realclean rm -f config.h.in configure $(MAKE) -C simdzone devclean basename.o: $(srcdir)/compat/basename.c $(COMPILE) -c $(srcdir)/compat/basename.c inet_pton.o: $(srcdir)/compat/inet_pton.c $(COMPILE) -c $(srcdir)/compat/inet_pton.c inet_ntop.o: $(srcdir)/compat/inet_ntop.c $(COMPILE) -c $(srcdir)/compat/inet_ntop.c inet_aton.o: $(srcdir)/compat/inet_aton.c $(COMPILE) -c $(srcdir)/compat/inet_aton.c b64_pton.o: $(srcdir)/compat/b64_pton.c $(COMPILE) -c $(srcdir)/compat/b64_pton.c b64_ntop.o: $(srcdir)/compat/b64_ntop.c $(COMPILE) -c $(srcdir)/compat/b64_ntop.c memcmp.o: $(srcdir)/compat/memcmp.c $(COMPILE) -c $(srcdir)/compat/memcmp.c memmove.o: $(srcdir)/compat/memmove.c $(COMPILE) -c $(srcdir)/compat/memmove.c snprintf.o: $(srcdir)/compat/snprintf.c $(COMPILE) -c $(srcdir)/compat/snprintf.c strlcat.o: $(srcdir)/compat/strlcat.c $(COMPILE) -c $(srcdir)/compat/strlcat.c strlcpy.o: $(srcdir)/compat/strlcpy.c $(COMPILE) -c $(srcdir)/compat/strlcpy.c strptime.o: $(srcdir)/compat/strptime.c $(COMPILE) -c $(srcdir)/compat/strptime.c setproctitle.o: $(srcdir)/compat/setproctitle.c $(COMPILE) -c $(srcdir)/compat/setproctitle.c vsnprintf.o: $(srcdir)/compat/vsnprintf.c $(COMPILE) -c $(srcdir)/compat/vsnprintf.c timegm.o: $(srcdir)/compat/timegm.c $(COMPILE) -c $(srcdir)/compat/timegm.c malloc.o: $(srcdir)/compat/malloc.c $(COMPILE) -c $(srcdir)/compat/malloc.c pselect.o: $(srcdir)/compat/pselect.c $(COMPILE) -c $(srcdir)/compat/pselect.c reallocarray.o: $(srcdir)/compat/reallocarray.c $(COMPILE) -c $(srcdir)/compat/reallocarray.c fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(COMPILE) -c $(srcdir)/compat/fake-rfc2553.c cpuset.o: $(srcdir)/compat/cpuset.c $(COMPILE) -c $(srcdir)/compat/cpuset.c explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c $(COMPILE) -c $(srcdir)/compat/explicit_bzero.c cutest_dname.o: $(srcdir)/tpkg/cutest/cutest_dname.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_dname.c cutest_dns.o: $(srcdir)/tpkg/cutest/cutest_dns.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_dns.c cutest_iterated_hash.o: $(srcdir)/tpkg/cutest/cutest_iterated_hash.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_iterated_hash.c cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_run.c cutest_rbtree.o: $(srcdir)/tpkg/cutest/cutest_rbtree.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_rbtree.c cutest_radtree.o: $(srcdir)/tpkg/cutest/cutest_radtree.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_radtree.c cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_namedb.c cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_options.c cutest_region.o: $(srcdir)/tpkg/cutest/cutest_region.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_region.c cutest_rrl.o: $(srcdir)/tpkg/cutest/cutest_rrl.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_rrl.c cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_udb.c cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_udbrad.c cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_util.c cutest_bitset.o: $(srcdir)/tpkg/cutest/cutest_bitset.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_bitset.c cutest_popen3.o: $(srcdir)/tpkg/cutest/cutest_popen3.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_popen3.c cutest_iter.o: $(srcdir)/tpkg/cutest/cutest_iter.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_iter.c cutest_event.o: $(srcdir)/tpkg/cutest/cutest_event.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_event.c popen3_echo.o: $(srcdir)/tpkg/cutest/popen3_echo.c $(COMPILE) -c $(srcdir)/tpkg/cutest/popen3_echo.c cutest.o: $(srcdir)/tpkg/cutest/cutest.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest.c qtest.o: $(srcdir)/tpkg/cutest/qtest.c $(COMPILE) -c $(srcdir)/tpkg/cutest/qtest.c configlexer.c: $(srcdir)/configlexer.lex if test "$(LEX)" != ":"; then rm -f $@ ;\ echo '#include "config.h"' > $@ ;\ $(LEX) -P c_ -i -t $(srcdir)/configlexer.lex >> $@ ;\ fi @if test ! -f $@; then echo "No $@ : need flex and bison to compile from source repository"; exit 1; fi # Builds both util/configparser.c and util/configparser.h. # To avoid double-building we split one target out. configparser.c: $(srcdir)/configparser.y $(YACC) -d -p c_ -o configparser.c $(srcdir)/configparser.y configparser.h: configparser.c touch $@ # for build to run flex and bison before compiling code that needs the headers configlexer.o: configlexer.c config.h configparser.h configparser.o: configparser.c config.h configparser.h options.o: $(srcdir)/options.c config.h configparser.h dns.o: $(srcdir)/dns.c config.h zonec.o: $(srcdir)/zonec.c config.h metrics.o: $(srcdir)/metrics.c config.h # dnstap dnstap.o: $(srcdir)/dnstap/dnstap.c config.h dnstap/dnstap_config.h \ dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h $(srcdir)/dnstap/dnstap.h \ $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h dnstap.pb-c.o: dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h dnstap_collector.o: $(srcdir)/dnstap/dnstap_collector.c config.h \ $(srcdir)/dnstap/dnstap.h $(srcdir)/dnstap/dnstap_collector.h \ $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/region-allocator.h \ $(srcdir)/buffer.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/options.h $(srcdir)/remote.h dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h: $(srcdir)/dnstap/dnstap.proto @-if test ! -d dnstap; then $(INSTALL) -d dnstap; fi $(PROTOC_C) --c_out=. --proto_path=$(srcdir) $(srcdir)/dnstap/dnstap.proto # autoconf rules config.h.in: configure.ac autoheader configure: configure.ac autoconf tags: ctags *.[ch] # dependency generation DEPEND_TMP=depend1073.tmp DEPEND_TMP2=depend1074.tmp DEPEND_TARGET=Makefile DEPEND_TARGET2=Makefile.in depend: (cd $(srcdir) ; $(CC) -MM $(CPPFLAGS) *.c compat/*.c `if test -d tpkg/cutest; then echo tpkg/cutest/*.c; fi`) | \ $(SED) -e 's? *\([^ ]*\.[ch]\)? $$(srcdir)/\1?g' | \ $(SED) -e 's?$$(srcdir)/config.h?config.h?g' \ -e 's?$$(srcdir)/configlexer.c?configlexer.c?g' \ -e 's?$$(srcdir)/configparser.c?configparser.c?g' \ -e 's?$$(srcdir)/configparser.h?configparser.h?g' \ -e 's?$$(srcdir)/dnstap/dnstap_config.h??g' \ -e 's?$$(srcdir)/dnstap/dnstap.pb-c.c?dnstap/dnstap.pb-c.c?g' \ -e 's?$$(srcdir)/dnstap/dnstap.pb-c.h?dnstap/dnstap.pb-c.h?g' \ -e 's?$$(srcdir)/simdzone/include/zone/export.h?simdzone/include/zone/export.h?g' \ > $(DEPEND_TMP) cp $(DEPEND_TARGET) $(DEPEND_TMP2) head -`$(EGREP) -n "# Dependencies" $(DEPEND_TARGET) | tail -1 | $(SED) -e 's/:.*$$//'` $(DEPEND_TMP2) > $(DEPEND_TARGET) cat $(DEPEND_TMP) >> $(DEPEND_TARGET) @if diff $(DEPEND_TARGET) $(DEPEND_TMP2); then echo " $(DEPEND_TARGET) unchanged"; else echo " Updated $(DEPEND_TARGET))"; fi @if test -f $(DEPEND_TARGET2); then \ cp $(DEPEND_TARGET2) $(DEPEND_TMP2); \ head -`$(EGREP) -n "# Dependencies" $(DEPEND_TARGET2) | tail -1 | $(SED) -e 's/:.*$$//'` $(DEPEND_TMP2) > $(DEPEND_TARGET2); \ cat $(DEPEND_TMP) >> $(DEPEND_TARGET2); \ if diff $(DEPEND_TARGET2) $(DEPEND_TMP2); then echo " $(DEPEND_TARGET2) unchanged"; else echo " Updated $(DEPEND_TARGET2))"; fi; \ fi rm -f $(DEPEND_TMP) $(DEPEND_TMP2) proxy_protocol.o: $(srcdir)/util/proxy_protocol.c config.h $(srcdir)/util/proxy_protocol.h # Dependencies answer.o: $(srcdir)/answer.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/answer.h $(srcdir)/dns.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h \ $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/tsig.h axfr.o: $(srcdir)/axfr.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/options.h $(srcdir)/ixfr.h bitset.o: $(srcdir)/bitset.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/bitset.h buffer.o: $(srcdir)/buffer.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h configlexer.o: configlexer.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h configparser.h configparser.o: configparser.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/tsig.h $(srcdir)/rrl.h \ $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h configparser.h dbaccess.o: $(srcdir)/dbaccess.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/options.h $(srcdir)/rdata.h \ $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h \ $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfrcreate.h dbcreate.o: $(srcdir)/dbcreate.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h $(srcdir)/options.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h difffile.o: $(srcdir)/difffile.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/difffile.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/nsec3.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/zonec.h $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd.h dname.o: $(srcdir)/dname.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/dns.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h dns.o: $(srcdir)/dns.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/dns.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h edns.o: $(srcdir)/edns.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h ipc.o: $(srcdir)/ipc.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/region-allocator.h \ $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/xfrd-notify.h \ $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/packet.h iterated_hash.o: $(srcdir)/iterated_hash.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/iterated_hash.h \ $(srcdir)/util.h ixfr.o: $(srcdir)/ixfr.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/rdata.h $(srcdir)/axfr.h $(srcdir)/options.h $(srcdir)/zonec.h \ $(srcdir)/simdzone/include/zone.h $(srcdir)/simdzone/include/zone/attributes.h \ simdzone/include/zone/export.h ixfrcreate.o: $(srcdir)/ixfrcreate.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/ixfrcreate.h $(srcdir)/dns.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/options.h lookup3.o: $(srcdir)/lookup3.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/lookup3.h mini_event.o: $(srcdir)/mini_event.c config.h $(srcdir)/compat/cpuset.h namedb.o: $(srcdir)/namedb.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsec3.h netio.o: $(srcdir)/netio.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/netio.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h \ $(srcdir)/remote.h $(srcdir)/xfrd-disk.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/util/proxy_protocol.h config.h \ $(srcdir)/compat/cpuset.h nsd-checkconf.o: $(srcdir)/nsd-checkconf.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/dns.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h nsd-checkzone.o: $(srcdir)/nsd-checkzone.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h $(srcdir)/dns.h \ $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/options.h $(srcdir)/rbtree.h \ $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h \ $(srcdir)/ixfrcreate.h $(srcdir)/difffile.h $(srcdir)/udb.h nsd-control.o: $(srcdir)/nsd-control.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/util.h $(srcdir)/tsig.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/dns.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/zonec.h \ $(srcdir)/namedb.h $(srcdir)/radtree.h nsd-mem.o: $(srcdir)/nsd-mem.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h \ $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h nsec3.o: $(srcdir)/nsec3.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsec3.h $(srcdir)/iterated_hash.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/answer.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/tsig.h \ $(srcdir)/options.h options.o: $(srcdir)/options.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/difffile.h \ $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/xfrd.h configparser.h packet.o: $(srcdir)/packet.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/packet.h $(srcdir)/dns.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h \ $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/rdata.h popen3.o: $(srcdir)/popen3.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/popen3.h query.o: $(srcdir)/query.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/answer.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/query.h \ $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/axfr.h $(srcdir)/options.h $(srcdir)/nsec3.h radtree.o: $(srcdir)/radtree.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/radtree.h $(srcdir)/util.h \ $(srcdir)/region-allocator.h rbtree.o: $(srcdir)/rbtree.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h rdata.o: $(srcdir)/rdata.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/rdata.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h region-allocator.o: $(srcdir)/region-allocator.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h remote.o: $(srcdir)/remote.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/util.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h \ $(srcdir)/tsig.h $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/remote.h rrl.o: $(srcdir)/rrl.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/lookup3.h $(srcdir)/options.h server.o: $(srcdir)/server.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/netio.h $(srcdir)/xfrd.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h \ $(srcdir)/xfrd-disk.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/nsec3.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/lookup3.h $(srcdir)/rrl.h \ $(srcdir)/ixfr.h $(srcdir)/verify.h $(srcdir)/util/proxy_protocol.h config.h $(srcdir)/compat/cpuset.h siphash.o: $(srcdir)/siphash.c tsig.o: $(srcdir)/tsig.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/dns.h $(srcdir)/tsig-openssl.h $(srcdir)/packet.h $(srcdir)/namedb.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h tsig-openssl.o: $(srcdir)/tsig-openssl.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/tsig-openssl.h \ $(srcdir)/region-allocator.h $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/dns.h udb.o: $(srcdir)/udb.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h util.o: $(srcdir)/util.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/util.h $(srcdir)/region-allocator.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/options.h verify.o: $(srcdir)/verify.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ $(srcdir)/options.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/verify.h $(srcdir)/popen3.h xfrd.o: $(srcdir)/xfrd.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd-notify.h \ $(srcdir)/xfrd-catalog-zones.h $(srcdir)/netio.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/rdata.h \ $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/rrl.h $(srcdir)/query.h xfrd-catalog-zones.o: $(srcdir)/xfrd-catalog-zones.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/difffile.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h \ $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd.h $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h xfrd-disk.o: $(srcdir)/xfrd-disk.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd.h \ $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h xfrd-notify.o: $(srcdir)/xfrd-notify.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/xfrd-notify.h \ $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/dns.h $(srcdir)/rbtree.h $(srcdir)/xfrd.h \ $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/packet.h xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.h xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/util.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/packet.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/options.h $(srcdir)/udb.h zonec.o: $(srcdir)/zonec.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \ $(srcdir)/options.h $(srcdir)/nsec3.h $(srcdir)/simdzone/include/zone.h \ $(srcdir)/simdzone/include/zone/attributes.h simdzone/include/zone/export.h b64_ntop.o: $(srcdir)/compat/b64_ntop.c config.h $(srcdir)/compat/cpuset.h b64_pton.o: $(srcdir)/compat/b64_pton.c config.h $(srcdir)/compat/cpuset.h basename.o: $(srcdir)/compat/basename.c cpuset.o: $(srcdir)/compat/cpuset.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/compat/cpuset.h explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h $(srcdir)/compat/cpuset.h fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(srcdir)/compat/fake-rfc2553.h config.h \ $(srcdir)/compat/cpuset.h inet_aton.o: $(srcdir)/compat/inet_aton.c config.h $(srcdir)/compat/cpuset.h inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h $(srcdir)/compat/cpuset.h inet_pton.o: $(srcdir)/compat/inet_pton.c config.h $(srcdir)/compat/cpuset.h malloc.o: $(srcdir)/compat/malloc.c memcmp.o: $(srcdir)/compat/memcmp.c config.h $(srcdir)/compat/cpuset.h memmove.o: $(srcdir)/compat/memmove.c config.h $(srcdir)/compat/cpuset.h pselect.o: $(srcdir)/compat/pselect.c config.h $(srcdir)/compat/cpuset.h reallocarray.o: $(srcdir)/compat/reallocarray.c config.h $(srcdir)/compat/cpuset.h setproctitle.o: $(srcdir)/compat/setproctitle.c config.h $(srcdir)/compat/cpuset.h snprintf.o: $(srcdir)/compat/snprintf.c config.h $(srcdir)/compat/cpuset.h strlcat.o: $(srcdir)/compat/strlcat.c config.h $(srcdir)/compat/cpuset.h strlcpy.o: $(srcdir)/compat/strlcpy.c config.h $(srcdir)/compat/cpuset.h strptime.o: $(srcdir)/compat/strptime.c cutest_bitset.o: $(srcdir)/tpkg/cutest/cutest_bitset.c $(srcdir)/bitset.h \ $(srcdir)/tpkg/cutest/cutest.h cutest.o: $(srcdir)/tpkg/cutest/cutest.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h cutest_dname.o: $(srcdir)/tpkg/cutest/cutest_dname.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h cutest_dns.o: $(srcdir)/tpkg/cutest/cutest_dns.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/dns.h cutest_event.o: $(srcdir)/tpkg/cutest/cutest_event.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h \ $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h \ $(srcdir)/tpkg/cutest/cutest.h cutest_iterated_hash.o: $(srcdir)/tpkg/cutest/cutest_iterated_hash.c config.h \ $(srcdir)/compat/cpuset.h $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h \ $(srcdir)/iterated_hash.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h cutest_iter.o: $(srcdir)/tpkg/cutest/cutest_iter.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/nsd.h \ $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/options.h \ $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/tpkg/cutest/cutest.h cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsec3.h $(srcdir)/udb.h \ $(srcdir)/difffile.h $(srcdir)/namedb.h $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ $(srcdir)/simdzone/include/zone.h $(srcdir)/simdzone/include/zone/attributes.h \ simdzone/include/zone/export.h cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h cutest_popen3.o: $(srcdir)/tpkg/cutest/cutest_popen3.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/popen3.h $(srcdir)/tpkg/cutest/cutest.h cutest_radtree.o: $(srcdir)/tpkg/cutest/cutest_radtree.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/radtree.h $(srcdir)/region-allocator.h $(srcdir)/util.h cutest_rbtree.o: $(srcdir)/tpkg/cutest/cutest_rbtree.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h cutest_region.o: $(srcdir)/tpkg/cutest/cutest_region.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h cutest_rrl.o: $(srcdir)/tpkg/cutest/cutest_rrl.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ $(srcdir)/packet.h $(srcdir)/tsig.h cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/bitset.h cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/udb.h cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c config.h $(srcdir)/compat/cpuset.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h \ $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h popen3_echo.o: $(srcdir)/tpkg/cutest/popen3_echo.c qtest.o: $(srcdir)/tpkg/cutest/qtest.c config.h $(srcdir)/compat/cpuset.h $(srcdir)/tpkg/cutest/qtest.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/namedb.h \ $(srcdir)/util.h $(srcdir)/nsec3.h $(srcdir)/options.h $(srcdir)/packet.h $(srcdir)/dname.h $(srcdir)/rdata.h nsd-4.12.0/LICENSE0000644000175000017500000000273715002373054013013 0ustar mozziemozzieCopyright (c) 2001-2006, NLnet Labs. All rights reserved. This software is open source. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the NLNET LABS nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nsd-4.12.0/.readthedocs.yaml0000644000175000017500000000100015002373054015213 0ustar mozziemozzieversion: 2 build: os: ubuntu-22.04 apt_packages: - autoconf - automake - libtool - make - libevent-dev - libssl-dev - flex - bison - mandoc tools: python: "3" jobs: pre_build: - | autoconf && autoheader libtoolize -c -i ./configure --with-libevent=yes --with-libssl=yes make html sphinx: configuration: doc/manual/conf.py python: install: - requirements: doc/manual/requirements.txt submodules: include: all nsd-4.12.0/.gitmodules0000644000175000017500000000013115002373054014145 0ustar mozziemozzie[submodule "simdzone"] path = simdzone url = https://github.com/NLnetLabs/simdzone.git