Merge branch 'feature/rpz' of github.com:ralphdolmans/unbound into feature/rpz

This commit is contained in:
Ralph Dolmans 2019-04-25 14:47:09 +02:00
commit 46acf0f99d
23 changed files with 1010 additions and 48 deletions

16
.travis.yml Normal file
View file

@ -0,0 +1,16 @@
sudo: false
language: c
compiler:
- gcc
addons:
apt:
packages:
- libssl-dev
- libevent-dev
- libexpat-dev
- clang
script:
- ./configure --enable-debug --disable-flto
- make
- make test
- (cd testdata; ../testcode/mini_tdir.sh exe clang-analysis.tdir ; if grep -e "warning:" -e "error:" result.clang-analysis ; then exit 1; else exit 0; fi)

View file

@ -86,6 +86,10 @@
if you don't. */
#undef HAVE_DECL_ARC4RANDOM_UNIFORM
/* Define to 1 if you have the declaration of `evsignal_assign', and to 0 if
you don't. */
#undef HAVE_DECL_EVSIGNAL_ASSIGN
/* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you
don't. */
#undef HAVE_DECL_INET_NTOP
@ -166,6 +170,9 @@
/* 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 `event_assign' function. */
#undef HAVE_EVENT_ASSIGN
/* Define to 1 if you have the `event_base_free' function. */
#undef HAVE_EVENT_BASE_FREE

29
configure vendored
View file

@ -19013,6 +19013,35 @@ _ACEOF
fi
done
# only in libev. (tested on 4.00)
for ac_func in event_assign
do :
ac_fn_c_check_func "$LINENO" "event_assign" "ac_cv_func_event_assign"
if test "x$ac_cv_func_event_assign" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_EVENT_ASSIGN 1
_ACEOF
fi
done
# in libevent, for thread-safety
ac_fn_c_check_decl "$LINENO" "evsignal_assign" "ac_cv_have_decl_evsignal_assign" "$ac_includes_default
#ifdef HAVE_EVENT_H
# include <event.h>
#else
# include \"event2/event.h\"
#endif
"
if test "x$ac_cv_have_decl_evsignal_assign" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_EVSIGNAL_ASSIGN $ac_have_decl
_ACEOF
PC_LIBEVENT_DEPENDENCY="libevent"
if test -n "$BAK_LDFLAGS_SET"; then

View file

@ -1200,6 +1200,14 @@ large outgoing port ranges. ])
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)
AC_CHECK_FUNCS([event_assign]) # in libevent, for thread-safety
AC_CHECK_DECLS([evsignal_assign], [], [], [AC_INCLUDES_DEFAULT
#ifdef HAVE_EVENT_H
# include <event.h>
#else
# include "event2/event.h"
#endif
])
PC_LIBEVENT_DEPENDENCY="libevent"
AC_SUBST(PC_LIBEVENT_DEPENDENCY)
if test -n "$BAK_LDFLAGS_SET"; then

View file

@ -1,3 +1,47 @@
18 April 2019: Ralph
- Scrub RRs from answer section when reusing NXDOMAIN message for
subdomain answers.
- For harden-below-nxdomain: do not consider a name to be non-exitent
when message contains a CNAME record.
18 April 2019: Wouter
- travis build file.
16 April 2019: Wouter
- Better braces in if statement in TCP fastopen code.
- iana portlist updated.
15 April 2019: Wouter
- Fix tls write event for read state change to re-call SSL_write and
not resume the TLS handshake.
11 April 2019: George
- Update python documentation for init_standard().
- Typos.
11 April 2019: Wouter
- Fix that auth zone uses correct network type for sockets for
SOA serial probes. This fixes that probes fail because earlier
probe addresses are unreachable.
- Fix that auth zone fails over to next master for timeout in tcp.
- Squelch SSL read and write connection reset by peer and broken pipe
messages. Verbosity 2 and higher enables them.
8 April 2019: Wouter
- Fix to use event_assign with libevent for thread-safety.
- verbose information about auth zone lookup process, also lookup
start, timeout and fail.
- Fix #17: Add python module example from Jan Janak, that is a
plugin for the Unbound DNS resolver to resolve DNS records in
multicast DNS [RFC 6762] via Avahi. The plugin communicates
with Avahi via DBus. The comment section at the beginning of
the file contains detailed documentation.
- Fix to wipe ssl ticket keys from memory with explicit_bzero,
if available.
5 April 2019: Wouter
- Fix to reinit event structure for accepted TCP (and TLS) sockets.
4 April 2019: Wouter
- Fix spelling error in log output for event method.

View file

@ -828,7 +828,7 @@ Can be given multiple times, for different domains.
.TP
.B qname\-minimisation: \fI<yes or no>
Send minimum amount of information to upstream servers to enhance privacy.
Only sent minimum required labels of the QNAME and set QTYPE to A when
Only send minimum required labels of the QNAME and set QTYPE to A when
possible. Best effort approach; full QNAME and original QTYPE will be sent when
upstream replies with a RCODE other than NOERROR, except when receiving
NXDOMAIN from a DNSSEC signed zone. Default is yes.

View file

@ -1211,6 +1211,19 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
}
}
void
iter_scrub_nxdomain(struct dns_msg* msg)
{
if(msg->rep->an_numrrsets == 0)
return;
memmove(msg->rep->rrsets, msg->rep->rrsets+msg->rep->an_numrrsets,
sizeof(struct ub_packed_rrset_key*) *
(msg->rep->rrset_count-msg->rep->an_numrrsets));
msg->rep->rrset_count -= msg->rep->an_numrrsets;
msg->rep->an_numrrsets = 0;
}
void iter_dec_attempts(struct delegpt* dp, int d)
{
struct delegpt_addr* a;

View file

@ -334,6 +334,13 @@ int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
void iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns,
uint8_t* z);
/**
* Prepare an NXDOMAIN message to be used for a subdomain answer by removing all
* RRs from the ANSWER section.
* @param msg: the response to scrub.
*/
void iter_scrub_nxdomain(struct dns_msg* msg);
/**
* Remove query attempts from all available ips. For 0x20.
* @param dp: delegpt.

View file

@ -2718,8 +2718,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
&& !(iq->chase_flags & BIT_RD)) {
if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
LDNS_RCODE_NOERROR) {
if(qstate->env->cfg->qname_minimisation_strict)
return final_state(iq);
if(qstate->env->cfg->qname_minimisation_strict) {
if(FLAGS_GET_RCODE(iq->response->rep->flags) ==
LDNS_RCODE_NXDOMAIN) {
iter_scrub_nxdomain(iq->response);
return final_state(iq);
}
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
/* Best effort qname-minimisation.
* Stop minimising and send full query when
* RCODE is not NOERROR. */

View file

@ -1,8 +1,11 @@
def init(id, cfg):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
return True
def init_standard(id, env):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, env.cfg.python_script))
return True
def deinit(id):
log_info("pythonmod: deinit called, module id is %d" % id)
return True

View file

@ -54,6 +54,25 @@ Script file must contain four compulsory functions:
return True
.. function:: init_standard(id, env)
Initialize module internals, like database etc.
Called just once on module load.
*Preferred* over the init() function above as this function's signature is the
same as the C counterpart and allows for extra functionality during init.
The previously accessible configuration options can now be found in env.cfg.
:param id: module identifier (integer)
:param env: :class:`module_env` module environment
::
def init_standard(id, env):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, env.cfg.python_script))
return True
.. function:: deinit(id)
Deinitialize module internals.

View file

@ -0,0 +1,567 @@
#!/usr/bin/env python3
#
# A plugin for the Unbound DNS resolver to resolve DNS records in
# multicast DNS [RFC 6762] via Avahi.
#
# Copyright (C) 2018-2019 Internet Real-Time Lab, Columbia University
# http://www.cs.columbia.edu/irt/
#
# Written by Jan Janak <janakj@cs.columbia.edu>
#
# 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.
#
#
# Dependendies:
# Unbound with pythonmodule configured for Python 3
# dnspython [http://www.dnspython.org]
# pydbus [https://github.com/LEW21/pydbus]
#
# To enable Python 3 support, configure Unbound as follows:
# PYTHON_VERSION=3 ./configure --with-pythonmodule
#
# The plugin in meant to be used as a fallback resolver that resolves
# records in multicast DNS if the upstream server cannot be reached or
# provides no answer (NXDOMAIN).
#
# mDNS requests for negative records, i.e., records for which Avahi
# returns no answer (NXDOMAIN), are expensive. Since there is no
# single authoritative server in mDNS, such requests terminate only
# via a timeout. The timeout is about a second (if MDNS_TIMEOUT is not
# configured), or the value configured via MDNS_TIMEOUT. The
# corresponding Unbound thread will be blocked for this amount of
# time. For this reason, it is important to configure an appropriate
# number of threads in unbound.conf and limit the RR types and names
# that will be resolved via Avahi via the environment variables
# described later.
#
# An example unbound.conf with the plugin enabled:
#
# | server:
# | module-config: "validator python iterator"
# | num-threads: 32
# | cache-max-negative-ttl: 60
# | cache-max-ttl: 60
#
#
# The plugin can also be run interactively. Provide the name and
# record type to be resolved as command line arguments and the
# resolved record will be printed to standard output:
#
# $ ./avahi-resolver.py voip-phx4.phxnet.org A
# voip-phx4.phxnet.org. 120 IN A 10.4.3.2
#
#
# The behavior of the plugin can be controlled via the following
# environment variables:
#
# DBUS_SYSTEM_BUS_ADDRESS
#
# The address of the system DBus bus, in the format expected by DBus,
# e.g., unix:path=/run/avahi/system-bus.sock
#
#
# DEBUG
#
# Set this environment variable to "yes", "true", "on", or "1" to
# enable debugging. In debugging mode, the plugin will output a lot
# more information about what it is doing either to the standard
# output (when run interactively) or to Unbound via log_info and
# log_error.
#
# By default debugging is disabled.
#
#
# MDNS_TTL
#
# Avahi does not provide the TTL value for the records it returns.
# This environment variable can be used to configure the TTL value for
# such records.
#
# The default value is 120 seconds.
#
#
# MDNS_TIMEOUT
#
# The maximum amount of time (in milliseconds) an Avahi request is
# allowed to run. This value sets the time it takes to resolve
# negative (non-existent) records in Avahi. If unset, the request
# terminates when Avahi sends the "AllForNow" signal, telling the
# client that more records are unlikely to arrive. This takes roughly
# about one second. You may need to configure a longer value here on
# slower networks, e.g., networks that relay mDNS packets such as
# MANETs.
#
#
# MDNS_GETONE
#
# If set to "true", "1", or "on", an Avahi request will terminate as
# soon as at least one record has been found. If there are multiple
# nodes in the mDNS network publishing the same record, only one (or
# subset) will be returned.
#
# If set to "false", "0", or "off", the plugin will gather records for
# MDNS_TIMEOUT and return all records found. This is only useful in
# networks where multiple nodes are known to publish different records
# under the same name and the client needs to be able to obtain them
# all. When configured this way, all Avahi requests will always take
# MDNS_TIMEOUT to complete!
#
# This option is set to true by default.
#
#
# MDNS_REJECT_TYPES
#
# A comma-separated list of record types that will NOT be resolved in
# mDNS via Avahi. Use this environment variable to prevent specific
# record types from being resolved via Avahi. For example, if your
# network does not support IPv6, you can put AAAA on this list.
#
# The default value is an empty list.
#
# Example: MDNS_REJECT_TYPES=aaaa,mx,soa
#
#
# MDNS_ACCEPT_TYPES
#
# If set, a record type will be resolved via Avahi if and only if it
# is present on this comma-separated list. In other words, this is a
# whitelist.
#
# The default value is an empty list which means all record types will
# be resolved via Avahi.
#
# Example: MDNS_ACCEPT_TYPES=a,ptr,txt,srv,aaaa,cname
#
#
# MDNS_REJECT_NAMES
#
# If the name being resolved matches the regular expression in this
# environment variable, the name will NOT be resolved via Avahi. In
# other words, this environment variable provides a blacklist.
#
# The default value is empty--no names will be reject.
#
# Example: MDNS_REJECT_NAMES=(^|\.)example\.com\.$
#
#
# MDNS_ACCEPT_NAMES
#
# If set to a regular expression, a name will be resolved via Avahi if
# and only if it matches the regular expression. In other words, this
# variable provides a whitelist.
#
# The default value is empty--all names will be resolved via Avahi.
#
# Example: MDNS_ACCEPT_NAMES=^.*\.example\.com\.$
#
import os
import re
import array
import threading
import traceback
import dns.rdata
import dns.rdatatype
import dns.rdataclass
from queue import Queue
from gi.repository import GLib
from pydbus import SystemBus
IF_UNSPEC = -1
PROTO_UNSPEC = -1
sysbus = None
avahi = None
trampoline = dict()
thread_local = threading.local()
dbus_thread = None
dbus_loop = None
def str2bool(v):
if v.lower() in ['false', 'no', '0', 'off', '']:
return False
return True
def dbg(msg):
if DEBUG != False:
log_info('avahi-resolver: %s' % msg)
#
# Although pydbus has an internal facility for handling signals, we
# cannot use that with Avahi. When responding from an internal cache,
# Avahi sends the first signal very quickly, before pydbus has had a
# chance to subscribe for the signal. This will result in lost signal
# and missed data:
#
# https://github.com/LEW21/pydbus/issues/87
#
# As a workaround, we subscribe to all signals before creating a
# record browser and do our own signal matching and dispatching via
# the following function.
#
def signal_dispatcher(connection, sender, path, interface, name, args):
o = trampoline.get(path, None)
if o is None:
return
if name == 'ItemNew': o.itemNew(*args)
elif name == 'ItemRemove': o.itemRemove(*args)
elif name == 'AllForNow': o.allForNow(*args)
elif name == 'Failure': o.failure(*args)
class RecordBrowser:
def __init__(self, callback, name, type_, timeout=None, getone=True):
self.callback = callback
self.records = []
self.error = None
self.getone = getone
self.timer = None if timeout is None else GLib.timeout_add(timeout, self.timedOut)
self.browser_path = avahi.RecordBrowserNew(IF_UNSPEC, PROTO_UNSPEC, name, dns.rdataclass.IN, type_, 0)
trampoline[self.browser_path] = self
self.browser = sysbus.get('.Avahi', self.browser_path)
self.dbg('Created RecordBrowser(name=%s, type=%s, getone=%s, timeout=%s)'
% (name, dns.rdatatype.to_text(type_), getone, timeout))
def dbg(self, msg):
dbg('[%s] %s' % (self.browser_path, msg))
def _done(self):
del trampoline[self.browser_path]
self.dbg('Freeing')
self.browser.Free()
if self.timer is not None:
self.dbg('Removing timer')
GLib.source_remove(self.timer)
self.callback(self.records, self.error)
def itemNew(self, interface, protocol, name, class_, type_, rdata, flags):
self.dbg('Got signal ItemNew')
self.records.append((name, class_, type_, rdata))
if self.getone:
self._done()
def itemRemove(self, interface, protocol, name, class_, type_, rdata, flags):
self.dbg('Got signal ItemRemove')
self.records.remove((name, class_, type_, rdata))
def failure(self, error):
self.dbg('Got signal Failure')
self.error = Exception(error)
self._done()
def allForNow(self):
self.dbg('Got signal AllForNow')
if self.timer is None:
self._done()
def timedOut(self):
self.dbg('Timed out')
self._done()
return False
#
# This function runs the main event loop for DBus (GLib). This
# function must be run in a dedicated worker thread.
#
def dbus_main():
global sysbus, avahi, dbus_loop
dbg('Connecting to system DBus')
sysbus = SystemBus()
dbg('Subscribing to .Avahi.RecordBrowser signals')
sysbus.con.signal_subscribe('org.freedesktop.Avahi',
'org.freedesktop.Avahi.RecordBrowser',
None, None, None, 0, signal_dispatcher)
avahi = sysbus.get('.Avahi', '/')
dbg("Connected to Avahi Daemon: %s (API %s) [%s]"
% (avahi.GetVersionString(), avahi.GetAPIVersion(), avahi.GetHostNameFqdn()))
dbg('Starting DBus main loop')
dbus_loop = GLib.MainLoop()
dbus_loop.run()
#
# This function must be run in the DBus worker thread. It creates a
# new RecordBrowser instance and once it has finished doing it thing,
# it will send the result back to the original thread via the queue.
#
def start_resolver(queue, *args, **kwargs):
try:
RecordBrowser(lambda *v: queue.put_nowait(v), *args, **kwargs)
except Exception as e:
queue.put_nowait((None, e))
return False
#
# To resolve a request, we setup a queue, post a task to the DBus
# worker thread, and wait for the result (or error) to arrive over the
# queue. If the worker thread reports an error, raise the error as an
# exception.
#
def resolve(*args, **kwargs):
try:
queue = thread_local.queue
except AttributeError:
dbg('Creating new per-thread queue')
queue = Queue()
thread_local.queue = queue
GLib.idle_add(lambda: start_resolver(queue, *args, **kwargs))
records, error = queue.get()
queue.task_done()
if error is not None:
raise error
return records
def parse_type_list(lst):
return list(map(dns.rdatatype.from_text, [v.strip() for v in lst.split(',') if len(v)]))
def init(*args, **kwargs):
global dbus_thread, DEBUG
global MDNS_TTL, MDNS_GETONE, MDNS_TIMEOUT
global MDNS_REJECT_TYPES, MDNS_ACCEPT_TYPES
global MDNS_REJECT_NAMES, MDNS_ACCEPT_NAMES
DEBUG = str2bool(os.environ.get('DEBUG', str(False)))
MDNS_TTL = int(os.environ.get('MDNS_TTL', 120))
dbg("TTL for records from Avahi: %d" % MDNS_TTL)
MDNS_REJECT_TYPES = parse_type_list(os.environ.get('MDNS_REJECT_TYPES', ''))
if MDNS_REJECT_TYPES:
dbg('Types NOT resolved via Avahi: %s' % MDNS_REJECT_TYPES)
MDNS_ACCEPT_TYPES = parse_type_list(os.environ.get('MDNS_ACCEPT_TYPES', ''))
if MDNS_ACCEPT_TYPES:
dbg('ONLY resolving the following types via Avahi: %s' % MDNS_ACCEPT_TYPES)
v = os.environ.get('MDNS_REJECT_NAMES', None)
MDNS_REJECT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
if MDNS_REJECT_NAMES is not None:
dbg('Names NOT resolved via Avahi: %s' % MDNS_REJECT_NAMES.pattern)
v = os.environ.get('MDNS_ACCEPT_NAMES', None)
MDNS_ACCEPT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
if MDNS_ACCEPT_NAMES is not None:
dbg('ONLY resolving the following names via Avahi: %s' % MDNS_ACCEPT_NAMES.pattern)
v = os.environ.get('MDNS_TIMEOUT', None)
MDNS_TIMEOUT = int(v) if v is not None else None
if MDNS_TIMEOUT is not None:
dbg('Avahi request timeout: %s' % MDNS_TIMEOUT)
MDNS_GETONE = str2bool(os.environ.get('MDNS_GETONE', str(True)))
dbg('Terminate Avahi requests on first record: %s' % MDNS_GETONE)
dbus_thread = threading.Thread(target=dbus_main)
dbus_thread.daemon = True
dbus_thread.start()
def deinit(*args, **kwargs):
dbus_loop.quit()
dbus_thread.join()
return True
def inform_super(id, qstate, superqstate, qdata):
return True
def get_rcode(msg):
if not msg:
return RCODE_SERVFAIL
return msg.rep.flags & 0xf
def rr2text(rec, ttl):
name, class_, type_, rdata = rec
wire = array.array('B', rdata).tostring()
return '%s. %d %s %s %s' % (
name,
ttl,
dns.rdataclass.to_text(class_),
dns.rdatatype.to_text(type_),
dns.rdata.from_wire(class_, type_, wire, 0, len(wire), None))
def operate(id, event, qstate, qdata):
qi = qstate.qinfo
name = qi.qname_str
type_ = qi.qtype
type_str = dns.rdatatype.to_text(type_)
class_ = qi.qclass
class_str = dns.rdataclass.to_text(class_)
rc = get_rcode(qstate.return_msg)
if event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS:
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
if event != MODULE_EVENT_MODDONE:
log_err("avahi-resolver: Unexpected event %d" % event)
qstate.ext_state[id] = MODULE_ERROR
return True
qstate.ext_state[id] = MODULE_FINISHED
# Only resolve via Avahi if we got NXDOMAIn from the upstream DNS
# server, or if we could not reach the upstream DNS server. If we
# got some records for the name from the upstream DNS server
# already, do not resolve the record in Avahi.
if rc != RCODE_NXDOMAIN and rc != RCODE_SERVFAIL:
return True
dbg("Got request for '%s %s %s'" % (name, class_str, type_str))
# Avahi only supports the IN class
if class_ != RR_CLASS_IN:
dbg('Rejected, Avahi only supports the IN class')
return True
# Avahi does not support meta queries (e.g., ANY)
if dns.rdatatype.is_metatype(type_):
dbg('Rejected, Avahi does not support the type %s' % type_str)
return True
# If we have a type blacklist and the requested type is on the
# list, reject it.
if MDNS_REJECT_TYPES and type_ in MDNS_REJECT_TYPES:
dbg('Rejected, type %s is on the blacklist' % type_str)
return True
# If we have a type whitelist and if the requested type is not on
# the list, reject it.
if MDNS_ACCEPT_TYPES and type_ not in MDNS_ACCEPT_TYPES:
dbg('Rejected, type %s is not on the whitelist' % type_str)
return True
# If we have a name blacklist and if the requested name matches
# the blacklist, reject it.
if MDNS_REJECT_NAMES is not None:
if MDNS_REJECT_NAMES.search(name):
dbg('Rejected, name %s is on the blacklist' % name)
return True
# If we have a name whitelist and if the requested name does not
# match the whitelist, reject it.
if MDNS_ACCEPT_NAMES is not None:
if not MDNS_ACCEPT_NAMES.search(name):
dbg('Rejected, name %s is not on the whitelist' % name)
return True
dbg("Resolving '%s %s %s' via Avahi" % (name, class_str, type_str))
recs = resolve(name, type_, getone=MDNS_GETONE, timeout=MDNS_TIMEOUT)
if not recs:
dbg('Result: Not found (NXDOMAIN)')
qstate.return_rcode = RCODE_NXDOMAIN
return True
m = DNSMessage(name, type_, class_, PKT_QR | PKT_RD | PKT_RA)
for r in recs:
s = rr2text(r, MDNS_TTL)
dbg('Result: %s' % s)
m.answer.append(s)
if not m.set_return_msg(qstate):
raise Exception("Error in set_return_msg")
if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
raise Exception("Error in storeQueryInCache")
qstate.return_msg.rep.security = 2
qstate.return_rcode = RCODE_NOERROR
return True
#
# It does not appear to be sufficient to check __name__ to determine
# whether we are being run in interactive mode. As a workaround, try
# to import module unboundmodule and if that fails, assume we're being
# run in interactive mode.
#
try:
import unboundmodule
embedded = True
except ImportError:
embedded = False
if __name__ == '__main__' and not embedded:
import sys
def log_info(msg):
print(msg)
def log_err(msg):
print('ERROR: %s' % msg, file=sys.stderr)
if len(sys.argv) != 3:
print('Usage: %s <name> <rr_type>' % sys.argv[0])
sys.exit(2)
name = sys.argv[1]
type_str = sys.argv[2]
try:
type_ = dns.rdatatype.from_text(type_str)
except dns.rdatatype.UnknownRdatatype:
log_err('Unsupported DNS record type "%s"' % type_str)
sys.exit(2)
if dns.rdatatype.is_metatype(type_):
log_err('Meta record type "%s" cannot be resolved via Avahi' % type_str)
sys.exit(2)
init()
try:
recs = resolve(name, type_, getone=MDNS_GETONE, timeout=MDNS_TIMEOUT)
if not len(recs):
print('%s not found (NXDOMAIN)' % name)
sys.exit(1)
for r in recs:
print(rr2text(r, MDNS_TTL))
finally:
deinit()

View file

@ -78,7 +78,7 @@ def init_standard(id, env):
extra functionality during init.
..note:: This function is preferred by unbound over the old init function.
..note:: The previously accessible configuration options can now be found in
env.cgf.
env.cfg.
"""
log_info("python: inited script {}".format(env.cfg.python_script))

View file

@ -275,7 +275,7 @@ def init_standard(id, env):
..note:: This function is preferred by unbound over the old init function.
..note:: The previously accessible configuration options can now be found in
env.cgf.
env.cfg.
"""
log_info("python: inited script {}".format(env.cfg.python_script))

View file

@ -2014,11 +2014,13 @@ auth_xfer_delete(struct auth_xfer* xfr)
if(xfr->task_probe) {
auth_free_masters(xfr->task_probe->masters);
comm_point_delete(xfr->task_probe->cp);
comm_timer_delete(xfr->task_probe->timer);
free(xfr->task_probe);
}
if(xfr->task_transfer) {
auth_free_masters(xfr->task_transfer->masters);
comm_point_delete(xfr->task_transfer->cp);
comm_timer_delete(xfr->task_transfer->timer);
if(xfr->task_transfer->chunks_first) {
auth_chunks_delete(xfr->task_transfer);
}
@ -4953,6 +4955,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
static void
xfr_transfer_disown(struct auth_xfer* xfr)
{
/* remove timer (from this worker's event base) */
comm_timer_delete(xfr->task_transfer->timer);
xfr->task_transfer->timer = NULL;
/* remove the commpoint */
comm_point_delete(xfr->task_transfer->cp);
xfr->task_transfer->cp = NULL;
@ -5034,6 +5039,8 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
struct sockaddr_storage addr;
socklen_t addrlen = 0;
struct auth_master* master = xfr->task_transfer->master;
struct timeval t;
int timeout;
if(!master) return 0;
if(master->allow_notify) return 0; /* only for notify */
@ -5059,25 +5066,46 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
comm_point_delete(xfr->task_transfer->cp);
xfr->task_transfer->cp = NULL;
}
if(!xfr->task_transfer->timer) {
xfr->task_transfer->timer = comm_timer_create(env->worker_base,
auth_xfer_transfer_timer_callback, xfr);
if(!xfr->task_transfer->timer) {
log_err("malloc failure");
return 0;
}
}
timeout = AUTH_TRANSFER_TIMEOUT;
#ifndef S_SPLINT_S
t.tv_sec = timeout/1000;
t.tv_usec = (timeout%1000)*1000;
#endif
if(master->http) {
/* perform http fetch */
/* store http port number into sockaddr,
* unless someone used unbound's host@port notation */
xfr->task_transfer->on_ixfr = 0;
if(strchr(master->host, '@') == NULL)
sockaddr_store_port(&addr, addrlen, master->port);
xfr->task_transfer->cp = outnet_comm_point_for_http(
env->outnet, auth_xfer_transfer_http_callback, xfr,
&addr, addrlen, AUTH_TRANSFER_TIMEOUT, master->ssl,
master->host, master->file);
&addr, addrlen, -1, master->ssl, master->host,
master->file);
if(!xfr->task_transfer->cp) {
char zname[255+1];
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "cannot create http cp "
"connection for %s to %s", zname,
master->host);
"connection for %s to %s", zname, as);
return 0;
}
comm_timer_set(xfr->task_transfer->timer, &t);
if(verbosity >= VERB_ALGO) {
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "auth zone %s transfer next HTTP fetch from %s started", zname, as);
}
return 1;
}
@ -5091,14 +5119,23 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
/* connect on fd */
xfr->task_transfer->cp = outnet_comm_point_for_tcp(env->outnet,
auth_xfer_transfer_tcp_callback, xfr, &addr, addrlen,
env->scratch_buffer, AUTH_TRANSFER_TIMEOUT);
env->scratch_buffer, -1);
if(!xfr->task_transfer->cp) {
char zname[255+1];
dname_str(xfr->name, zname);
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "cannot create tcp cp connection for "
"xfr %s to %s", zname, master->host);
"xfr %s to %s", zname, as);
return 0;
}
comm_timer_set(xfr->task_transfer->timer, &t);
if(verbosity >= VERB_ALGO) {
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "auth zone %s transfer next %s fetch from %s started", zname,
(xfr->task_transfer->on_ixfr?"IXFR":"AXFR"), as);
}
return 1;
}
@ -5116,6 +5153,11 @@ xfr_transfer_nexttarget_or_end(struct auth_xfer* xfr, struct module_env* env)
* and we may then get an instant cache response,
* and that calls the callback just like a full
* lookup and lookup failures also call callback */
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s transfer next target lookup", zname);
}
lock_basic_unlock(&xfr->lock);
return;
}
@ -5134,6 +5176,11 @@ xfr_transfer_nexttarget_or_end(struct auth_xfer* xfr, struct module_env* env)
/* failed to fetch, next master */
xfr_transfer_nextmaster(xfr);
}
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s transfer failed, wait", zname);
}
/* we failed to fetch the zone, move to wait task
* use the shorter retry timeout */
@ -5231,7 +5278,25 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
if(answer) {
xfr_master_add_addrs(xfr->task_transfer->
lookup_target, answer, wanted_qtype);
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
}
}
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
}
}
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
}
}
if(xfr->task_transfer->lookup_target->list &&
@ -5616,6 +5681,46 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
xfr_transfer_nexttarget_or_end(xfr, env);
}
/** callback for the task_transfer timer */
void
auth_xfer_transfer_timer_callback(void* arg)
{
struct auth_xfer* xfr = (struct auth_xfer*)arg;
struct module_env* env;
int gonextonfail = 1;
log_assert(xfr->task_transfer);
lock_basic_lock(&xfr->lock);
env = xfr->task_transfer->env;
if(env->outnet->want_to_quit) {
lock_basic_unlock(&xfr->lock);
return; /* stop on quit */
}
verbose(VERB_ALGO, "xfr stopped, connection timeout to %s",
xfr->task_transfer->master->host);
/* see if IXFR caused the failure, if so, try AXFR */
if(xfr->task_transfer->on_ixfr) {
xfr->task_transfer->ixfr_possible_timeout_count++;
if(xfr->task_transfer->ixfr_possible_timeout_count >=
NUM_TIMEOUTS_FALLBACK_IXFR) {
verbose(VERB_ALGO, "xfr to %s, fallback "
"from IXFR to AXFR (because of timeouts)",
xfr->task_transfer->master->host);
xfr->task_transfer->ixfr_fail = 1;
gonextonfail = 0;
}
}
/* delete transferred data from list */
auth_chunks_delete(xfr->task_transfer);
comm_point_delete(xfr->task_transfer->cp);
xfr->task_transfer->cp = NULL;
if(gonextonfail)
xfr_transfer_nextmaster(xfr);
xfr_transfer_nexttarget_or_end(xfr, env);
}
/** callback for task_transfer tcp connections */
int
auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
@ -5632,6 +5737,8 @@ auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
lock_basic_unlock(&xfr->lock);
return 0; /* stop on quit */
}
/* stop the timer */
comm_timer_disable(xfr->task_transfer->timer);
if(err != NETEVENT_NOERROR) {
/* connection failed, closed, or timeout */
@ -5712,6 +5819,8 @@ auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
return 0; /* stop on quit */
}
verbose(VERB_ALGO, "auth zone transfer http callback");
/* stop the timer */
comm_timer_disable(xfr->task_transfer->timer);
if(err != NETEVENT_NOERROR && err != NETEVENT_DONE) {
/* connection failed, closed, or timeout */
@ -5838,14 +5947,26 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
xfr->task_probe->id = (uint16_t)(ub_random(env->rnd)&0xffff);
xfr_create_soa_probe_packet(xfr, env->scratch_buffer,
xfr->task_probe->id);
/* we need to remove the cp if we have a different ip4/ip6 type now */
if(xfr->task_probe->cp &&
((xfr->task_probe->cp_is_ip6 && !addr_is_ip6(&addr, addrlen)) ||
(!xfr->task_probe->cp_is_ip6 && addr_is_ip6(&addr, addrlen)))
) {
comm_point_delete(xfr->task_probe->cp);
xfr->task_probe->cp = NULL;
}
if(!xfr->task_probe->cp) {
if(addr_is_ip6(&addr, addrlen))
xfr->task_probe->cp_is_ip6 = 1;
else xfr->task_probe->cp_is_ip6 = 0;
xfr->task_probe->cp = outnet_comm_point_for_udp(env->outnet,
auth_xfer_probe_udp_callback, xfr, &addr, addrlen);
if(!xfr->task_probe->cp) {
char zname[255+1];
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "cannot create udp cp for "
"probe %s to %s", zname, master->host);
"probe %s to %s", zname, as);
return 0;
}
}
@ -5861,12 +5982,20 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
/* send udp packet */
if(!comm_point_send_udp_msg(xfr->task_probe->cp, env->scratch_buffer,
(struct sockaddr*)&addr, addrlen)) {
char zname[255+1];
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "failed to send soa probe for %s to %s",
zname, master->host);
zname, as);
return 0;
}
if(verbosity >= VERB_ALGO) {
char zname[255+1], as[256];
dname_str(xfr->name, zname);
addr_to_str(&addr, addrlen, as, sizeof(as));
verbose(VERB_ALGO, "auth zone %s soa probe sent to %s", zname,
as);
}
xfr->task_probe->timeout = timeout;
#ifndef S_SPLINT_S
t.tv_sec = timeout/1000;
@ -5891,6 +6020,11 @@ auth_xfer_probe_timer_callback(void* arg)
return; /* stop on quit */
}
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s soa probe timeout", zname);
}
if(xfr->task_probe->timeout <= AUTH_PROBE_TIMEOUT_STOP) {
/* try again with bigger timeout */
if(xfr_probe_send_probe(xfr, env, xfr->task_probe->timeout*2)) {
@ -6078,6 +6212,11 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
* and we may then get an instant cache response,
* and that calls the callback just like a full
* lookup and lookup failures also call callback */
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s probe next target lookup", zname);
}
lock_basic_unlock(&xfr->lock);
return;
}
@ -6086,9 +6225,19 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
/* probe of list has ended. Create or refresh the list of of
* allow_notify addrs */
probe_copy_masters_for_allow_notify(xfr);
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s probe: notify addrs updated", zname);
}
if(xfr->task_probe->only_lookup) {
/* only wanted lookups for copy, stop probe and start wait */
xfr->task_probe->only_lookup = 0;
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname);
}
xfr_probe_disown(xfr);
if(xfr->task_nextprobe->worker == NULL)
xfr_set_timeout(xfr, env, 0, 0);
@ -6110,13 +6259,22 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
/* done with probe sequence, wait */
if(xfr->task_probe->have_new_lease) {
/* if zone not updated, start the wait timer again */
verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait");
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth_zone %s unchanged, new lease, wait", zname);
}
xfr_probe_disown(xfr);
if(xfr->have_zone)
xfr->lease_time = *env->now;
if(xfr->task_nextprobe->worker == NULL)
xfr_set_timeout(xfr, env, 0, 0);
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s soa probe failed, wait to retry", zname);
}
/* we failed to send this as well, move to the wait task,
* use the shorter retry timeout */
xfr_probe_disown(xfr);
@ -6161,7 +6319,25 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
if(answer) {
xfr_master_add_addrs(xfr->task_probe->
lookup_target, answer, wanted_qtype);
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
}
}
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
}
}
} else {
if(verbosity >= VERB_ALGO) {
char zname[255+1];
dname_str(xfr->name, zname);
verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
}
}
if(xfr->task_probe->lookup_target->list &&

View file

@ -335,6 +335,8 @@ struct auth_probe {
/** the SOA probe udp event.
* on the workers event base. */
struct comm_point* cp;
/** is the cp for ip6 or ip4 */
int cp_is_ip6;
/** timeout for packets.
* on the workers event base. */
struct comm_timer* timer;
@ -406,6 +408,9 @@ struct auth_transfer {
/** the transfer (TCP) to the master.
* on the workers event base. */
struct comm_point* cp;
/** timeout for the transfer.
* on the workers event base. */
struct comm_timer* timer;
};
/** list of addresses */
@ -655,6 +660,8 @@ int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
struct comm_reply* repinfo);
/** xfer probe timeout callback, part of task_probe */
void auth_xfer_probe_timer_callback(void* arg);
/** xfer transfer timeout callback, part of task_transfer */
void auth_xfer_transfer_timer_callback(void* arg);
/** mesh callback for task_probe on lookup of host names */
void auth_xfer_probe_lookup_callback(void* arg, int rcode,
struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,

View file

@ -40,6 +40,7 @@
*/
#include "config.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iter_utils.h"
#include "validator/val_nsec.h"
#include "validator/val_utils.h"
#include "services/cache/dns.h"
@ -914,12 +915,15 @@ dns_cache_lookup(struct module_env* env,
struct dns_msg* msg;
if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
&& data->security == sec_status_secure
&& (data->an_numrrsets == 0 ||
ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
&& (msg=tomsg(env, &k, data, region, now, scratch))){
lock_rw_unlock(&e->lock);
msg->qinfo.qname=qname;
msg->qinfo.qname_len=qnamelen;
/* check that DNSSEC really works out */
msg->rep->security = sec_status_unchecked;
iter_scrub_nxdomain(msg);
return msg;
}
lock_rw_unlock(&e->lock);

View file

@ -851,13 +851,16 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
#ifdef ENOPROTOOPT
/* squelch ENOPROTOOPT: freebsd server mode with kernel support
disabled, except when verbosity enabled for debugging */
if(errno != ENOPROTOOPT || verbosity >= 3)
if(errno != ENOPROTOOPT || verbosity >= 3) {
#endif
if(errno == EPERM) {
log_warn("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));
} else {
log_err("Setting TCP Fast Open as server failed: %s", strerror(errno));
}
#ifdef ENOPROTOOPT
}
#endif
}
#endif
return s;

View file

@ -157,7 +157,7 @@ struct reply_info {
time_t prefetch_ttl;
/**
* Reply TTL extended with serve exipred TTL, to limit time to serve
* Reply TTL extended with serve expired TTL, to limit time to serve
* expired message.
*/
time_t serve_expired_ttl;

View file

@ -127,6 +127,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
#endif
else if(fptr == &auth_xfer_timer) return 1;
else if(fptr == &auth_xfer_probe_timer_callback) return 1;
else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
return 0;
}

View file

@ -1245,7 +1245,12 @@ listen_sslctx_delete_ticket_keys(void)
struct tls_session_ticket_key *key;
if(!ticket_keys) return;
for(key = ticket_keys; key->key_name != NULL; key++) {
memset(key->key_name, 0xdd, 80); /* wipe key data from memory*/
/* wipe key data from memory*/
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(key->key_name, 80);
#else
memset(key->key_name, 0xdd, 80);
#endif
free(key->key_name);
}
free(ticket_keys);

View file

@ -926,6 +926,14 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
}
/* accept incoming connection. */
c_hdl = c->tcp_free;
/* clear leftover flags from previous use, and then set the
* correct event base for the event structure for libevent */
ub_event_free(c_hdl->ev->ev);
c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1, UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT, comm_point_tcp_handle_callback, c_hdl);
if(!c_hdl->ev->ev) {
log_warn("could not ub_event_new, dropped tcp");
return;
}
log_assert(fd != -1);
(void)fd;
new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
@ -1184,6 +1192,10 @@ ssl_handle_read(struct comm_point* c)
comm_point_listen_for_rw(c, 0, 1);
return 1;
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef ECONNRESET
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
if(errno != 0)
log_err("SSL_read syscall: %s",
strerror(errno));
@ -1228,6 +1240,10 @@ ssl_handle_read(struct comm_point* c)
comm_point_listen_for_rw(c, 0, 1);
return 1;
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef ECONNRESET
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
if(errno != 0)
log_err("SSL_read syscall: %s",
strerror(errno));
@ -1288,13 +1304,17 @@ ssl_handle_write(struct comm_point* c)
if(want == SSL_ERROR_ZERO_RETURN) {
return 0; /* closed */
} else if(want == SSL_ERROR_WANT_READ) {
c->ssl_shake_state = comm_ssl_shake_read;
c->ssl_shake_state = comm_ssl_shake_hs_read;
comm_point_listen_for_rw(c, 1, 0);
return 1; /* wait for read condition */
} else if(want == SSL_ERROR_WANT_WRITE) {
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
return 1; /* write more later */
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
if(errno == EPIPE && verbosity < 2)
return 0; /* silence 'broken pipe' */
#endif
if(errno != 0)
log_err("SSL_write syscall: %s",
strerror(errno));
@ -1322,13 +1342,17 @@ ssl_handle_write(struct comm_point* c)
if(want == SSL_ERROR_ZERO_RETURN) {
return 0; /* closed */
} else if(want == SSL_ERROR_WANT_READ) {
c->ssl_shake_state = comm_ssl_shake_read;
c->ssl_shake_state = comm_ssl_shake_hs_read;
comm_point_listen_for_rw(c, 1, 0);
return 1; /* wait for read condition */
} else if(want == SSL_ERROR_WANT_WRITE) {
ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
return 1; /* write more later */
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
if(errno == EPIPE && verbosity < 2)
return 0; /* silence 'broken pipe' */
#endif
if(errno != 0)
log_err("SSL_write syscall: %s",
strerror(errno));
@ -1738,6 +1762,16 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
}
#endif
if(event&UB_EV_TIMEOUT) {
verbose(VERB_QUERY, "tcp took too long, dropped");
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(c->callback));
(void)(*c->callback)(c, c->cb_arg,
NETEVENT_TIMEOUT, NULL);
}
return;
}
if(event&UB_EV_READ) {
int has_tcpq = (c->tcp_req_info != NULL);
if(!comm_point_tcp_handle_read(fd, c, 0)) {
@ -1768,16 +1802,6 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
tcp_req_info_read_again(fd, c);
return;
}
if(event&UB_EV_TIMEOUT) {
verbose(VERB_QUERY, "tcp took too long, dropped");
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(c->callback));
(void)(*c->callback)(c, c->cb_arg,
NETEVENT_TIMEOUT, NULL);
}
return;
}
log_err("Ignored event %d for tcphdl.", event);
}
@ -1826,6 +1850,10 @@ ssl_http_read_more(struct comm_point* c)
comm_point_listen_for_rw(c, 0, 1);
return 1;
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef ECONNRESET
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
if(errno != 0)
log_err("SSL_read syscall: %s",
strerror(errno));
@ -2268,12 +2296,16 @@ ssl_http_write_more(struct comm_point* c)
if(want == SSL_ERROR_ZERO_RETURN) {
return 0; /* closed */
} else if(want == SSL_ERROR_WANT_READ) {
c->ssl_shake_state = comm_ssl_shake_read;
c->ssl_shake_state = comm_ssl_shake_hs_read;
comm_point_listen_for_rw(c, 1, 0);
return 1; /* wait for read condition */
} else if(want == SSL_ERROR_WANT_WRITE) {
return 1; /* write more later */
} else if(want == SSL_ERROR_SYSCALL) {
#ifdef EPIPE
if(errno == EPIPE && verbosity < 2)
return 0; /* silence 'broken pipe' */
#endif
if(errno != 0)
log_err("SSL_write syscall: %s",
strerror(errno));
@ -2382,6 +2414,16 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
log_assert(c->type == comm_http);
ub_comm_base_now(c->ev->base);
if(event&UB_EV_TIMEOUT) {
verbose(VERB_QUERY, "http took too long, dropped");
reclaim_http_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(c->callback));
(void)(*c->callback)(c, c->cb_arg,
NETEVENT_TIMEOUT, NULL);
}
return;
}
if(event&UB_EV_READ) {
if(!comm_point_http_handle_read(fd, c)) {
reclaim_http_handler(c);
@ -2406,16 +2448,6 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
}
return;
}
if(event&UB_EV_TIMEOUT) {
verbose(VERB_QUERY, "http took too long, dropped");
reclaim_http_handler(c);
if(!c->tcp_do_close) {
fptr_ok(fptr_whitelist_comm_point(c->callback));
(void)(*c->callback)(c, c->cb_arg,
NETEVENT_TIMEOUT, NULL);
}
return;
}
log_err("Ignored event %d for httphdl.", event);
}
@ -3138,8 +3170,8 @@ comm_point_stop_listening(struct comm_point* c)
void
comm_point_start_listening(struct comm_point* c, int newfd, int msec)
{
verbose(VERB_ALGO, "comm point start listening %d",
c->fd==-1?newfd:c->fd);
verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
c->fd==-1?newfd:c->fd, msec);
if(c->type == comm_tcp_accept && !c->tcp_free) {
/* no use to start listening no free slots. */
return;

View file

@ -295,11 +295,18 @@ ub_event_new(struct ub_event_base* base, int fd, short bits,
if (!ev)
return NULL;
#ifndef HAVE_EVENT_ASSIGN
event_set(ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg);
if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
free(ev);
return NULL;
}
#else
if (event_assign(ev, AS_EVENT_BASE(base), fd, bits, cb, arg) != 0) {
free(ev);
return NULL;
}
#endif
return AS_UB_EVENT(ev);
}
@ -312,11 +319,18 @@ ub_signal_new(struct ub_event_base* base, int fd,
if (!ev)
return NULL;
#if !HAVE_DECL_EVSIGNAL_ASSIGN
signal_set(ev, fd, NATIVE_BITS_CB(cb), arg);
if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
free(ev);
return NULL;
}
#else
if (evsignal_assign(ev, AS_EVENT_BASE(base), fd, cb, arg) != 0) {
free(ev);
return NULL;
}
#endif
return AS_UB_EVENT(ev);
}