Imported Upstream version 0.9.0
Ondřej Surý
8 years ago
0 | * 2015-12-31: Version 0.9.0 | |
1 | * Update of unofficial extension to the API that supports stub mode | |
2 | TLS verification. GETDNS_AUTHENTICATION_HOSTNAME is replaced by | |
3 | GETDNS_AUTHENTICATION_REQUIRED (but remains available as an alias). | |
4 | Upstreams can now be configured with either a hostname or a SPKI pinset | |
5 | for TLS authentication (or both). If the GETDNS_AUTHENTICATION_REQUIRED | |
6 | option is used at least one piece of authentication information must be | |
7 | configured for each upstream, and all the configured authentication | |
8 | information for an upstream must validate. | |
9 | * Remove STARTTLS implementation (no change to SPEC) | |
10 | * Enable TCP Fast Open when possible. Add OSX support for TFO. | |
11 | * Rename return_call_debugging to return_call_reporting | |
12 | * Bugfix: configure problem with getdns-0.5.1 on OpenBSD | |
13 | Thanks Claus Assmann. | |
14 | * pkg-config support. Thanks Neil Cook. | |
15 | * Functions to convert from RR dicts to wireformat and text format | |
16 | and vice versa. Including a function that builds a getdns_list | |
17 | of RR dicts from a zonefile. | |
18 | * Use the with the getdns_context_set_dns_root_servers() function | |
19 | provided root servers in recursing resolution modus. | |
20 | * getdns_query option (-f) to read a DNSSEC trust anchor from file. | |
21 | * getdns_query option (-R) to read a "root hints" file. | |
22 | * Bugfix: Detect and prevent duplicate NSEC(3)s to be returned with | |
23 | dnssec_return_validation_chain. | |
24 | * Bugfix: Remove duplicate RRs from RRsets when DNSSEC verifying | |
25 | * Client side edns-tcp-keepalive support | |
26 | * TSIG support + getdns_query syntax to specify TSIG parameters | |
27 | per upstream: @<ip>[^[<algorithm>:]<name>:<secret in Base64>] | |
28 | * Bugfix: Allow truncated answers to be returned in case of missing | |
29 | fallback transport. | |
30 | * Verify upstream TLS pubkeys with pinsets; A getdns_query option | |
31 | (-K) to attach pinsets to getdns_contexts. | |
32 | Thanks Daniel Kahn Gillmor | |
33 | * Initial support for Windows. Thanks Gowri Visweswaran | |
34 | * add_warning_for_bad_dns extension | |
35 | * Try and retry with suffixes giving with getdns_context_set_suffix() | |
36 | following directions given by getdns_context_set_append_name() | |
37 | getdns_query options to set suffixes and append_name directions: | |
38 | '-W' to append suffix always (default) | |
39 | '-1' to append suffix only to single label after failure | |
40 | '-M' to append suffix only to multi label name after failure | |
41 | '-N' to never append a suffix | |
42 | '-Z <suffixes>' to set suffixes with the given comma separed list | |
43 | * Better help text for getdns_query (printed with the '-h' option) | |
44 | * Setting the +specify_class extension with getdns_query | |
45 | * Return NOT_IMPLEMENTED for not implemented namespaces, and the | |
46 | not implemented getdns_context_set_follow_redirects() function. | |
47 | ||
0 | 48 | * 2015-11-18: Version 0.5.1 |
1 | 49 | * Bugfix: growing upstreams arrow. |
2 | 50 | * Bugfix: Segfault on timeout in specific conditions |
38 | 38 | exec_prefix = @exec_prefix@ |
39 | 39 | bindir = @bindir@ |
40 | 40 | docdir = @docdir@ |
41 | libdir = @libdir@ | |
41 | 42 | |
42 | 43 | srcdir = @srcdir@ |
43 | 44 | INSTALL = @INSTALL@ |
44 | 45 | |
45 | all : default @GETDNS_QUERY@ | |
46 | all : default @GETDNS_QUERY@ | |
46 | 47 | |
47 | 48 | default: |
48 | 49 | cd src && $(MAKE) $@ |
49 | 50 | |
50 | install: all @INSTALL_GETDNS_QUERY@ | |
51 | install: all getdns.pc @INSTALL_GETDNS_QUERY@ | |
51 | 52 | $(INSTALL) -m 755 -d $(DESTDIR)$(docdir) |
52 | 53 | $(INSTALL) -m 644 $(srcdir)/AUTHORS $(DESTDIR)$(docdir) |
53 | 54 | $(INSTALL) -m 644 $(srcdir)/ChangeLog $(DESTDIR)$(docdir) |
56 | 57 | $(INSTALL) -m 644 $(srcdir)/LICENSE $(DESTDIR)$(docdir) |
57 | 58 | $(INSTALL) -m 644 $(srcdir)/NEWS $(DESTDIR)$(docdir) |
58 | 59 | $(INSTALL) -m 644 $(srcdir)/README.md $(DESTDIR)$(docdir) |
60 | $(INSTALL) -m 755 -d $(DESTDIR)$(libdir)/pkgconfig | |
61 | $(INSTALL) -m 644 getdns.pc $(DESTDIR)$(libdir)/pkgconfig | |
59 | 62 | $(INSTALL) -m 755 -d $(DESTDIR)$(docdir)/spec |
60 | 63 | $(INSTALL) -m 644 $(srcdir)/spec/index.html $(DESTDIR)$(docdir)/spec |
61 | 64 | $(INSTALL) -m 644 $(srcdir)/spec/getdns*tgz $(DESTDIR)$(docdir)/spec || true |
112 | 115 | cd src && $(MAKE) $@ |
113 | 116 | cd doc && $(MAKE) $@ |
114 | 117 | cd spec/example && $(MAKE) $@ |
115 | rm -f *.o | |
118 | rm -f *.o *.pc | |
116 | 119 | |
117 | 120 | depend: |
118 | 121 | cd src && $(MAKE) $@ |
122 | cd spec/example && $(MAKE) $@ | |
119 | 123 | |
120 | 124 | distclean: |
121 | 125 | cd src && $(MAKE) $@ |
125 | 129 | cd spec/example && $(MAKE) $@ |
126 | 130 | rmdir spec/example 2>/dev/null || true |
127 | 131 | rmdir spec 2>/dev/null || true |
128 | rm -f config.log config.status Makefile libtool | |
132 | rm -f config.log config.status Makefile libtool getdns.pc | |
129 | 133 | rm -fR autom4te.cache |
130 | 134 | rm -f m4/libtool.m4 |
131 | 135 | rm -f m4/lt~obsolete.m4 |
189 | 193 | cp $(srcdir)/install-sh $(distdir) |
190 | 194 | cp $(srcdir)/config.sub $(distdir) |
191 | 195 | cp $(srcdir)/config.guess $(distdir) |
196 | cp $(srcdir)/getdns.pc.in $(distdir) | |
192 | 197 | cp libtool $(distdir) |
193 | 198 | cp $(srcdir)/ltmain.sh $(distdir) |
194 | 199 | cp $(srcdir)/m4/*.m4 $(distdir)/m4 |
231 | 236 | rm -rf $(distdir) |
232 | 237 | @echo "*** Package $(distdir).tar.gz is ready for distribution" |
233 | 238 | |
239 | getdns.pc: $(srcdir)/getdns.pc.in | |
240 | ./config.status $@ | |
241 | ||
234 | 242 | Makefile: $(srcdir)/Makefile.in config.status |
235 | 243 | ./config.status $@ |
236 | 244 |
0 | 0 | getdns API |
1 | 1 | ========== |
2 | 2 | |
3 | * Date: 2015-10-22 | |
3 | * Date: 2015-12-30 | |
4 | 4 | * GitHub: <https://github.com/getdnsapi/getdns> |
5 | 5 | |
6 | 6 | getdns is an implementation of a modern asynchronous DNS API specification |
14 | 14 | Download the sources from our [github repo](https://github.com/getdnsapi/getdns) |
15 | 15 | or from [getdnsapi.net](https://getdnsapi.net) and verify the download using |
16 | 16 | the checksums (SHA1 or MD5) or using gpg to verify the signature. Our keys are |
17 | available from the [pgp keyservers](http://keyserver.pgp.com) | |
17 | available from the [pgp keyservers](https://keyserver.pgp.com) | |
18 | 18 | |
19 | 19 | * willem@nlnetlabs.nl, key id E5F8F8212F77A498 |
20 | 20 | * gwiley@verisign.com, key id 9DC3D572A6B73532 |
21 | 21 | |
22 | The [getdns-api mailing list](http://www.vpnc.org/mailman/listinfo/getdns-api) | |
22 | We have a [users list](https://getdnsapi.net/mailman/listinfo/spec) for this implementation. | |
23 | ||
24 | The [getdns-api mailing list](https://getdnsapi.net/mailman/listinfo/spec) | |
23 | 25 | is a good place to engage in discussions regarding the design of the API. |
24 | 26 | |
25 | 27 | If you are just getting started with the library take a look at the section |
34 | 36 | |
35 | 37 | * Provide an open source implementation, in C, of the formally described getdns API by getdns API team at <https://getdnsapi.net/spec.html> |
36 | 38 | * Initial support for FreeBSD, OSX, Linux (CentOS/RHEL, Ubuntu) via functional "configure" script |
39 | * Initial support for Windows 8.1 | |
37 | 40 | * Initial support to include the Android platform |
38 | 41 | * Include examples and tests as part of the build |
39 | 42 | * Document code using doxygen |
83 | 86 | ============================== |
84 | 87 | |
85 | 88 | External dependencies are linked outside the getdns API build tree (we rely on configure to find them). We would like to keep the dependency tree short. |
89 | Please refer to section for building on Windows for separate dependency and build instructions. | |
86 | 90 | |
87 | 91 | * [libunbound from NLnet Labs](https://unbound.net/) version 1.4.16 or later. |
88 | 92 | * [libidn from the FSF](https://www.gnu.org/software/libidn/) version 1. |
111 | 115 | * [libuv](https://github.com/joyent/libuv) |
112 | 116 | * [libev](http://software.schmorp.de/pkg/libev.html) |
113 | 117 | |
118 | NOTE: The current Windows implementation does not support the above. | |
119 | ||
114 | 120 | ## Regression Tests |
115 | 121 | |
116 | 122 | A suite of regression tests are included with the library, if you make changes or just |
117 | 123 | want to sanity check things on your system take a look at src/test. You will need |
118 | to install [libcheck](http://check.sourceforge.net/) and [libldns from NLnet Labs](https://nlnetlabs.nl/projects/ldns/) version 1.6.17 or later. Both libraries are also available from | |
124 | to install [libcheck](https://libcheck.github.io/check/) and [libldns from NLnet Labs](https://nlnetlabs.nl/projects/ldns/) version 1.6.17 or later. Both libraries are also available from | |
119 | 125 | many of the package repositories for the more popular operating systems. |
126 | ||
127 | NOTE: The current Windows implementation does not support the above. | |
120 | 128 | |
121 | 129 | ## DNSSEC |
122 | 130 | |
127 | 135 | format. Note that this is different than the format of BIND.keys. |
128 | 136 | |
129 | 137 | The best way to setup or update the root trust anchor is by using |
130 | [`unbound-anchor`](http://www.unbound.net/documentation/unbound-anchor.html). | |
138 | [`unbound-anchor`](https://www.unbound.net/documentation/unbound-anchor.html). | |
131 | 139 | To setup the library with the root trust anchor at the default location, |
132 | 140 | execute the following steps as root: |
133 | 141 | |
138 | 146 | |
139 | 147 | The following API calls are documented in getDNS but *not supported* by the implementation at this time: |
140 | 148 | |
141 | * DNS Search suffixes | |
142 | * `getdns_context_set_append_name` | |
143 | * `getdns_context_set_suffix` | |
144 | * Setting root servers via `getdns_context_set_dns_root_servers` | |
149 | * Disabling following of `CNAME`s with `getdns_context_set_follow_redirects()` | |
145 | 150 | * Detecting changes to resolv.conf and hosts |
146 | * MDNS and NetBIOS namespaces (only DNS and LOCALFILES are supported) | |
147 | ||
148 | Some platform specific features are not implemented in the first public release of getdns, however they are on the radar. These include: | |
149 | ||
150 | * Respecting settings in /etc/nsswitch.conf (linux and some other OSes), for the first release we simply check local files (/etc/hosts) before checking the DNS. | |
151 | * Search suffixes specified in /etc/resolv.conf | |
151 | * MDNS, NIS and NetBIOS namespaces (only DNS and LOCALFILES are supported) | |
152 | 152 | |
153 | 153 | #Known Issues |
154 | 154 | |
166 | 166 | * RHEL/CentOS 6.4 |
167 | 167 | * OSX 10.8 |
168 | 168 | * Ubuntu 14.04 |
169 | ||
170 | We intend to add MS-Windows, Android and other platforms to the releases as we have time to port it. | |
169 | * Microsoft Windows 8.1 (initial support for DNSSEC but no TLS provided for version 0.5.1) | |
170 | ||
171 | We intend to add Android and other platforms to the releases as we have time to port it. | |
171 | 172 | |
172 | 173 | |
173 | 174 | ##Platform Specific Build Reports |
176 | 177 | |
177 | 178 | ###FreeBSD |
178 | 179 | |
179 | If you're using [FreeBSD](http://www.freebsd.org/), you may install getdns via the [ports tree](http://www.freshports.org/dns/getdns/) by running: `cd /usr/ports/dns/getdns && make install clean` | |
180 | If you're using [FreeBSD](https://www.freebsd.org/), you may install getdns via the [ports tree](https://www.freshports.org/dns/getdns/) by running: `cd /usr/ports/dns/getdns && make install clean` | |
180 | 181 | |
181 | 182 | If you are using FreeBSD 10 getdns can be intalled via 'pkg install getdns'. |
182 | 183 | |
232 | 233 | |
233 | 234 | As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expected to be located at `$(brew --prefix)/etc/getdns-root.key`. Additionally, the OpenSSL library installed by Homebrew is linked against. Note that the Homebrew OpenSSL installation clones the Keychain certificates to the default OpenSSL location so TLS certificate authentication should work out of the box. |
234 | 235 | |
236 | ||
237 | ### Microsoft Windows 8.1 | |
238 | ||
239 | This section has some Windows specific build instructions. | |
240 | ||
241 | Build tested using [Mingw(3.21.0) and Msys 1.0](http://www.mingw.org/) on Windows 8.1 | |
242 | ||
243 | Dependencies: | |
244 | The following dependencies are built from source on Mingw | |
245 | openssl1.0.2a | |
246 | libidn | |
247 | ||
248 | The windows version of getdns currently only is supported in the stub only mode. | |
249 | ||
250 | To configure: | |
251 | ||
252 | ./configure --enable-stub-only --with-trust-anchor="c:\\\MinGW\\\msys\\\1.0\\\etc\\\unbound\\\getdns-root.key" --with-ssl=/c/OpenSSL --with-getdns_query | |
253 | ||
254 | The trust anchor is also installed by unbound on c:\program Files (X86)\unbound\root.key and can be referenced from there | |
255 | or anywhere else that the user chooses to configure it. | |
256 | ||
257 | After configuring, do a `make` and `make install` to build getdns for Windows. | |
258 | ||
259 | Example test queries: | |
260 | ||
261 | ./getdns_query.exe -s gmadkat.com A @64.6.64.6 +return_call_reporting (UDP) | |
262 | ./getdns_query.exe -s gmadkat.com A @64.6.64.6 -T +return_call_reporting (TCP) | |
263 | ./getdns_query.exe -s gmadkat.com A -l L @185.49.141.37 +return_call_reporting (TLS without authentication) | |
264 | ./getdns_query.exe -s www.huque.com A +dnssec_return_status +return_call_reporting (DNSSEC) | |
265 | ||
266 | ||
235 | 267 | Contributors |
236 | 268 | ============ |
237 | 269 | * Theogene Bucuti |
238 | 270 | * Andrew Cathrow, Verisign Labs |
271 | * Neil Cook | |
239 | 272 | * Saúl Ibarra Corretgé |
240 | 273 | * Craig Despeaux, Verisign, Inc. |
241 | 274 | * John Dickinson, Sinodun |
268 | 301 | |
269 | 302 | Acknowledgements |
270 | 303 | ================ |
271 | The development team explicitly acknowledges Paul Hoffman for his initiative and efforts to develop a consensus based DNS API. We would like to thank the participants of the [mailing list](http://www.vpnc.org/mailman/listinfo/getdns-api) for their contributions. | |
304 | The development team explicitly acknowledges Paul Hoffman for his initiative and efforts to develop a consensus based DNS API. We would like to thank the participants of the [mailing list](https://getdnsapi.net/mailman/listinfo/spec) for their contributions. |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for getdns 0.5.1. | |
2 | # Generated by GNU Autoconf 2.69 for getdns 0.9.0. | |
3 | 3 | # |
4 | 4 | # Report bugs to <stub-resolver@verisignlabs.com>. |
5 | 5 | # |
589 | 589 | # Identity of this package. |
590 | 590 | PACKAGE_NAME='getdns' |
591 | 591 | PACKAGE_TARNAME='getdns' |
592 | PACKAGE_VERSION='0.5.1' | |
593 | PACKAGE_STRING='getdns 0.5.1' | |
592 | PACKAGE_VERSION='0.9.0' | |
593 | PACKAGE_STRING='getdns 0.9.0' | |
594 | 594 | PACKAGE_BUGREPORT='stub-resolver@verisignlabs.com' |
595 | 595 | PACKAGE_URL='https://getdnsapi.net' |
596 | 596 | |
770 | 770 | enable_debug_sched |
771 | 771 | enable_debug_stub |
772 | 772 | enable_debug_sec |
773 | enable_all_debugging | |
773 | 774 | enable_tcp_fastopen |
774 | 775 | enable_native_stub_dnssec |
775 | 776 | with_ssl |
778 | 779 | enable_ecdsa |
779 | 780 | enable_draft_dnssec_roadblock_avoidance |
780 | 781 | enable_draft_edns_cookies |
782 | enable_all_drafts | |
781 | 783 | enable_stub_only |
782 | 784 | with_libidn |
783 | 785 | with_libunbound |
1342 | 1344 | # Omit some internal or obsolete options to make the list less imposing. |
1343 | 1345 | # This message is too long to be a string in the A/UX 3.1 sh. |
1344 | 1346 | cat <<_ACEOF |
1345 | \`configure' configures getdns 0.5.1 to adapt to many kinds of systems. | |
1347 | \`configure' configures getdns 0.9.0 to adapt to many kinds of systems. | |
1346 | 1348 | |
1347 | 1349 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1348 | 1350 | |
1407 | 1409 | |
1408 | 1410 | if test -n "$ac_init_help"; then |
1409 | 1411 | case $ac_init_help in |
1410 | short | recursive ) echo "Configuration of getdns 0.5.1:";; | |
1412 | short | recursive ) echo "Configuration of getdns 0.9.0:";; | |
1411 | 1413 | esac |
1412 | 1414 | cat <<\_ACEOF |
1413 | 1415 | |
1424 | 1426 | --enable-debug-sched Enable scheduling debugging messages |
1425 | 1427 | --enable-debug-stub Enable stub debugging messages |
1426 | 1428 | --enable-debug-sec Enable dnssec debugging messages |
1427 | --enable-tcp-fastopen Enable TCP Fast Open | |
1429 | --enable-all-debugging Enable scheduling, stub and dnssec debugging | |
1430 | --disable-tcp-fastopen Disable TCP Fast Open (default=enabled if available) | |
1428 | 1431 | --disable-native-stub-dnssec |
1429 | 1432 | Disable native stub DNSSEC support |
1430 | 1433 | --disable-sha2 Disable SHA256 and SHA512 RRSIG support |
1434 | 1437 | Enable experimental dnssec roadblock avoidance |
1435 | 1438 | --enable-draft-edns-cookies |
1436 | 1439 | Enable experimental edns cookies |
1440 | --enable-all-drafts Enable cookies and roadblock avoidance | |
1437 | 1441 | --enable-stub-only Restricts resolution modes to STUB (which will be |
1438 | 1442 | the default mode). Removes the libunbound |
1439 | 1443 | dependency. |
1549 | 1553 | test -n "$ac_init_help" && exit $ac_status |
1550 | 1554 | if $ac_init_version; then |
1551 | 1555 | cat <<\_ACEOF |
1552 | getdns configure 0.5.1 | |
1556 | getdns configure 0.9.0 | |
1553 | 1557 | generated by GNU Autoconf 2.69 |
1554 | 1558 | |
1555 | 1559 | Copyright (C) 2012 Free Software Foundation, Inc. |
1981 | 1985 | This file contains any messages produced by compilers while |
1982 | 1986 | running configure, to aid debugging if configure makes a mistake. |
1983 | 1987 | |
1984 | It was created by getdns $as_me 0.5.1, which was | |
1988 | It was created by getdns $as_me 0.9.0, which was | |
1985 | 1989 | generated by GNU Autoconf 2.69. Invocation command line was |
1986 | 1990 | |
1987 | 1991 | $ $0 $@ |
2341 | 2345 | fi |
2342 | 2346 | |
2343 | 2347 | |
2344 | GETDNS_VERSION="0.5.1$RELEASE_CANDIDATE" | |
2345 | ||
2346 | GETDNS_NUMERIC_VERSION=0x00050100 | |
2347 | ||
2348 | API_VERSION="October 2015" | |
2349 | ||
2350 | API_NUMERIC_VERSION=0x07df0a00 | |
2348 | GETDNS_VERSION="0.9.0$RELEASE_CANDIDATE" | |
2349 | ||
2350 | GETDNS_NUMERIC_VERSION=0x00090000 | |
2351 | ||
2352 | API_VERSION="December 2015" | |
2353 | ||
2354 | API_NUMERIC_VERSION=0x07df0c00 | |
2351 | 2355 | |
2352 | 2356 | GETDNS_COMPILATION_COMMENT="getdns $GETDNS_VERSION configured on $CURRENT_DATE for the $API_VERSION version of the API" |
2353 | 2357 | |
2374 | 2378 | # getdns-0.3.2 had libversion 3:5:2 |
2375 | 2379 | # getdns-0.3.3 had libversion 3:6:2 |
2376 | 2380 | # getdns-0.5.0 had libversion 4:0:3 |
2377 | # getdns-0.5.1 has libversion 4:1:3 | |
2381 | # getdns-0.5.1 had libversion 4:1:3 (but should have been getdns-0.6.0) | |
2382 | # getdns-0.9.0 will have libversion 5:0:4 | |
2378 | 2383 | # |
2379 | GETDNS_LIBVERSION=4:1:3 | |
2384 | GETDNS_LIBVERSION=5:0:4 | |
2380 | 2385 | |
2381 | 2386 | |
2382 | 2387 | |
3665 | 3670 | |
3666 | 3671 | |
3667 | 3672 | case "$host_os" in |
3668 | linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE" | |
3673 | linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE" | |
3669 | 3674 | ;; |
3670 | 3675 | solaris* ) CFLAGS="$CFLAGS -D__EXTENSIONS__" # for strdup() from <string.h> |
3671 | 3676 | ;; |
11221 | 11226 | fi |
11222 | 11227 | |
11223 | 11228 | |
11229 | ||
11224 | 11230 | # Check whether --enable-debug-sched was given. |
11225 | 11231 | if test "${enable_debug_sched+set}" = set; then : |
11226 | 11232 | enableval=$enable_debug_sched; |
11227 | 11233 | fi |
11228 | 11234 | |
11229 | case "$enable_debug_sched" in | |
11235 | # Check whether --enable-debug-stub was given. | |
11236 | if test "${enable_debug_stub+set}" = set; then : | |
11237 | enableval=$enable_debug_stub; | |
11238 | fi | |
11239 | ||
11240 | # Check whether --enable-debug-sec was given. | |
11241 | if test "${enable_debug_sec+set}" = set; then : | |
11242 | enableval=$enable_debug_sec; | |
11243 | fi | |
11244 | ||
11245 | # Check whether --enable-all-debugging was given. | |
11246 | if test "${enable_all_debugging+set}" = set; then : | |
11247 | enableval=$enable_all_debugging; | |
11248 | fi | |
11249 | ||
11250 | case "$enable_all_debugging" in | |
11230 | 11251 | yes) |
11231 | ||
11232 | cat >>confdefs.h <<_ACEOF | |
11233 | #define SCHED_DEBUG 1 | |
11234 | _ACEOF | |
11235 | ||
11252 | enable_debug_sched=yes | |
11253 | enable_debug_stub=yes | |
11254 | enable_debug_sec=yes | |
11236 | 11255 | ;; |
11237 | 11256 | no|*) |
11238 | 11257 | ;; |
11239 | 11258 | esac |
11240 | # Check whether --enable-debug-stub was given. | |
11241 | if test "${enable_debug_stub+set}" = set; then : | |
11242 | enableval=$enable_debug_stub; | |
11243 | fi | |
11244 | ||
11245 | case "$enable_debug_stub" in | |
11259 | case "$enable_debug_sched" in | |
11246 | 11260 | yes) |
11247 | 11261 | |
11248 | 11262 | cat >>confdefs.h <<_ACEOF |
11249 | #define STUB_DEBUG 1 | |
11263 | #define SCHED_DEBUG 1 | |
11250 | 11264 | _ACEOF |
11251 | 11265 | |
11252 | 11266 | ;; |
11253 | 11267 | no|*) |
11254 | 11268 | ;; |
11255 | 11269 | esac |
11256 | # Check whether --enable-debug-sec was given. | |
11257 | if test "${enable_debug_sec+set}" = set; then : | |
11258 | enableval=$enable_debug_sec; | |
11259 | fi | |
11260 | ||
11261 | case "$enable_debug_sec" in | |
11270 | case "$enable_debug_stub" in | |
11262 | 11271 | yes) |
11263 | 11272 | |
11264 | 11273 | cat >>confdefs.h <<_ACEOF |
11265 | #define SEC_DEBUG 1 | |
11274 | #define STUB_DEBUG 1 | |
11266 | 11275 | _ACEOF |
11267 | 11276 | |
11268 | 11277 | ;; |
11269 | 11278 | no|*) |
11270 | 11279 | ;; |
11271 | 11280 | esac |
11272 | ||
11273 | # Check whether --enable-tcp-fastopen was given. | |
11274 | if test "${enable_tcp_fastopen+set}" = set; then : | |
11275 | enableval=$enable_tcp_fastopen; | |
11276 | fi | |
11277 | ||
11278 | case "$enable_tcp_fastopen" in | |
11281 | case "$enable_debug_sec" in | |
11279 | 11282 | yes) |
11280 | ac_fn_c_check_decl "$LINENO" "MSG_FASTOPEN" "ac_cv_have_decl_MSG_FASTOPEN" "$ac_includes_default | |
11281 | #include <sys/socket.h> | |
11282 | ||
11283 | " | |
11284 | if test "x$ac_cv_have_decl_MSG_FASTOPEN" = xyes; then : | |
11285 | ||
11286 | else | |
11287 | as_fn_error $? "TCP Fast Open is not available: please rerun without --enable-tcp-fastopen" "$LINENO" 5 | |
11288 | fi | |
11289 | ||
11290 | 11283 | |
11291 | 11284 | cat >>confdefs.h <<_ACEOF |
11292 | #define USE_TCP_FASTOPEN 1 | |
11285 | #define SEC_DEBUG 1 | |
11293 | 11286 | _ACEOF |
11294 | 11287 | |
11295 | 11288 | ;; |
11297 | 11290 | ;; |
11298 | 11291 | esac |
11299 | 11292 | |
11300 | # Not yet enabled by default as crash found when TCP fails. | |
11301 | # AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--disable-tcp-fastopen], Disable TCP Fast Open (default=enabled if available)), | |
11302 | # enable_tcp_fastopen="$enableval", enable_tcp_fastopen=yes) | |
11303 | # if test "x$enable_tcp_fastopen" = xno; then | |
11304 | # AC_MSG_WARN([TCP Fast Open is disabled]) | |
11305 | # else | |
11306 | # AC_CHECK_DECL([MSG_FASTOPEN], [AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])], | |
11307 | # [AC_MSG_WARN([TCP Fast Open is not available.])], [AC_INCLUDES_DEFAULT | |
11308 | # #include <sys/socket.h> | |
11309 | # ]) | |
11310 | # fi | |
11293 | # Check whether --enable-tcp-fastopen was given. | |
11294 | if test "${enable_tcp_fastopen+set}" = set; then : | |
11295 | enableval=$enable_tcp_fastopen; enable_tcp_fastopen="$enableval" | |
11296 | else | |
11297 | enable_tcp_fastopen=yes | |
11298 | fi | |
11299 | ||
11300 | if test "x$enable_tcp_fastopen" = xno; then | |
11301 | { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: TCP Fast Open is disabled" >&5 | |
11302 | $as_echo "$as_me: WARNING: TCP Fast Open is disabled" >&2;} | |
11303 | else | |
11304 | case `uname` in | |
11305 | Linux) ac_fn_c_check_decl "$LINENO" "MSG_FASTOPEN" "ac_cv_have_decl_MSG_FASTOPEN" "#include <sys/socket.h> | |
11306 | " | |
11307 | if test "x$ac_cv_have_decl_MSG_FASTOPEN" = xyes; then : | |
11308 | ||
11309 | cat >>confdefs.h <<_ACEOF | |
11310 | #define USE_TCP_FASTOPEN 1 | |
11311 | _ACEOF | |
11312 | ||
11313 | else | |
11314 | { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: TCP Fast Open is not available, continuing without" >&5 | |
11315 | $as_echo "$as_me: WARNING: TCP Fast Open is not available, continuing without" >&2;} | |
11316 | fi | |
11317 | ||
11318 | ;; | |
11319 | Darwin) ac_fn_c_check_decl "$LINENO" "CONNECT_RESUME_ON_READ_WRITE" "ac_cv_have_decl_CONNECT_RESUME_ON_READ_WRITE" "#include <sys/socket.h> | |
11320 | " | |
11321 | if test "x$ac_cv_have_decl_CONNECT_RESUME_ON_READ_WRITE" = xyes; then : | |
11322 | ||
11323 | cat >>confdefs.h <<_ACEOF | |
11324 | #define USE_OSX_TCP_FASTOPEN 1 | |
11325 | _ACEOF | |
11326 | ||
11327 | else | |
11328 | { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: TCP Fast Open is not available, continuing without" >&5 | |
11329 | $as_echo "$as_me: WARNING: TCP Fast Open is not available, continuing without" >&2;} | |
11330 | fi | |
11331 | ||
11332 | ;; | |
11333 | *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: TCP Fast Open is not available, continuing without" >&5 | |
11334 | $as_echo "$as_me: WARNING: TCP Fast Open is not available, continuing without" >&2;} | |
11335 | ;; | |
11336 | esac | |
11337 | fi | |
11311 | 11338 | |
11312 | 11339 | # Check whether --enable-native-stub-dnssec was given. |
11313 | 11340 | if test "${enable_native_stub_dnssec+set}" = set; then : |
11385 | 11412 | |
11386 | 11413 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for HMAC_CTX_init in -lcrypto" >&5 |
11387 | 11414 | $as_echo_n "checking for HMAC_CTX_init in -lcrypto... " >&6; } |
11388 | LIBS="$LIBS -lcrypto -lssl" | |
11389 | LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl" | |
11415 | LIBS="$LIBS -lssl -lcrypto" | |
11416 | LIBSSL_LIBS="$LIBSSL_LIBS -lssl -lcrypto" | |
11390 | 11417 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
11391 | 11418 | /* end confdefs.h. */ |
11392 | 11419 | |
11814 | 11841 | |
11815 | 11842 | done |
11816 | 11843 | |
11817 | for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode | |
11844 | for ac_func in OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode | |
11818 | 11845 | do : |
11819 | 11846 | as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` |
11820 | 11847 | ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" |
12180 | 12207 | ;; |
12181 | 12208 | esac |
12182 | 12209 | |
12210 | ||
12183 | 12211 | # Check whether --enable-draft-dnssec-roadblock-avoidance was given. |
12184 | 12212 | if test "${enable_draft_dnssec_roadblock_avoidance+set}" = set; then : |
12185 | 12213 | enableval=$enable_draft_dnssec_roadblock_avoidance; |
12186 | 12214 | fi |
12187 | 12215 | |
12188 | case "$enable_draft_dnssec_roadblock_avoidance" in | |
12216 | # Check whether --enable-draft-edns-cookies was given. | |
12217 | if test "${enable_draft_edns_cookies+set}" = set; then : | |
12218 | enableval=$enable_draft_edns_cookies; | |
12219 | fi | |
12220 | ||
12221 | # Check whether --enable-all-drafts was given. | |
12222 | if test "${enable_all_drafts+set}" = set; then : | |
12223 | enableval=$enable_all_drafts; | |
12224 | fi | |
12225 | ||
12226 | case "$enable_all_drafts" in | |
12189 | 12227 | yes) |
12190 | ||
12191 | cat >>confdefs.h <<_ACEOF | |
12192 | #define DNSSEC_ROADBLOCK_AVOIDANCE 1 | |
12193 | _ACEOF | |
12194 | ||
12228 | enable_draft_dnssec_roadblock_avoidance=yes | |
12229 | enable_draft_edns_cookies=yes | |
12195 | 12230 | ;; |
12196 | 12231 | no|*) |
12197 | 12232 | ;; |
12198 | 12233 | esac |
12199 | ||
12200 | # Check whether --enable-draft-edns-cookies was given. | |
12201 | if test "${enable_draft_edns_cookies+set}" = set; then : | |
12202 | enableval=$enable_draft_edns_cookies; | |
12203 | fi | |
12204 | ||
12234 | case "$enable_draft_dnssec_roadblock_avoidance" in | |
12235 | yes) | |
12236 | ||
12237 | cat >>confdefs.h <<_ACEOF | |
12238 | #define DNSSEC_ROADBLOCK_AVOIDANCE 1 | |
12239 | _ACEOF | |
12240 | ||
12241 | ;; | |
12242 | no|*) | |
12243 | ;; | |
12244 | esac | |
12205 | 12245 | case "$enable_draft_edns_cookies" in |
12206 | 12246 | yes) |
12207 | 12247 | if test "x_$HAVE_SSL" != "x_yes"; then |
12253 | 12293 | esac |
12254 | 12294 | |
12255 | 12295 | # search to set include and library paths right |
12256 | # find libidn | |
12257 | my_with_libidn=1 | |
12296 | # find libidn (no libidn on windows though) | |
12297 | for ac_header in windows.h winsock.h stdio.h winsock2.h ws2tcpip.h | |
12298 | do : | |
12299 | as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` | |
12300 | ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default | |
12301 | " | |
12302 | if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : | |
12303 | cat >>confdefs.h <<_ACEOF | |
12304 | #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 | |
12305 | _ACEOF | |
12306 | ||
12307 | fi | |
12308 | ||
12309 | done | |
12310 | ||
12311 | ||
12312 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 | |
12313 | $as_echo_n "checking for getaddrinfo... " >&6; } | |
12314 | ac_cv_func_getaddrinfo=no | |
12315 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext | |
12316 | /* end confdefs.h. */ | |
12317 | ||
12318 | #ifdef __cplusplus | |
12319 | extern "C" | |
12320 | { | |
12321 | #endif | |
12322 | char* getaddrinfo(); | |
12323 | char* (*f) () = getaddrinfo; | |
12324 | #ifdef __cplusplus | |
12325 | } | |
12326 | #endif | |
12327 | int main() { | |
12328 | ; | |
12329 | return 0; | |
12330 | } | |
12331 | ||
12332 | _ACEOF | |
12333 | if ac_fn_c_try_link "$LINENO"; then : | |
12334 | ac_cv_func_getaddrinfo="yes" | |
12335 | if test "$ac_cv_header_windows_h" = "yes"; then | |
12336 | ||
12337 | $as_echo "#define USE_WINSOCK 1" >>confdefs.h | |
12338 | ||
12339 | USE_WINSOCK="1" | |
12340 | LIBS="$LIBS -lws2_32" | |
12341 | fi | |
12342 | ||
12343 | else | |
12344 | ORIGLIBS="$LIBS" | |
12345 | LIBS="$LIBS -lws2_32" | |
12346 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext | |
12347 | /* end confdefs.h. */ | |
12348 | ||
12349 | #define _WIN32_WINNT 0x0501 | |
12350 | #ifdef HAVE_WINDOWS_H | |
12351 | #include <windows.h> | |
12352 | #endif | |
12353 | #ifdef HAVE_WINSOCK_H | |
12354 | #include <winsock.h> | |
12355 | #endif | |
12356 | #ifdef HAVE_WINSOCK2_H | |
12357 | #include <winsock2.h> | |
12358 | #endif | |
12359 | #include <stdio.h> | |
12360 | #ifdef HAVE_WS2TCPIP_H | |
12361 | #include <ws2tcpip.h> | |
12362 | #endif | |
12363 | ||
12364 | int | |
12365 | main () | |
12366 | { | |
12367 | ||
12368 | (void)getaddrinfo(NULL, NULL, NULL, NULL); | |
12369 | ||
12370 | ||
12371 | ; | |
12372 | return 0; | |
12373 | } | |
12374 | _ACEOF | |
12375 | if ac_fn_c_try_link "$LINENO"; then : | |
12376 | ||
12377 | ac_cv_func_getaddrinfo="yes" | |
12378 | ||
12379 | $as_echo "#define USE_WINSOCK 1" >>confdefs.h | |
12380 | ||
12381 | USE_WINSOCK="1" | |
12382 | ||
12383 | else | |
12384 | ||
12385 | ac_cv_func_getaddrinfo="no" | |
12386 | LIBS="$ORIGLIBS" | |
12387 | ||
12388 | fi | |
12389 | rm -f core conftest.err conftest.$ac_objext \ | |
12390 | conftest$ac_exeext conftest.$ac_ext | |
12391 | ||
12392 | fi | |
12393 | rm -f core conftest.err conftest.$ac_objext \ | |
12394 | conftest$ac_exeext conftest.$ac_ext | |
12395 | ||
12396 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getaddrinfo" >&5 | |
12397 | $as_echo "$ac_cv_func_getaddrinfo" >&6; } | |
12398 | if test $ac_cv_func_getaddrinfo = yes; then | |
12399 | ||
12400 | $as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h | |
12401 | ||
12402 | fi | |
12403 | ||
12404 | if test "$USE_WINSOCK" = 1; then | |
12405 | { $as_echo "$as_me:${as_lineno-$LINENO}: Building on Windows ... YES! " >&5 | |
12406 | $as_echo "$as_me: Building on Windows ... YES! " >&6;} | |
12407 | ||
12408 | cat >>confdefs.h <<_ACEOF | |
12409 | #define GETDNS_ON_WINDOWS 1 | |
12410 | _ACEOF | |
12411 | ||
12412 | cat >>confdefs.h <<_ACEOF | |
12413 | #define STUB_NATIVE_DNSSEC 1 | |
12414 | _ACEOF | |
12415 | ||
12416 | LIBS="$LIBS -lgdi32 -liphlpapi" | |
12417 | my_with_libunbound=0 | |
12418 | my_with_libidn=0 | |
12419 | else | |
12420 | my_with_libidn=1 | |
12421 | fi | |
12422 | ||
12423 | ||
12424 | if test $my_with_libidn = 1 | |
12425 | then | |
12258 | 12426 | |
12259 | 12427 | # Check whether --with-libidn was given. |
12260 | 12428 | if test "${with_libidn+set}" = set; then : |
12263 | 12431 | withval="yes" |
12264 | 12432 | fi |
12265 | 12433 | |
12266 | if test x_$withval = x_yes; then | |
12267 | for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do | |
12268 | if test -f "$dir/include/idna.h"; then | |
12269 | CFLAGS="$CFLAGS -I$dir/include" | |
12270 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
12271 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in $dir" >&5 | |
12434 | if test x_$withval = x_yes; then | |
12435 | for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do | |
12436 | if test -f "$dir/include/idna.h"; then | |
12437 | CFLAGS="$CFLAGS -I$dir/include" | |
12438 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
12439 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in $dir" >&5 | |
12272 | 12440 | $as_echo "$as_me: Found libidn in $dir" >&6;} |
12273 | break | |
12441 | break | |
12442 | fi | |
12443 | if test -f "$dir/include/idn/idna.h"; then | |
12444 | CFLAGS="$CFLAGS -I$dir/include/idn" | |
12445 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
12446 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in $dir" >&5 | |
12447 | $as_echo "$as_me: Found libidn in $dir" >&6;} | |
12448 | break | |
12449 | fi | |
12450 | done | |
12451 | if test -f "/usr/include/idn/idna.h"; then | |
12452 | CFLAGS="$CFLAGS -I/usr/include/idn" | |
12453 | #LDFLAGS="$LDFLAGS -L/usr/lib" | |
12454 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in /usr" >&5 | |
12455 | $as_echo "$as_me: Found libidn in /usr" >&6;} | |
12274 | 12456 | fi |
12275 | if test -f "$dir/include/idn/idna.h"; then | |
12276 | CFLAGS="$CFLAGS -I$dir/include/idn" | |
12277 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
12278 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in $dir" >&5 | |
12279 | $as_echo "$as_me: Found libidn in $dir" >&6;} | |
12280 | break | |
12457 | else | |
12458 | if test x_$withval != x_no; then | |
12459 | CFLAGS="$CFLAGS -I$withval/include" | |
12460 | LDFLAGS="$LDFLAGS -L$withval/lib" | |
12461 | else | |
12462 | my_with_libidn=0 | |
12281 | 12463 | fi |
12282 | done | |
12283 | if test -f "/usr/include/idn/idna.h"; then | |
12284 | CFLAGS="$CFLAGS -I/usr/include/idn" | |
12285 | #LDFLAGS="$LDFLAGS -L/usr/lib" | |
12286 | { $as_echo "$as_me:${as_lineno-$LINENO}: Found libidn in /usr" >&5 | |
12287 | $as_echo "$as_me: Found libidn in /usr" >&6;} | |
12288 | fi | |
12289 | else | |
12290 | if test x_$withval != x_no; then | |
12291 | CFLAGS="$CFLAGS -I$withval/include" | |
12292 | LDFLAGS="$LDFLAGS -L$withval/lib" | |
12293 | else | |
12294 | my_with_libidn=0 | |
12295 | 12464 | fi |
12296 | 12465 | fi |
12297 | 12466 | |
14034 | 14203 | |
14035 | 14204 | |
14036 | 14205 | |
14037 | ac_config_files="$ac_config_files Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile" | |
14206 | ac_config_files="$ac_config_files Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile getdns.pc" | |
14038 | 14207 | |
14039 | 14208 | if test -n "$DOXYGEN" |
14040 | 14209 | then ac_config_files="$ac_config_files src/Doxyfile" |
14164 | 14333 | cat >>confdefs.h <<_ACEOF |
14165 | 14334 | #define HAVE_DECL_ARC4RANDOM_UNIFORM $ac_have_decl |
14166 | 14335 | _ACEOF |
14336 | ||
14337 | ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton" | |
14338 | if test "x$ac_cv_func_inet_pton" = xyes; then : | |
14339 | $as_echo "#define HAVE_INET_PTON 1" >>confdefs.h | |
14340 | ||
14341 | else | |
14342 | case " $LIBOBJS " in | |
14343 | *" inet_pton.$ac_objext "* ) ;; | |
14344 | *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" | |
14345 | ;; | |
14346 | esac | |
14347 | ||
14348 | fi | |
14349 | ||
14350 | ||
14351 | ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" | |
14352 | if test "x$ac_cv_func_inet_ntop" = xyes; then : | |
14353 | $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h | |
14354 | ||
14355 | else | |
14356 | case " $LIBOBJS " in | |
14357 | *" inet_ntop.$ac_objext "* ) ;; | |
14358 | *) LIBOBJS="$LIBOBJS inet_ntop.$ac_objext" | |
14359 | ;; | |
14360 | esac | |
14361 | ||
14362 | fi | |
14363 | ||
14167 | 14364 | |
14168 | 14365 | ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" |
14169 | 14366 | if test "x$ac_cv_func_strlcpy" = xyes; then : |
15007 | 15204 | # report actual input values of CONFIG_FILES etc. instead of their |
15008 | 15205 | # values after options handling. |
15009 | 15206 | ac_log=" |
15010 | This file was extended by getdns $as_me 0.5.1, which was | |
15207 | This file was extended by getdns $as_me 0.9.0, which was | |
15011 | 15208 | generated by GNU Autoconf 2.69. Invocation command line was |
15012 | 15209 | |
15013 | 15210 | CONFIG_FILES = $CONFIG_FILES |
15074 | 15271 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
15075 | 15272 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
15076 | 15273 | ac_cs_version="\\ |
15077 | getdns config.status 0.5.1 | |
15274 | getdns config.status 0.9.0 | |
15078 | 15275 | configured by $0, generated by GNU Autoconf 2.69, |
15079 | 15276 | with options \\"\$ac_cs_config\\" |
15080 | 15277 | |
15488 | 15685 | "spec/example/Makefile") CONFIG_FILES="$CONFIG_FILES spec/example/Makefile" ;; |
15489 | 15686 | "src/test/Makefile") CONFIG_FILES="$CONFIG_FILES src/test/Makefile" ;; |
15490 | 15687 | "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; |
15688 | "getdns.pc") CONFIG_FILES="$CONFIG_FILES getdns.pc" ;; | |
15491 | 15689 | "src/Doxyfile") CONFIG_FILES="$CONFIG_FILES src/Doxyfile" ;; |
15492 | 15690 | "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; |
15493 | 15691 |
31 | 31 | AC_PREREQ([2.56]) |
32 | 32 | AC_CONFIG_MACRO_DIRS([m4]) |
33 | 33 | sinclude(./m4/acx_openssl.m4) |
34 | sinclude(./m4/acx_getaddrinfo.m4) | |
34 | 35 | sinclude(./m4/ax_check_compile_flag.m4) |
35 | 36 | sinclude(./m4/pkg.m4) |
36 | 37 | |
37 | AC_INIT([getdns], [0.5.1], [stub-resolver@verisignlabs.com], [], [https://getdnsapi.net]) | |
38 | AC_INIT([getdns], [0.9.0], [stub-resolver@verisignlabs.com], [], [https://getdnsapi.net]) | |
38 | 39 | AC_SUBST(RELEASE_CANDIDATE, []) |
39 | 40 | |
40 | 41 | # Set current date from system if not set |
45 | 46 | [CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"]) |
46 | 47 | |
47 | 48 | AC_SUBST(GETDNS_VERSION, ["AC_PACKAGE_VERSION$RELEASE_CANDIDATE"]) |
48 | AC_SUBST(GETDNS_NUMERIC_VERSION, [0x00050100]) | |
49 | AC_SUBST(API_VERSION, ["October 2015"]) | |
50 | AC_SUBST(API_NUMERIC_VERSION, [0x07df0a00]) | |
49 | AC_SUBST(GETDNS_NUMERIC_VERSION, [0x00090000]) | |
50 | AC_SUBST(API_VERSION, ["December 2015"]) | |
51 | AC_SUBST(API_NUMERIC_VERSION, [0x07df0c00]) | |
51 | 52 | GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRENT_DATE for the $API_VERSION version of the API" |
52 | 53 | |
53 | 54 | |
73 | 74 | # getdns-0.3.2 had libversion 3:5:2 |
74 | 75 | # getdns-0.3.3 had libversion 3:6:2 |
75 | 76 | # getdns-0.5.0 had libversion 4:0:3 |
76 | # getdns-0.5.1 has libversion 4:1:3 | |
77 | # getdns-0.5.1 had libversion 4:1:3 (but should have been getdns-0.6.0) | |
78 | # getdns-0.9.0 will have libversion 5:0:4 | |
77 | 79 | # |
78 | GETDNS_LIBVERSION=4:1:3 | |
80 | GETDNS_LIBVERSION=5:0:4 | |
79 | 81 | |
80 | 82 | AC_SUBST(GETDNS_COMPILATION_COMMENT) |
81 | 83 | AC_SUBST(GETDNS_LIBVERSION) |
96 | 98 | AX_CHECK_COMPILE_FLAG([-Wall],[CFLAGS="$CFLAGS -Wall"],[],[]) |
97 | 99 | |
98 | 100 | case "$host_os" in |
99 | linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE" | |
101 | linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE" | |
100 | 102 | ;; |
101 | 103 | solaris* ) CFLAGS="$CFLAGS -D__EXTENSIONS__" # for strdup() from <string.h> |
102 | 104 | ;; |
136 | 138 | ]) |
137 | 139 | ACX_ARG_RPATH |
138 | 140 | |
141 | ||
139 | 142 | AC_ARG_ENABLE(debug-sched, AC_HELP_STRING([--enable-debug-sched], [Enable scheduling debugging messages])) |
143 | AC_ARG_ENABLE(debug-stub, AC_HELP_STRING([--enable-debug-stub], [Enable stub debugging messages])) | |
144 | AC_ARG_ENABLE(debug-sec, AC_HELP_STRING([--enable-debug-sec], [Enable dnssec debugging messages])) | |
145 | AC_ARG_ENABLE(all-debugging, AC_HELP_STRING([--enable-all-debugging], [Enable scheduling, stub and dnssec debugging])) | |
146 | case "$enable_all_debugging" in | |
147 | yes) | |
148 | enable_debug_sched=yes | |
149 | enable_debug_stub=yes | |
150 | enable_debug_sec=yes | |
151 | ;; | |
152 | no|*) | |
153 | ;; | |
154 | esac | |
140 | 155 | case "$enable_debug_sched" in |
141 | 156 | yes) |
142 | 157 | AC_DEFINE_UNQUOTED([SCHED_DEBUG], [1], [Define this to enable printing of scheduling debugging messages.]) |
144 | 159 | no|*) |
145 | 160 | ;; |
146 | 161 | esac |
147 | AC_ARG_ENABLE(debug-stub, AC_HELP_STRING([--enable-debug-stub], [Enable stub debugging messages])) | |
148 | 162 | case "$enable_debug_stub" in |
149 | 163 | yes) |
150 | 164 | AC_DEFINE_UNQUOTED([STUB_DEBUG], [1], [Define this to enable printing of stub debugging messages.]) |
152 | 166 | no|*) |
153 | 167 | ;; |
154 | 168 | esac |
155 | AC_ARG_ENABLE(debug-sec, AC_HELP_STRING([--enable-debug-sec], [Enable dnssec debugging messages])) | |
156 | 169 | case "$enable_debug_sec" in |
157 | 170 | yes) |
158 | 171 | AC_DEFINE_UNQUOTED([SEC_DEBUG], [1], [Define this to enable printing of dnssec debugging messages.]) |
161 | 174 | ;; |
162 | 175 | esac |
163 | 176 | |
164 | AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--enable-tcp-fastopen], [Enable TCP Fast Open])) | |
165 | case "$enable_tcp_fastopen" in | |
166 | yes) | |
167 | AC_CHECK_DECL([MSG_FASTOPEN], [], [AC_MSG_ERROR([TCP Fast Open is not available: please rerun without --enable-tcp-fastopen])], [AC_INCLUDES_DEFAULT | |
168 | #include <sys/socket.h> | |
169 | ]) | |
170 | AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.]) | |
171 | ;; | |
172 | no|*) | |
173 | ;; | |
174 | esac | |
175 | ||
176 | # Not yet enabled by default as crash found when TCP fails. | |
177 | # AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--disable-tcp-fastopen], Disable TCP Fast Open (default=enabled if available)), | |
178 | # enable_tcp_fastopen="$enableval", enable_tcp_fastopen=yes) | |
179 | # if test "x$enable_tcp_fastopen" = xno; then | |
180 | # AC_MSG_WARN([TCP Fast Open is disabled]) | |
181 | # else | |
182 | # AC_CHECK_DECL([MSG_FASTOPEN], [AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])], | |
183 | # [AC_MSG_WARN([TCP Fast Open is not available.])], [AC_INCLUDES_DEFAULT | |
184 | # #include <sys/socket.h> | |
185 | # ]) | |
186 | # fi | |
177 | AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--disable-tcp-fastopen], Disable TCP Fast Open (default=enabled if available)), | |
178 | enable_tcp_fastopen="$enableval", enable_tcp_fastopen=yes) | |
179 | if test "x$enable_tcp_fastopen" = xno; then | |
180 | AC_MSG_WARN([TCP Fast Open is disabled]) | |
181 | else | |
182 | case `uname` in | |
183 | Linux) AC_CHECK_DECL([MSG_FASTOPEN], [AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])], | |
184 | [AC_MSG_WARN([TCP Fast Open is not available, continuing without])], [#include <sys/socket.h>]) | |
185 | ;; | |
186 | Darwin) AC_CHECK_DECL([CONNECT_RESUME_ON_READ_WRITE], [AC_DEFINE_UNQUOTED([USE_OSX_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])], | |
187 | [AC_MSG_WARN([TCP Fast Open is not available, continuing without])], [#include <sys/socket.h>]) | |
188 | ;; | |
189 | *) AC_MSG_WARN([TCP Fast Open is not available, continuing without]) | |
190 | ;; | |
191 | esac | |
192 | fi | |
187 | 193 | |
188 | 194 | AC_ARG_ENABLE(native-stub-dnssec, AC_HELP_STRING([--disable-native-stub-dnssec], [Disable native stub DNSSEC support])) |
189 | 195 | case "$enable_native_stub_dnssec" in |
211 | 217 | fi |
212 | 218 | AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) |
213 | 219 | AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) |
214 | AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode]) | |
220 | AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode]) | |
215 | 221 | AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ |
216 | 222 | AC_INCLUDES_DEFAULT |
217 | 223 | #ifdef HAVE_OPENSSL_ERR_H |
392 | 398 | ;; |
393 | 399 | esac |
394 | 400 | |
401 | ||
395 | 402 | AC_ARG_ENABLE(draft-dnssec-roadblock-avoidance, AC_HELP_STRING([--enable-draft-dnssec-roadblock-avoidance], [Enable experimental dnssec roadblock avoidance])) |
403 | AC_ARG_ENABLE(draft-edns-cookies, AC_HELP_STRING([--enable-draft-edns-cookies], [Enable experimental edns cookies])) | |
404 | AC_ARG_ENABLE(all-drafts, AC_HELP_STRING([--enable-all-drafts], [Enable cookies and roadblock avoidance])) | |
405 | case "$enable_all_drafts" in | |
406 | yes) | |
407 | enable_draft_dnssec_roadblock_avoidance=yes | |
408 | enable_draft_edns_cookies=yes | |
409 | ;; | |
410 | no|*) | |
411 | ;; | |
412 | esac | |
396 | 413 | case "$enable_draft_dnssec_roadblock_avoidance" in |
397 | 414 | yes) |
398 | 415 | AC_DEFINE_UNQUOTED([DNSSEC_ROADBLOCK_AVOIDANCE], [1], [Define this to enable the experimental draft dnssec roadblock avoidance.]) |
400 | 417 | no|*) |
401 | 418 | ;; |
402 | 419 | esac |
403 | ||
404 | AC_ARG_ENABLE(draft-edns-cookies, AC_HELP_STRING([--enable-draft-edns-cookies], [Enable experimental edns cookies])) | |
405 | 420 | case "$enable_draft_edns_cookies" in |
406 | 421 | yes) |
407 | 422 | if test "x_$HAVE_SSL" != "x_yes"; then |
429 | 444 | esac |
430 | 445 | |
431 | 446 | # search to set include and library paths right |
432 | # find libidn | |
433 | my_with_libidn=1 | |
434 | AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], | |
435 | [path to libidn (default: search /usr/local ..)]), | |
436 | [], [withval="yes"]) | |
437 | if test x_$withval = x_yes; then | |
438 | for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do | |
439 | if test -f "$dir/include/idna.h"; then | |
440 | CFLAGS="$CFLAGS -I$dir/include" | |
441 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
442 | AC_MSG_NOTICE([Found libidn in $dir]) | |
443 | break | |
447 | # find libidn (no libidn on windows though) | |
448 | AC_CHECK_HEADERS([windows.h winsock.h stdio.h winsock2.h ws2tcpip.h],,, [AC_INCLUDES_DEFAULT]) | |
449 | ACX_CHECK_GETADDRINFO_WITH_INCLUDES | |
450 | if test "$USE_WINSOCK" = 1; then | |
451 | AC_MSG_NOTICE([ Building on Windows ... YES! ]) | |
452 | AC_DEFINE_UNQUOTED([GETDNS_ON_WINDOWS], [1], [Define this to enable Windows build.]) | |
453 | AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1]) | |
454 | LIBS="$LIBS -lgdi32 -liphlpapi" | |
455 | my_with_libunbound=0 | |
456 | my_with_libidn=0 | |
457 | else | |
458 | my_with_libidn=1 | |
459 | fi | |
460 | ||
461 | ||
462 | if test $my_with_libidn = 1 | |
463 | then | |
464 | AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], | |
465 | [path to libidn (default: search /usr/local ..)]), | |
466 | [], [withval="yes"]) | |
467 | if test x_$withval = x_yes; then | |
468 | for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do | |
469 | if test -f "$dir/include/idna.h"; then | |
470 | CFLAGS="$CFLAGS -I$dir/include" | |
471 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
472 | AC_MSG_NOTICE([Found libidn in $dir]) | |
473 | break | |
474 | fi | |
475 | if test -f "$dir/include/idn/idna.h"; then | |
476 | CFLAGS="$CFLAGS -I$dir/include/idn" | |
477 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
478 | AC_MSG_NOTICE([Found libidn in $dir]) | |
479 | break | |
480 | fi | |
481 | done | |
482 | if test -f "/usr/include/idn/idna.h"; then | |
483 | CFLAGS="$CFLAGS -I/usr/include/idn" | |
484 | #LDFLAGS="$LDFLAGS -L/usr/lib" | |
485 | AC_MSG_NOTICE([Found libidn in /usr]) | |
444 | 486 | fi |
445 | if test -f "$dir/include/idn/idna.h"; then | |
446 | CFLAGS="$CFLAGS -I$dir/include/idn" | |
447 | LDFLAGS="$LDFLAGS -L$dir/lib" | |
448 | AC_MSG_NOTICE([Found libidn in $dir]) | |
449 | break | |
487 | else | |
488 | if test x_$withval != x_no; then | |
489 | CFLAGS="$CFLAGS -I$withval/include" | |
490 | LDFLAGS="$LDFLAGS -L$withval/lib" | |
491 | else | |
492 | my_with_libidn=0 | |
450 | 493 | fi |
451 | done | |
452 | if test -f "/usr/include/idn/idna.h"; then | |
453 | CFLAGS="$CFLAGS -I/usr/include/idn" | |
454 | #LDFLAGS="$LDFLAGS -L/usr/lib" | |
455 | AC_MSG_NOTICE([Found libidn in /usr]) | |
456 | fi | |
457 | else | |
458 | if test x_$withval != x_no; then | |
459 | CFLAGS="$CFLAGS -I$withval/include" | |
460 | LDFLAGS="$LDFLAGS -L$withval/lib" | |
461 | else | |
462 | my_with_libidn=0 | |
463 | 494 | fi |
464 | 495 | fi |
465 | 496 | |
876 | 907 | AC_SUBST(INSTALL_GETDNS_QUERY) |
877 | 908 | AC_SUBST(UNINSTALL_GETDNS_QUERY) |
878 | 909 | |
879 | AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile]) | |
910 | AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile getdns.pc]) | |
880 | 911 | if [ test -n "$DOXYGEN" ] |
881 | 912 | then AC_CONFIG_FILES([src/Doxyfile]) |
882 | 913 | fi |
927 | 958 | AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) |
928 | 959 | fi |
929 | 960 | AC_CHECK_DECLS([strlcpy,arc4random,arc4random_uniform]) |
961 | AC_REPLACE_FUNCS(inet_pton) | |
962 | AC_REPLACE_FUNCS(inet_ntop) | |
930 | 963 | AC_REPLACE_FUNCS(strlcpy) |
931 | 964 | AC_REPLACE_FUNCS(arc4random) |
932 | 965 | AC_REPLACE_FUNCS(arc4random_uniform) |
984 | 1017 | AC_SUBST(C99COMPATFLAGS) |
985 | 1018 | |
986 | 1019 | AH_BOTTOM([ |
1020 | ||
1021 | /* the version of the windows API enabled */ | |
1022 | #undef WINVER | |
1023 | #undef _WIN32_WINNT | |
1024 | #define WINVER 0x0600 // 0x0502 | |
1025 | #define _WIN32_WINNT 0x0600 // 0x0502 | |
1026 | #ifdef HAVE_WINSOCK2_H | |
1027 | #include <winsock2.h> | |
1028 | #include<BaseTsd.h> | |
1029 | #endif | |
1030 | ||
1031 | #ifdef HAVE_WS2TCPIP_H | |
1032 | #include <ws2tcpip.h> | |
1033 | #endif | |
1034 | ||
1035 | #ifndef USE_WINSOCK | |
1036 | #define ARG_LL "%ll" | |
1037 | #else | |
1038 | #define ARG_LL "%I64" | |
1039 | #endif | |
1040 | ||
1041 | /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ | |
1042 | #ifdef HAVE_WINSOCK2_H | |
1043 | #define FD_SET_T (u_int) | |
1044 | #else | |
1045 | #define FD_SET_T | |
1046 | #endif | |
1047 | ||
1048 | ||
987 | 1049 | #include <stdint.h> |
988 | 1050 | #include <stdio.h> |
989 | 1051 | #include <unistd.h> |
1040 | 1102 | unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest); |
1041 | 1103 | #endif /* COMPAT_SHA512 */ |
1042 | 1104 | |
1105 | #ifndef HAVE_INET_PTON | |
1106 | int inet_pton(int af, const char* src, void* dst); | |
1107 | #endif /* HAVE_INET_PTON */ | |
1108 | ||
1109 | #ifndef HAVE_INET_NTOP | |
1110 | const char *inet_ntop(int af, const void *src, char *dst, size_t size); | |
1111 | #endif | |
1112 | ||
1043 | 1113 | #ifdef __cplusplus |
1044 | 1114 | } |
1045 | 1115 | #endif |
1093 | 1163 | # define ATTR_UNUSED(x) x |
1094 | 1164 | #endif /* !HAVE_ATTR_UNUSED */ |
1095 | 1165 | |
1096 | /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ | |
1097 | #ifdef HAVE_WINSOCK2_H | |
1098 | #define FD_SET_T (u_int) | |
1099 | #else | |
1100 | #define FD_SET_T | |
1101 | #endif | |
1102 | ||
1103 | 1166 | #ifdef TIME_WITH_SYS_TIME |
1104 | 1167 | # include <sys/time.h> |
1105 | 1168 | # include <time.h> |
274 | 274 | Set to the DNS class number (other than Internet (IN) class desired in query. |
275 | 275 | |
276 | 276 | .HP 3 |
277 | "return_call_debugging" (int) | |
277 | "return_call_reporting" (int) | |
278 | 278 | |
279 | 279 | Set to GETDNS_EXTENSION_TRUE to add the name |
280 | .I call_debugging | |
280 | .I call_reporting | |
281 | 281 | (list) to the top level of the response object that includes a dict for each call made to the API. TBD: more detail |
282 | 282 | |
283 | 283 | .LP |
0 | prefix=@prefix@ | |
1 | exec_prefix=${prefix} | |
2 | libdir=${exec_prefix}/lib | |
3 | includedir=${prefix}/include | |
4 | ||
5 | Name: getdns | |
6 | Version: @GETDNS_VERSION@ | |
7 | Description: A modern asynchronous DNS library | |
8 | ||
9 | Libs: -L${libdir} -lgetdns | |
10 | Cflags: -I${includedir} |
163 | 163 | LTCC="gcc" |
164 | 164 | |
165 | 165 | # LTCC compiler flags. |
166 | LTCFLAGS="-g -O2 -Wall -D_BSD_SOURCE -I/usr/local/include" | |
166 | LTCFLAGS="-g -O2 -Wall -D_BSD_SOURCE -D_DEFAULT_SOURCE -I/usr/local/include" | |
167 | 167 | |
168 | 168 | # Take the output of nm and produce a listing of raw symbols and C names. |
169 | 169 | global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p' | sed '/ __gnu_lto/d'" |
0 | # Taken from acx_nlnetlabs.m4 - common macros for configure checks | |
1 | # Copyright 2009, Wouter Wijngaards, NLnet Labs. | |
2 | # BSD licensed. | |
3 | # | |
4 | ||
5 | dnl Check getaddrinfo. | |
6 | dnl Works on linux, solaris, bsd and windows(links winsock). | |
7 | dnl defines HAVE_GETADDRINFO, USE_WINSOCK. | |
8 | AC_DEFUN([ACX_CHECK_GETADDRINFO_WITH_INCLUDES], | |
9 | [AC_REQUIRE([AC_PROG_CC]) | |
10 | AC_MSG_CHECKING(for getaddrinfo) | |
11 | ac_cv_func_getaddrinfo=no | |
12 | AC_LINK_IFELSE( | |
13 | [AC_LANG_SOURCE([[ | |
14 | #ifdef __cplusplus | |
15 | extern "C" | |
16 | { | |
17 | #endif | |
18 | char* getaddrinfo(); | |
19 | char* (*f) () = getaddrinfo; | |
20 | #ifdef __cplusplus | |
21 | } | |
22 | #endif | |
23 | int main() { | |
24 | ; | |
25 | return 0; | |
26 | } | |
27 | ]])], | |
28 | dnl this case on linux, solaris, bsd | |
29 | [ac_cv_func_getaddrinfo="yes" | |
30 | dnl see if on windows | |
31 | if test "$ac_cv_header_windows_h" = "yes"; then | |
32 | AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) | |
33 | USE_WINSOCK="1" | |
34 | LIBS="$LIBS -lws2_32" | |
35 | fi | |
36 | ], | |
37 | dnl no quick getaddrinfo, try mingw32 and winsock2 library. | |
38 | ORIGLIBS="$LIBS" | |
39 | LIBS="$LIBS -lws2_32" | |
40 | AC_LINK_IFELSE( | |
41 | [AC_LANG_PROGRAM( | |
42 | [ | |
43 | #define _WIN32_WINNT 0x0501 | |
44 | #ifdef HAVE_WINDOWS_H | |
45 | #include <windows.h> | |
46 | #endif | |
47 | #ifdef HAVE_WINSOCK_H | |
48 | #include <winsock.h> | |
49 | #endif | |
50 | #ifdef HAVE_WINSOCK2_H | |
51 | #include <winsock2.h> | |
52 | #endif | |
53 | #include <stdio.h> | |
54 | #ifdef HAVE_WS2TCPIP_H | |
55 | #include <ws2tcpip.h> | |
56 | #endif | |
57 | ], | |
58 | [ | |
59 | (void)getaddrinfo(NULL, NULL, NULL, NULL); | |
60 | ] | |
61 | )], | |
62 | [ | |
63 | ac_cv_func_getaddrinfo="yes" | |
64 | dnl already: LIBS="$LIBS -lws2_32" | |
65 | AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) | |
66 | USE_WINSOCK="1" | |
67 | ], | |
68 | [ | |
69 | ac_cv_func_getaddrinfo="no" | |
70 | LIBS="$ORIGLIBS" | |
71 | ]) | |
72 | ) | |
73 | ||
74 | AC_MSG_RESULT($ac_cv_func_getaddrinfo) | |
75 | if test $ac_cv_func_getaddrinfo = yes; then | |
76 | AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether getaddrinfo is available]) | |
77 | fi | |
78 | ])dnl Endof AC_CHECK_GETADDRINFO_WITH_INCLUDES | |
79 | ||
80 | dnl End of file |
47 | 47 | fi |
48 | 48 | |
49 | 49 | AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto]) |
50 | LIBS="$LIBS -lcrypto -lssl" | |
51 | LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl" | |
50 | LIBS="$LIBS -lssl -lcrypto" | |
51 | LIBSSL_LIBS="$LIBSSL_LIBS -lssl -lcrypto" | |
52 | 52 | AC_TRY_LINK(, [ |
53 | 53 | int HMAC_CTX_init(void); |
54 | 54 | (void)HMAC_CTX_init(); |
132 | 132 | |
133 | 133 | depend: |
134 | 134 | (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) |
135 | (cd $(srcdir) ; gcc -MM -I. -I../../src *.c | \ | |
136 | sed -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ | |
137 | -e 's? \$$(srcdir)/config\.h? ../../src/config.h?g' \ | |
138 | -e 's? \.\./\.\./src/getdns/getdns_extra\.h? $$(srcdir)/../../src/getdns/getdns_extra.h?g' \ | |
135 | (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I../../src -I"$$blddir"/../../src *.c | \ | |
136 | sed -e "s? $$blddir/? ?g" \ | |
137 | -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ | |
138 | -e 's? \$$(srcdir)/\.\./\.\./src/config\.h? ../../src/config.h?g' \ | |
139 | -e 's? $$(srcdir)/\.\./\.\./src/getdns/getdns_extra\.h? ../../src/getdns/getdns_extra.h?g' \ | |
139 | 140 | -e 's? \.\./\.\./src/getdns/getdns_ext_libevent\.h? $$(srcdir)/../../src/getdns/getdns_ext_libevent.h?g' \ |
140 | 141 | -e 's? \.\./\.\./src/getdns/getdns_ext_libev\.h? $$(srcdir)/../../src/getdns/getdns_ext_libev.h?g' \ |
141 | 142 | -e 's? \.\./\.\./src/getdns/getdns_ext_libuv\.h? $$(srcdir)/../../src/getdns/getdns_ext_libuv.h?g' \ |
143 | -e 's? \.\./\.\./src/debug\.h? $$(srcdir)/../../src/debug.h?g' \ | |
142 | 144 | -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) |
143 | 145 | (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ |
144 | || mv Makefile.in.new Makefile.in ) | |
146 | || mv Makefile.in.new Makefile.in ) | |
145 | 147 | |
146 | 148 | |
147 | 149 | # Dependencies for the examples |
148 | 150 | example-all-functions.lo example-all-functions.o: $(srcdir)/example-all-functions.c $(srcdir)/getdns_libevent.h \ |
149 | 151 | ../../src/config.h ../../src/getdns/getdns.h \ |
150 | $(srcdir)/../../src/getdns/getdns_ext_libevent.h $(srcdir)/../../src/getdns/getdns_extra.h | |
152 | $(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h | |
151 | 153 | example-reverse.lo example-reverse.o: $(srcdir)/example-reverse.c $(srcdir)/getdns_libevent.h ../../src/config.h \ |
152 | 154 | ../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ |
153 | $(srcdir)/../../src/getdns/getdns_extra.h | |
155 | ../../src/getdns/getdns_extra.h | |
154 | 156 | example-simple-answers.lo example-simple-answers.o: $(srcdir)/example-simple-answers.c $(srcdir)/getdns_libevent.h \ |
155 | 157 | ../../src/config.h ../../src/getdns/getdns.h \ |
156 | $(srcdir)/../../src/getdns/getdns_ext_libevent.h $(srcdir)/../../src/getdns/getdns_extra.h | |
158 | $(srcdir)/../../src/getdns/getdns_ext_libevent.h ../../src/getdns/getdns_extra.h | |
157 | 159 | example-synchronous.lo example-synchronous.o: $(srcdir)/example-synchronous.c $(srcdir)/getdns_core_only.h \ |
158 | 160 | ../../src/getdns/getdns.h |
159 | 161 | example-tree.lo example-tree.o: $(srcdir)/example-tree.c $(srcdir)/getdns_libevent.h ../../src/config.h \ |
160 | 162 | ../../src/getdns/getdns.h $(srcdir)/../../src/getdns/getdns_ext_libevent.h \ |
161 | $(srcdir)/../../src/getdns/getdns_extra.h | |
163 | ../../src/getdns/getdns_extra.h |
93 | 93 | <p class=title2>Originally edited by Paul Hoffman</p> |
94 | 94 | <p class=title2>Currently maintained by the <a |
95 | 95 | href="mailto:team@getdnsapi.net">getdns team</a></p> |
96 | <p class=title2>Document version: "getdns October 2015"</p> | |
96 | <p class=title2>Document version: "getdns December 2015"</p> | |
97 | 97 | |
98 | 98 | <p>This document describes a modern asynchronous DNS API. This new API is intended to be useful to |
99 | 99 | application developers and operating system distributors as a way of making |
667 | 667 | |
668 | 668 | <li><code>specify_class</code></li> |
669 | 669 | |
670 | <li><code>return_call_debugging</code></li> | |
670 | <li><code>return_call_reporting</code></li> | |
671 | 671 | |
672 | 672 | </ul> |
673 | 673 | |
864 | 864 | <h2>3.6 Extensions Relating to the API</h2> |
865 | 865 | |
866 | 866 | <p>An application might want to see debugging information for queries such as the length of time it |
867 | takes for each query to return to the API. Use the <code>return_call_debugging</code> extension. The | |
867 | takes for each query to return to the API. Use the <code>return_call_reporting</code> extension. The | |
868 | 868 | extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to add the name |
869 | <code>call_debugging</code> (a list) to the top level of the response object. Each member of the | |
869 | <code>call_reporting</code> (a list) to the top level of the response object. Each member of the | |
870 | 870 | list is a dict that represents one call made for the call to the API. Each member has the following |
871 | 871 | names:</p> |
872 | 872 | |
874 | 874 | <li><code>query_name</code> (a bindata) is the name that was sent</li> |
875 | 875 | <li><code>query_type</code> (an int) is the type that was queried for</li> |
876 | 876 | <li><code>query_to</code> (a bindata) is the address to which the query was sent</li> |
877 | <li><code>start_time</code> (a bindata) is the time the query started in milliseconds since the epoch, | |
878 | represented as a uint64_t</li> | |
879 | <li><code>end_time</code> (a bindata) is the time the query was received in milliseconds since the epoch, | |
880 | represented as a uint64_t</li> | |
877 | <li><code>run_time</code> (a bindata) is the difference between the time the successful | |
878 | query started and ended in milliseconds, represented | |
879 | as a uint32_t (this does not include time taken for connection set up | |
880 | or transport fallback)</li> | |
881 | 881 | <li><code>entire_reply</code> (a bindata) is the entire response received</li> |
882 | 882 | <li><code>dnssec_result</code> (an int) is the DNSSEC status, or <code>GETDNS_DNSSEC_NOT_PERFORMED</code> |
883 | 883 | if DNSSEC validation was not performed</li> |
2146 | 2146 | Fallback transport options are specified by including multiple values in the list. |
2147 | 2147 | The values are <span class=default> |
2148 | 2148 | <code>GETDNS_TRANSPORT_UDP</code></span>, |
2149 | <code>GETDNS_TRANSPORT_TCP</code>, | |
2150 | <code>GETDNS_TRANSPORT_TLS</code>, or | |
2151 | <code>GETDNS_TRANSPORT_STARTTLS</code>. | |
2149 | <code>GETDNS_TRANSPORT_TCP</code>, or | |
2150 | <code>GETDNS_TRANSPORT_TLS</code>. | |
2152 | 2151 | The default is <span class=default> a list containing <code>GETDNS_TRANSPORT_UDP</code> then <code>GETDNS_TRANSPORT_TCP</code></span>.</p> |
2153 | 2152 | |
2154 | 2153 | <div class=forh> |
2157 | 2156 | getdns_context *context, |
2158 | 2157 | uint64_t timeout |
2159 | 2158 | );</div> |
2160 | <p class=cont>Specifies number of milliseconds the API will leave an idle TCP, TLS or STARTTLS connection open for (idle means no outstanding responses and no pending queries). | |
2159 | <p class=cont>Specifies number of milliseconds the API will leave an idle TCP or TLS connection open for (idle means no outstanding responses and no pending queries). | |
2161 | 2160 | The default is <span class=default>0</span>.</p> |
2162 | 2161 | |
2163 | 2162 | <div class=forh> |
2283 | 2282 | <code>port</code> to specify which port to use to contact these DNS servers; the default is 53. If |
2284 | 2283 | the stub and a recursive resolver both support TSIG (RFC 2845), the <code>upstream_list</code> entry |
2285 | 2284 | can also contain <code>tsig_algorithm</code> (a bindata) that is the name of the TSIG hash |
2286 | algorithm, and <code>tsig_secret</code> (a bindata) that is the TSIG key.</p> | |
2285 | algorithm, <code>tsig_name</code> (a bindata) that is the name of the TSIG key, and <code>tsig_secret</code> (a bindata) that is the TSIG key.</p> | |
2287 | 2286 | |
2288 | 2287 | <h2>8.8 Context for EDNS</h2> |
2289 | 2288 | |
2425 | 2424 | |
2426 | 2425 | <h1>9. The Generated Files</h1> |
2427 | 2426 | |
2428 | <p>There is <a href="getdns-0.701.tgz">a tarball</a> that includes the .h files, | |
2427 | <p>There is <a href="getdns-0.901.tgz">a tarball</a> that includes the .h files, | |
2429 | 2428 | the examples, and so on. The examples all make, even though there is no API implementation, based |
2430 | 2429 | on a pseudo-implementation in the tarball; see make-examples-PLATFORM.sh. Note that this currently builds fine |
2431 | 2430 | on the Macintosh and Ubuntu; help is definitely appreciated on making the build process |
63 | 63 | C99COMPATFLAGS=@C99COMPATFLAGS@ |
64 | 64 | |
65 | 65 | GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \ |
66 | list.lo request-internal.lo rr-dict.lo rr-iter.lo stub.lo sync.lo \ | |
67 | util-internal.lo | |
66 | list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \ | |
67 | rr-iter.lo stub.lo sync.lo util-internal.lo | |
68 | 68 | |
69 | 69 | GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \ |
70 | 70 | str2wire.lo |
73 | 73 | LIBOBJS=@LIBOBJS@ |
74 | 74 | COMPAT_OBJ=$(LIBOBJS:.o=.lo) |
75 | 75 | |
76 | UTIL_OBJ=mini_event.lo rbtree.lo val_secalgo.lo | |
76 | UTIL_OBJ=mini_event.lo winsock_event.lo rbtree.lo val_secalgo.lo | |
77 | 77 | |
78 | 78 | EXTENSION_OBJ=libmini_event.lo libevent.lo libev.lo |
79 | 79 | |
166 | 166 | distclean : clean |
167 | 167 | cd test && $(MAKE) $@ |
168 | 168 | rmdir test 2>/dev/null || true |
169 | rm -f Makefile config.status config.log Doxyfile config.h getdns/Makefile getdns/getdns.h | |
169 | rm -f Makefile config.status config.log Doxyfile config.h version.c getdns/Makefile getdns/getdns.h getdns/getdns_extra.h | |
170 | 170 | rmdir getdns 2>/dev/null || true |
171 | 171 | rmdir extension 2>/dev/null || true |
172 | 172 | rm -Rf autom4te.cache |
202 | 202 | |
203 | 203 | depend: |
204 | 204 | (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) |
205 | (cd $(srcdir) ; gcc -MM -I. *.c gldns/*.c compat/*.c util/*.c extension/*.c| \ | |
206 | sed -e 's?gldns/?$$(srcdir)/gldns/?g' \ | |
205 | (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" *.c gldns/*.c compat/*.c util/*.c extension/*.c| \ | |
206 | sed -e "s? $$blddir/? ?g" \ | |
207 | -e 's?gldns/?$$(srcdir)/gldns/?g' \ | |
207 | 208 | -e 's?compat/?$$(srcdir)/compat/?g' \ |
208 | 209 | -e 's?util/?$$(srcdir)/util/?g' \ |
209 | 210 | -e 's?extension/?$$(srcdir)/extension/?g' \ |
225 | 226 | # Dependencies for gldns, utils, the extensions and compat functions |
226 | 227 | const-info.lo const-info.o: $(srcdir)/const-info.c getdns/getdns.h getdns/getdns_extra.h \ |
227 | 228 | getdns/getdns.h $(srcdir)/const-info.h |
228 | context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ | |
229 | context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ | |
229 | 230 | $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ |
230 | 231 | getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ |
231 | 232 | config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ |
232 | 233 | $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ |
233 | $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h | |
234 | $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h | |
234 | 235 | convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \ |
235 | 236 | getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ |
236 | 237 | $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ |
237 | 238 | $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ |
238 | $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h | |
239 | dict.lo dict.o: $(srcdir)/dict.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ | |
240 | getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ | |
241 | $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ | |
242 | $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ | |
243 | $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h | |
244 | dnssec.lo dnssec.o: $(srcdir)/dnssec.c getdns/getdns.h config.h $(srcdir)/context.h \ | |
239 | $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h | |
240 | dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ | |
241 | getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ | |
242 | $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ | |
243 | $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ | |
244 | $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h | |
245 | dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ | |
245 | 246 | getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ |
246 | 247 | $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ |
247 | 248 | $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ |
252 | 253 | getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ |
253 | 254 | $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ |
254 | 255 | $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ |
255 | $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h | |
256 | $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/general.h | |
256 | 257 | list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ |
257 | 258 | getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ |
258 | 259 | $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ |
259 | 260 | $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ |
260 | 261 | $(srcdir)/list.h $(srcdir)/dict.h |
262 | pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \ | |
263 | $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \ | |
264 | $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ | |
265 | $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h | |
261 | 266 | request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \ |
262 | 267 | getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ |
263 | 268 | $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ |
264 | 269 | $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ |
265 | 270 | $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ |
266 | $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h | |
271 | $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/debug.h | |
267 | 272 | rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h getdns/getdns.h $(srcdir)/gldns/gbuffer.h \ |
268 | 273 | $(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \ |
269 | 274 | $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h config.h \ |
271 | 276 | $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h |
272 | 277 | rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/rr-dict.h config.h \ |
273 | 278 | $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h |
274 | stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ | |
279 | stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ | |
275 | 280 | getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ |
276 | $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/rr-iter.h \ | |
277 | $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h \ | |
278 | $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/util-internal.h $(srcdir)/general.h | |
281 | $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ | |
282 | $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h \ | |
283 | config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ | |
284 | $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h | |
279 | 285 | sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \ |
280 | 286 | getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ |
281 | 287 | config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/general.h \ |
282 | 288 | $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ |
283 | 289 | $(srcdir)/dnssec.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h |
284 | util-internal.lo util-internal.o: $(srcdir)/util-internal.c getdns/getdns.h $(srcdir)/dict.h $(srcdir)/util/rbtree.h \ | |
285 | $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/list.h \ | |
286 | $(srcdir)/util-internal.h config.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ | |
290 | util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \ | |
291 | $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \ | |
292 | $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ | |
287 | 293 | $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ |
288 | 294 | $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h |
289 | 295 | version.lo version.o: version.c |
306 | 312 | getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h |
307 | 313 | getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h |
308 | 314 | getentropy_win.lo getentropy_win.o: $(srcdir)/compat/getentropy_win.c |
315 | inet_ntop.lo inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h | |
316 | inet_pton.lo inet_pton.o: $(srcdir)/compat/inet_pton.c config.h | |
309 | 317 | sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h |
310 | 318 | strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h |
311 | 319 | mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ |
312 | 320 | $(srcdir)/util/fptr_wlist.h |
313 | rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/util-internal.h config.h \ | |
314 | $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \ | |
315 | $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ | |
316 | $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ | |
317 | $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/util/fptr_wlist.h | |
321 | rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/debug.h config.h \ | |
322 | $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h | |
318 | 323 | val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ |
319 | $(srcdir)/util-internal.h config.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ | |
320 | getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h \ | |
321 | $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ | |
322 | $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h \ | |
323 | $(srcdir)/gldns/gbuffer.h | |
324 | libev.lo libev.o: $(srcdir)/extension/libev.c $(srcdir)/getdns/getdns_ext_libev.h getdns/getdns.h \ | |
325 | getdns/getdns_extra.h $(srcdir)/types-internal.h getdns/getdns.h \ | |
326 | getdns/getdns_extra.h $(srcdir)/util/rbtree.h config.h | |
327 | libevent.lo libevent.o: $(srcdir)/extension/libevent.c $(srcdir)/getdns/getdns_ext_libevent.h \ | |
328 | getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h getdns/getdns.h \ | |
329 | getdns/getdns_extra.h $(srcdir)/util/rbtree.h config.h | |
330 | libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c $(srcdir)/extension/libmini_event.h \ | |
331 | config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h \ | |
324 | $(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h | |
325 | winsock_event.lo winsock_event.o: $(srcdir)/util/winsock_event.c config.h | |
326 | libev.lo libev.o: $(srcdir)/extension/libev.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ | |
327 | getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ | |
328 | $(srcdir)/getdns/getdns_ext_libev.h getdns/getdns_extra.h | |
329 | libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types-internal.h \ | |
332 | 330 | getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ |
333 | $(srcdir)/context.h config.h $(srcdir)/types-internal.h $(srcdir)/extension/libmini_event.h \ | |
334 | $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ | |
335 | $(srcdir)/gldns/pkthdr.h | |
336 | libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/getdns/getdns_ext_libuv.h \ | |
337 | getdns/getdns.h getdns/getdns_extra.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ | |
338 | getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ | |
339 | $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ | |
340 | $(srcdir)/types-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h | |
331 | $(srcdir)/getdns/getdns_ext_libevent.h getdns/getdns_extra.h | |
332 | libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.h \ | |
333 | $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \ | |
334 | $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h | |
335 | libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \ | |
336 | getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ | |
337 | $(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h |
32 | 32 | #include <sys/types.h> |
33 | 33 | #include <sys/param.h> |
34 | 34 | #include <sys/time.h> |
35 | #ifndef UB_ON_WINDOWS | |
35 | #ifndef GETDNS_ON_WINDOWS | |
36 | 36 | #include <sys/mman.h> |
37 | #else | |
38 | #include <wincrypt.h> | |
39 | #include <process.h> | |
40 | ||
41 | int getentropy(void *buf, size_t len); | |
42 | ||
43 | /* | |
44 | * On Windows, CryptGenRandom is supposed to be a well-seeded | |
45 | * cryptographically strong random number generator. | |
46 | */ | |
47 | int | |
48 | getentropy(void *buf, size_t len) | |
49 | { | |
50 | HCRYPTPROV provider; | |
51 | ||
52 | if (len > 256) { | |
53 | errno = EIO; | |
54 | return -1; | |
55 | } | |
56 | ||
57 | if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, | |
58 | CRYPT_VERIFYCONTEXT) == 0) | |
59 | goto fail; | |
60 | if (CryptGenRandom(provider, len, buf) == 0) { | |
61 | CryptReleaseContext(provider, 0); | |
62 | goto fail; | |
63 | } | |
64 | CryptReleaseContext(provider, 0); | |
65 | return (0); | |
66 | ||
67 | fail: | |
68 | errno = EIO; | |
69 | return (-1); | |
70 | } | |
37 | 71 | #endif |
38 | 72 | |
39 | 73 | #define KEYSTREAM_ONLY |
72 | 106 | return; |
73 | 107 | |
74 | 108 | if (rs == NULL) { |
75 | #ifndef UB_ON_WINDOWS | |
109 | #ifndef GETDNS_ON_WINDOWS | |
76 | 110 | if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE, |
77 | 111 | MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) |
78 | 112 | abort(); |
87 | 121 | #endif |
88 | 122 | } |
89 | 123 | if (rsx == NULL) { |
90 | #ifndef UB_ON_WINDOWS | |
124 | #ifndef GETDNS_ON_WINDOWS | |
91 | 125 | if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE, |
92 | 126 | MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) |
93 | 127 | abort(); |
15 | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | 17 | */ |
18 | ||
18 | 19 | #include "config.h" |
20 | #ifndef GETDNS_ON_WINDOWS | |
21 | ||
19 | 22 | |
20 | 23 | /* |
21 | 24 | #define _POSIX_C_SOURCE 199309L |
537 | 540 | errno = EIO; |
538 | 541 | return -1; |
539 | 542 | } |
543 | #endif ⏎ |
0 | /* From openssh 4.3p2 compat/inet_ntop.c */ | |
1 | /* Copyright (c) 1996 by Internet Software Consortium. | |
2 | * | |
3 | * Permission to use, copy, modify, and distribute this software for any | |
4 | * purpose with or without fee is hereby granted, provided that the above | |
5 | * copyright notice and this permission notice appear in all copies. | |
6 | * | |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | |
8 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
9 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | |
10 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
11 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
12 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
13 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
14 | * SOFTWARE. | |
15 | */ | |
16 | ||
17 | /* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */ | |
18 | ||
19 | #include <config.h> | |
20 | ||
21 | #ifndef HAVE_INET_NTOP | |
22 | ||
23 | #include <sys/param.h> | |
24 | #include <sys/types.h> | |
25 | #ifdef HAVE_SYS_SOCKET_H | |
26 | #include <sys/socket.h> | |
27 | #endif | |
28 | #ifdef HAVE_NETINET_IN_H | |
29 | #include <netinet/in.h> | |
30 | #endif | |
31 | #include <string.h> | |
32 | #include <errno.h> | |
33 | #include <stdio.h> | |
34 | ||
35 | #ifndef IN6ADDRSZ | |
36 | #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ | |
37 | #endif | |
38 | ||
39 | #ifndef INT16SZ | |
40 | #define INT16SZ 2 /* for systems without 16-bit ints */ | |
41 | #endif | |
42 | ||
43 | /* | |
44 | * WARNING: Don't even consider trying to compile this on a system where | |
45 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. | |
46 | */ | |
47 | ||
48 | static const char *inet_ntop4(const u_char *src, char *dst, size_t size); | |
49 | static const char *inet_ntop6(const u_char *src, char *dst, size_t size); | |
50 | ||
51 | /* char * | |
52 | * inet_ntop(af, src, dst, size) | |
53 | * convert a network format address to presentation format. | |
54 | * return: | |
55 | * pointer to presentation format address (`dst'), or NULL (see errno). | |
56 | * author: | |
57 | * Paul Vixie, 1996. | |
58 | */ | |
59 | const char * | |
60 | inet_ntop(int af, const void *src, char *dst, size_t size) | |
61 | { | |
62 | switch (af) { | |
63 | case AF_INET: | |
64 | return (inet_ntop4(src, dst, size)); | |
65 | case AF_INET6: | |
66 | return (inet_ntop6(src, dst, size)); | |
67 | default: | |
68 | #ifdef EAFNOSUPPORT | |
69 | errno = EAFNOSUPPORT; | |
70 | #else | |
71 | errno = ENOSYS; | |
72 | #endif | |
73 | return (NULL); | |
74 | } | |
75 | /* NOTREACHED */ | |
76 | } | |
77 | ||
78 | /* const char * | |
79 | * inet_ntop4(src, dst, size) | |
80 | * format an IPv4 address, more or less like inet_ntoa() | |
81 | * return: | |
82 | * `dst' (as a const) | |
83 | * notes: | |
84 | * (1) uses no statics | |
85 | * (2) takes a u_char* not an in_addr as input | |
86 | * author: | |
87 | * Paul Vixie, 1996. | |
88 | */ | |
89 | static const char * | |
90 | inet_ntop4(const u_char *src, char *dst, size_t size) | |
91 | { | |
92 | static const char fmt[] = "%u.%u.%u.%u"; | |
93 | char tmp[sizeof "255.255.255.255"]; | |
94 | int l; | |
95 | ||
96 | l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); | |
97 | if (l <= 0 || l >= (int)size) { | |
98 | errno = ENOSPC; | |
99 | return (NULL); | |
100 | } | |
101 | strlcpy(dst, tmp, size); | |
102 | return (dst); | |
103 | } | |
104 | ||
105 | /* const char * | |
106 | * inet_ntop6(src, dst, size) | |
107 | * convert IPv6 binary address into presentation (printable) format | |
108 | * author: | |
109 | * Paul Vixie, 1996. | |
110 | */ | |
111 | static const char * | |
112 | inet_ntop6(const u_char *src, char *dst, size_t size) | |
113 | { | |
114 | /* | |
115 | * Note that int32_t and int16_t need only be "at least" large enough | |
116 | * to contain a value of the specified size. On some systems, like | |
117 | * Crays, there is no such thing as an integer variable with 16 bits. | |
118 | * Keep this in mind if you think this function should have been coded | |
119 | * to use pointer overlays. All the world's not a VAX. | |
120 | */ | |
121 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; | |
122 | char *tp, *ep; | |
123 | struct { int base, len; } best, cur; | |
124 | u_int words[IN6ADDRSZ / INT16SZ]; | |
125 | int i; | |
126 | int advance; | |
127 | ||
128 | /* | |
129 | * Preprocess: | |
130 | * Copy the input (bytewise) array into a wordwise array. | |
131 | * Find the longest run of 0x00's in src[] for :: shorthanding. | |
132 | */ | |
133 | memset(words, '\0', sizeof words); | |
134 | for (i = 0; i < IN6ADDRSZ; i++) | |
135 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); | |
136 | best.base = -1; | |
137 | best.len = 0; | |
138 | cur.base = -1; | |
139 | cur.len = 0; | |
140 | for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { | |
141 | if (words[i] == 0) { | |
142 | if (cur.base == -1) | |
143 | cur.base = i, cur.len = 1; | |
144 | else | |
145 | cur.len++; | |
146 | } else { | |
147 | if (cur.base != -1) { | |
148 | if (best.base == -1 || cur.len > best.len) | |
149 | best = cur; | |
150 | cur.base = -1; | |
151 | } | |
152 | } | |
153 | } | |
154 | if (cur.base != -1) { | |
155 | if (best.base == -1 || cur.len > best.len) | |
156 | best = cur; | |
157 | } | |
158 | if (best.base != -1 && best.len < 2) | |
159 | best.base = -1; | |
160 | ||
161 | /* | |
162 | * Format the result. | |
163 | */ | |
164 | tp = tmp; | |
165 | ep = tmp + sizeof(tmp); | |
166 | for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { | |
167 | /* Are we inside the best run of 0x00's? */ | |
168 | if (best.base != -1 && i >= best.base && | |
169 | i < (best.base + best.len)) { | |
170 | if (i == best.base) { | |
171 | if (tp + 1 >= ep) | |
172 | return (NULL); | |
173 | *tp++ = ':'; | |
174 | } | |
175 | continue; | |
176 | } | |
177 | /* Are we following an initial run of 0x00s or any real hex? */ | |
178 | if (i != 0) { | |
179 | if (tp + 1 >= ep) | |
180 | return (NULL); | |
181 | *tp++ = ':'; | |
182 | } | |
183 | /* Is this address an encapsulated IPv4? */ | |
184 | if (i == 6 && best.base == 0 && | |
185 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { | |
186 | if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) | |
187 | return (NULL); | |
188 | tp += strlen(tp); | |
189 | break; | |
190 | } | |
191 | advance = snprintf(tp, ep - tp, "%x", words[i]); | |
192 | if (advance <= 0 || advance >= ep - tp) | |
193 | return (NULL); | |
194 | tp += advance; | |
195 | } | |
196 | /* Was it a trailing run of 0x00's? */ | |
197 | if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { | |
198 | if (tp + 1 >= ep) | |
199 | return (NULL); | |
200 | *tp++ = ':'; | |
201 | } | |
202 | if (tp + 1 >= ep) | |
203 | return (NULL); | |
204 | *tp++ = '\0'; | |
205 | ||
206 | /* | |
207 | * Check for overflow, copy, and we're done. | |
208 | */ | |
209 | if ((size_t)(tp - tmp) > size) { | |
210 | errno = ENOSPC; | |
211 | return (NULL); | |
212 | } | |
213 | strlcpy(dst, tmp, size); | |
214 | return (dst); | |
215 | } | |
216 | ||
217 | #endif /* !HAVE_INET_NTOP */ |
0 | /* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ | |
1 | ||
2 | /* Copyright (c) 1996 by Internet Software Consortium. | |
3 | * | |
4 | * Permission to use, copy, modify, and distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | |
9 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
10 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | |
11 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
12 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
13 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
14 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
15 | * SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <config.h> | |
19 | ||
20 | #include <string.h> | |
21 | #include <stdio.h> | |
22 | #include <errno.h> | |
23 | ||
24 | /* | |
25 | * WARNING: Don't even consider trying to compile this on a system where | |
26 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. | |
27 | */ | |
28 | ||
29 | static int inet_pton4 (const char *src, uint8_t *dst); | |
30 | static int inet_pton6 (const char *src, uint8_t *dst); | |
31 | ||
32 | /* | |
33 | * | |
34 | * The definitions we might miss. | |
35 | * | |
36 | */ | |
37 | #ifndef NS_INT16SZ | |
38 | #define NS_INT16SZ 2 | |
39 | #endif | |
40 | ||
41 | #ifndef NS_IN6ADDRSZ | |
42 | #define NS_IN6ADDRSZ 16 | |
43 | #endif | |
44 | ||
45 | #ifndef NS_INADDRSZ | |
46 | #define NS_INADDRSZ 4 | |
47 | #endif | |
48 | ||
49 | /* int | |
50 | * inet_pton(af, src, dst) | |
51 | * convert from presentation format (which usually means ASCII printable) | |
52 | * to network format (which is usually some kind of binary format). | |
53 | * return: | |
54 | * 1 if the address was valid for the specified address family | |
55 | * 0 if the address wasn't valid (`dst' is untouched in this case) | |
56 | * -1 if some other error occurred (`dst' is untouched in this case, too) | |
57 | * author: | |
58 | * Paul Vixie, 1996. | |
59 | */ | |
60 | int | |
61 | inet_pton(af, src, dst) | |
62 | int af; | |
63 | const char *src; | |
64 | void *dst; | |
65 | { | |
66 | switch (af) { | |
67 | case AF_INET: | |
68 | return (inet_pton4(src, dst)); | |
69 | case AF_INET6: | |
70 | return (inet_pton6(src, dst)); | |
71 | default: | |
72 | #ifdef EAFNOSUPPORT | |
73 | errno = EAFNOSUPPORT; | |
74 | #else | |
75 | errno = ENOSYS; | |
76 | #endif | |
77 | return (-1); | |
78 | } | |
79 | /* NOTREACHED */ | |
80 | } | |
81 | ||
82 | /* int | |
83 | * inet_pton4(src, dst) | |
84 | * like inet_aton() but without all the hexadecimal and shorthand. | |
85 | * return: | |
86 | * 1 if `src' is a valid dotted quad, else 0. | |
87 | * notice: | |
88 | * does not touch `dst' unless it's returning 1. | |
89 | * author: | |
90 | * Paul Vixie, 1996. | |
91 | */ | |
92 | static int | |
93 | inet_pton4(src, dst) | |
94 | const char *src; | |
95 | uint8_t *dst; | |
96 | { | |
97 | static const char digits[] = "0123456789"; | |
98 | int saw_digit, octets, ch; | |
99 | uint8_t tmp[NS_INADDRSZ], *tp; | |
100 | ||
101 | saw_digit = 0; | |
102 | octets = 0; | |
103 | *(tp = tmp) = 0; | |
104 | while ((ch = *src++) != '\0') { | |
105 | const char *pch; | |
106 | ||
107 | if ((pch = strchr(digits, ch)) != NULL) { | |
108 | uint32_t new = *tp * 10 + (pch - digits); | |
109 | ||
110 | if (new > 255) | |
111 | return (0); | |
112 | *tp = new; | |
113 | if (! saw_digit) { | |
114 | if (++octets > 4) | |
115 | return (0); | |
116 | saw_digit = 1; | |
117 | } | |
118 | } else if (ch == '.' && saw_digit) { | |
119 | if (octets == 4) | |
120 | return (0); | |
121 | *++tp = 0; | |
122 | saw_digit = 0; | |
123 | } else | |
124 | return (0); | |
125 | } | |
126 | if (octets < 4) | |
127 | return (0); | |
128 | ||
129 | memcpy(dst, tmp, NS_INADDRSZ); | |
130 | return (1); | |
131 | } | |
132 | ||
133 | /* int | |
134 | * inet_pton6(src, dst) | |
135 | * convert presentation level address to network order binary form. | |
136 | * return: | |
137 | * 1 if `src' is a valid [RFC1884 2.2] address, else 0. | |
138 | * notice: | |
139 | * (1) does not touch `dst' unless it's returning 1. | |
140 | * (2) :: in a full address is silently ignored. | |
141 | * credit: | |
142 | * inspired by Mark Andrews. | |
143 | * author: | |
144 | * Paul Vixie, 1996. | |
145 | */ | |
146 | static int | |
147 | inet_pton6(src, dst) | |
148 | const char *src; | |
149 | uint8_t *dst; | |
150 | { | |
151 | static const char xdigits_l[] = "0123456789abcdef", | |
152 | xdigits_u[] = "0123456789ABCDEF"; | |
153 | uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; | |
154 | const char *xdigits, *curtok; | |
155 | int ch, saw_xdigit; | |
156 | uint32_t val; | |
157 | ||
158 | memset((tp = tmp), '\0', NS_IN6ADDRSZ); | |
159 | endp = tp + NS_IN6ADDRSZ; | |
160 | colonp = NULL; | |
161 | /* Leading :: requires some special handling. */ | |
162 | if (*src == ':') | |
163 | if (*++src != ':') | |
164 | return (0); | |
165 | curtok = src; | |
166 | saw_xdigit = 0; | |
167 | val = 0; | |
168 | while ((ch = *src++) != '\0') { | |
169 | const char *pch; | |
170 | ||
171 | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) | |
172 | pch = strchr((xdigits = xdigits_u), ch); | |
173 | if (pch != NULL) { | |
174 | val <<= 4; | |
175 | val |= (pch - xdigits); | |
176 | if (val > 0xffff) | |
177 | return (0); | |
178 | saw_xdigit = 1; | |
179 | continue; | |
180 | } | |
181 | if (ch == ':') { | |
182 | curtok = src; | |
183 | if (!saw_xdigit) { | |
184 | if (colonp) | |
185 | return (0); | |
186 | colonp = tp; | |
187 | continue; | |
188 | } | |
189 | if (tp + NS_INT16SZ > endp) | |
190 | return (0); | |
191 | *tp++ = (uint8_t) (val >> 8) & 0xff; | |
192 | *tp++ = (uint8_t) val & 0xff; | |
193 | saw_xdigit = 0; | |
194 | val = 0; | |
195 | continue; | |
196 | } | |
197 | if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && | |
198 | inet_pton4(curtok, tp) > 0) { | |
199 | tp += NS_INADDRSZ; | |
200 | saw_xdigit = 0; | |
201 | break; /* '\0' was seen by inet_pton4(). */ | |
202 | } | |
203 | return (0); | |
204 | } | |
205 | if (saw_xdigit) { | |
206 | if (tp + NS_INT16SZ > endp) | |
207 | return (0); | |
208 | *tp++ = (uint8_t) (val >> 8) & 0xff; | |
209 | *tp++ = (uint8_t) val & 0xff; | |
210 | } | |
211 | if (colonp != NULL) { | |
212 | /* | |
213 | * Since some memmove()'s erroneously fail to handle | |
214 | * overlapping regions, we'll do the shift by hand. | |
215 | */ | |
216 | const int n = tp - colonp; | |
217 | int i; | |
218 | ||
219 | for (i = 1; i <= n; i++) { | |
220 | endp[- i] = colonp[n - i]; | |
221 | colonp[n - i] = 0; | |
222 | } | |
223 | tp = endp; | |
224 | } | |
225 | if (tp != endp) | |
226 | return (0); | |
227 | memcpy(dst, tmp, NS_IN6ADDRSZ); | |
228 | return (1); | |
229 | } |
16 | 16 | |
17 | 17 | /* The edns padding option code. */ |
18 | 18 | #undef EDNS_PADDING_OPCODE |
19 | ||
20 | /* Define this to enable Windows build. */ | |
21 | #undef GETDNS_ON_WINDOWS | |
19 | 22 | |
20 | 23 | /* Define to 1 if you have the `arc4random' function. */ |
21 | 24 | #undef HAVE_ARC4RANDOM |
90 | 93 | /* Define to 1 if you have the <event.h> header file. */ |
91 | 94 | #undef HAVE_EVENT_H |
92 | 95 | |
96 | /* Define to 1 if you have the `EVP_md5' function. */ | |
97 | #undef HAVE_EVP_MD5 | |
98 | ||
93 | 99 | /* Define to 1 if you have the `EVP_sha1' function. */ |
94 | 100 | #undef HAVE_EVP_SHA1 |
95 | 101 | |
102 | /* Define to 1 if you have the `EVP_sha224' function. */ | |
103 | #undef HAVE_EVP_SHA224 | |
104 | ||
96 | 105 | /* Define to 1 if you have the `EVP_sha256' function. */ |
97 | 106 | #undef HAVE_EVP_SHA256 |
98 | 107 | |
108 | /* Define to 1 if you have the `EVP_sha384' function. */ | |
109 | #undef HAVE_EVP_SHA384 | |
110 | ||
99 | 111 | /* Define to 1 if you have the `EVP_sha512' function. */ |
100 | 112 | #undef HAVE_EVP_SHA512 |
101 | 113 | |
108 | 120 | /* Define to 1 if you have the `FIPS_mode' function. */ |
109 | 121 | #undef HAVE_FIPS_MODE |
110 | 122 | |
123 | /* Whether getaddrinfo is available */ | |
124 | #undef HAVE_GETADDRINFO | |
125 | ||
111 | 126 | /* Define to 1 if you have the `getauxval' function. */ |
112 | 127 | #undef HAVE_GETAUXVAL |
113 | 128 | |
117 | 132 | /* If you have HMAC_CTX_init */ |
118 | 133 | #undef HAVE_HMAC_CTX_INIT |
119 | 134 | |
135 | /* Define to 1 if you have the `inet_ntop' function. */ | |
136 | #undef HAVE_INET_NTOP | |
137 | ||
138 | /* Define to 1 if you have the `inet_pton' function. */ | |
139 | #undef HAVE_INET_PTON | |
140 | ||
120 | 141 | /* Define to 1 if you have the <inttypes.h> header file. */ |
121 | 142 | #undef HAVE_INTTYPES_H |
122 | 143 | |
183 | 204 | /* Define to 1 if you have the <stdint.h> header file. */ |
184 | 205 | #undef HAVE_STDINT_H |
185 | 206 | |
207 | /* Define to 1 if you have the <stdio.h> header file. */ | |
208 | #undef HAVE_STDIO_H | |
209 | ||
186 | 210 | /* Define to 1 if you have the <stdlib.h> header file. */ |
187 | 211 | #undef HAVE_STDLIB_H |
188 | 212 | |
227 | 251 | |
228 | 252 | /* Define to 1 if you have the <uv.h> header file. */ |
229 | 253 | #undef HAVE_UV_H |
254 | ||
255 | /* Define to 1 if you have the <windows.h> header file. */ | |
256 | #undef HAVE_WINDOWS_H | |
257 | ||
258 | /* Define to 1 if you have the <winsock2.h> header file. */ | |
259 | #undef HAVE_WINSOCK2_H | |
260 | ||
261 | /* Define to 1 if you have the <winsock.h> header file. */ | |
262 | #undef HAVE_WINSOCK_H | |
263 | ||
264 | /* Define to 1 if you have the <ws2tcpip.h> header file. */ | |
265 | #undef HAVE_WS2TCPIP_H | |
230 | 266 | |
231 | 267 | /* Define to the sub-directory in which libtool stores uninstalled libraries. |
232 | 268 | */ |
289 | 325 | /* Needed for sync stub resolver functions */ |
290 | 326 | #undef USE_MINI_EVENT |
291 | 327 | |
328 | /* Define this to enable TCP fast open. */ | |
329 | #undef USE_OSX_TCP_FASTOPEN | |
330 | ||
292 | 331 | /* Define this to enable SHA256 and SHA512 support. */ |
293 | 332 | #undef USE_SHA2 |
294 | 333 | |
295 | 334 | /* Define this to enable TCP fast open. */ |
296 | 335 | #undef USE_TCP_FASTOPEN |
336 | ||
337 | /* Whether the windows socket API is used */ | |
338 | #undef USE_WINSOCK | |
297 | 339 | |
298 | 340 | /* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>, |
299 | 341 | <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the |
328 | 370 | /* Define to the type of an unsigned integer type of width exactly 8 bits if |
329 | 371 | such a type exists and the standard includes do not define it. */ |
330 | 372 | #undef uint8_t |
373 | ||
374 | ||
375 | ||
376 | /* the version of the windows API enabled */ | |
377 | #undef WINVER | |
378 | #undef _WIN32_WINNT | |
379 | #define WINVER 0x0600 // 0x0502 | |
380 | #define _WIN32_WINNT 0x0600 // 0x0502 | |
381 | #ifdef HAVE_WINSOCK2_H | |
382 | #include <winsock2.h> | |
383 | #include<BaseTsd.h> | |
384 | #endif | |
385 | ||
386 | #ifdef HAVE_WS2TCPIP_H | |
387 | #include <ws2tcpip.h> | |
388 | #endif | |
389 | ||
390 | #ifndef USE_WINSOCK | |
391 | #define ARG_LL "%ll" | |
392 | #else | |
393 | #define ARG_LL "%I64" | |
394 | #endif | |
395 | ||
396 | /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ | |
397 | #ifdef HAVE_WINSOCK2_H | |
398 | #define FD_SET_T (u_int) | |
399 | #else | |
400 | #define FD_SET_T | |
401 | #endif | |
331 | 402 | |
332 | 403 | |
333 | 404 | #include <stdint.h> |
386 | 457 | unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest); |
387 | 458 | #endif /* COMPAT_SHA512 */ |
388 | 459 | |
460 | #ifndef HAVE_INET_PTON | |
461 | int inet_pton(int af, const char* src, void* dst); | |
462 | #endif /* HAVE_INET_PTON */ | |
463 | ||
464 | #ifndef HAVE_INET_NTOP | |
465 | const char *inet_ntop(int af, const void *src, char *dst, size_t size); | |
466 | #endif | |
467 | ||
389 | 468 | #ifdef __cplusplus |
390 | 469 | } |
391 | 470 | #endif |
439 | 518 | # define ATTR_UNUSED(x) x |
440 | 519 | #endif /* !HAVE_ATTR_UNUSED */ |
441 | 520 | |
442 | /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ | |
443 | #ifdef HAVE_WINSOCK2_H | |
444 | #define FD_SET_T (u_int) | |
445 | #else | |
446 | #define FD_SET_T | |
447 | #endif | |
448 | ||
449 | 521 | #ifdef TIME_WITH_SYS_TIME |
450 | 522 | # include <sys/time.h> |
451 | 523 | # include <time.h> |
6 | 6 | #include "const-info.h" |
7 | 7 | |
8 | 8 | static struct const_info consts_info[] = { |
9 | { -1, NULL, "/* <unknown getdns value> */" }, | |
10 | { 0, "GETDNS_RETURN_GOOD", GETDNS_RETURN_GOOD_TEXT }, | |
11 | { 1, "GETDNS_RETURN_GENERIC_ERROR", GETDNS_RETURN_GENERIC_ERROR_TEXT }, | |
12 | { 300, "GETDNS_RETURN_BAD_DOMAIN_NAME", GETDNS_RETURN_BAD_DOMAIN_NAME_TEXT }, | |
13 | { 301, "GETDNS_RETURN_BAD_CONTEXT", GETDNS_RETURN_BAD_CONTEXT_TEXT }, | |
14 | { 302, "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", GETDNS_RETURN_CONTEXT_UPDATE_FAIL_TEXT }, | |
15 | { 303, "GETDNS_RETURN_UNKNOWN_TRANSACTION", GETDNS_RETURN_UNKNOWN_TRANSACTION_TEXT }, | |
16 | { 304, "GETDNS_RETURN_NO_SUCH_LIST_ITEM", GETDNS_RETURN_NO_SUCH_LIST_ITEM_TEXT }, | |
17 | { 305, "GETDNS_RETURN_NO_SUCH_DICT_NAME", GETDNS_RETURN_NO_SUCH_DICT_NAME_TEXT }, | |
18 | { 306, "GETDNS_RETURN_WRONG_TYPE_REQUESTED", GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT }, | |
19 | { 307, "GETDNS_RETURN_NO_SUCH_EXTENSION", GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT }, | |
20 | { 308, "GETDNS_RETURN_EXTENSION_MISFORMAT", GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT }, | |
21 | { 309, "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED_TEXT }, | |
22 | { 310, "GETDNS_RETURN_MEMORY_ERROR", GETDNS_RETURN_MEMORY_ERROR_TEXT }, | |
23 | { 311, "GETDNS_RETURN_INVALID_PARAMETER", GETDNS_RETURN_INVALID_PARAMETER_TEXT }, | |
24 | { 400, "GETDNS_DNSSEC_SECURE", GETDNS_DNSSEC_SECURE_TEXT }, | |
25 | { 401, "GETDNS_DNSSEC_BOGUS", GETDNS_DNSSEC_BOGUS_TEXT }, | |
26 | { 402, "GETDNS_DNSSEC_INDETERMINATE", GETDNS_DNSSEC_INDETERMINATE_TEXT }, | |
27 | { 403, "GETDNS_DNSSEC_INSECURE", GETDNS_DNSSEC_INSECURE_TEXT }, | |
28 | { 404, "GETDNS_DNSSEC_NOT_PERFORMED", GETDNS_DNSSEC_NOT_PERFORMED_TEXT }, | |
29 | { 500, "GETDNS_NAMESPACE_DNS", GETDNS_NAMESPACE_DNS_TEXT }, | |
30 | { 501, "GETDNS_NAMESPACE_LOCALNAMES", GETDNS_NAMESPACE_LOCALNAMES_TEXT }, | |
31 | { 502, "GETDNS_NAMESPACE_NETBIOS", GETDNS_NAMESPACE_NETBIOS_TEXT }, | |
32 | { 503, "GETDNS_NAMESPACE_MDNS", GETDNS_NAMESPACE_MDNS_TEXT }, | |
33 | { 504, "GETDNS_NAMESPACE_NIS", GETDNS_NAMESPACE_NIS_TEXT }, | |
34 | { 520, "GETDNS_RESOLUTION_STUB", GETDNS_RESOLUTION_STUB_TEXT }, | |
35 | { 521, "GETDNS_RESOLUTION_RECURSING", GETDNS_RESOLUTION_RECURSING_TEXT }, | |
36 | { 530, "GETDNS_REDIRECTS_FOLLOW", GETDNS_REDIRECTS_FOLLOW_TEXT }, | |
37 | { 531, "GETDNS_REDIRECTS_DO_NOT_FOLLOW", GETDNS_REDIRECTS_DO_NOT_FOLLOW_TEXT }, | |
38 | { 540, "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP_TEXT }, | |
39 | { 541, "GETDNS_TRANSPORT_UDP_ONLY", GETDNS_TRANSPORT_UDP_ONLY_TEXT }, | |
40 | { 542, "GETDNS_TRANSPORT_TCP_ONLY", GETDNS_TRANSPORT_TCP_ONLY_TEXT }, | |
41 | { 543, "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT }, | |
42 | { 544, "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT }, | |
43 | { 545, "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT }, | |
44 | { 546, "GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT }, | |
45 | { 550, "GETDNS_APPEND_NAME_ALWAYS", GETDNS_APPEND_NAME_ALWAYS_TEXT }, | |
46 | { 551, "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT }, | |
47 | { 552, "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT }, | |
48 | { 553, "GETDNS_APPEND_NAME_NEVER", GETDNS_APPEND_NAME_NEVER_TEXT }, | |
49 | { 600, "GETDNS_CONTEXT_CODE_NAMESPACES", GETDNS_CONTEXT_CODE_NAMESPACES_TEXT }, | |
50 | { 601, "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", GETDNS_CONTEXT_CODE_RESOLUTION_TYPE_TEXT }, | |
51 | { 602, "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS_TEXT }, | |
52 | { 603, "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS_TEXT }, | |
53 | { 604, "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS_TEXT }, | |
54 | { 605, "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", GETDNS_CONTEXT_CODE_DNS_TRANSPORT_TEXT }, | |
55 | { 606, "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES_TEXT }, | |
56 | { 607, "GETDNS_CONTEXT_CODE_APPEND_NAME", GETDNS_CONTEXT_CODE_APPEND_NAME_TEXT }, | |
57 | { 608, "GETDNS_CONTEXT_CODE_SUFFIX", GETDNS_CONTEXT_CODE_SUFFIX_TEXT }, | |
58 | { 609, "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS_TEXT }, | |
59 | { 610, "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE_TEXT }, | |
60 | { 611, "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE_TEXT }, | |
61 | { 612, "GETDNS_CONTEXT_CODE_EDNS_VERSION", GETDNS_CONTEXT_CODE_EDNS_VERSION_TEXT }, | |
62 | { 613, "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", GETDNS_CONTEXT_CODE_EDNS_DO_BIT_TEXT }, | |
63 | { 614, "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT }, | |
64 | { 615, "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT }, | |
65 | { 616, "GETDNS_CONTEXT_CODE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_TEXT }, | |
66 | { 617, "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", GETDNS_CONTEXT_CODE_IDLE_TIMEOUT_TEXT }, | |
67 | { 618, "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT }, | |
68 | { 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT }, | |
69 | { 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT }, | |
70 | { 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT }, | |
71 | { 703, "GETDNS_CALLBACK_ERROR", GETDNS_CALLBACK_ERROR_TEXT }, | |
72 | { 800, "GETDNS_NAMETYPE_DNS", GETDNS_NAMETYPE_DNS_TEXT }, | |
73 | { 801, "GETDNS_NAMETYPE_WINS", GETDNS_NAMETYPE_WINS_TEXT }, | |
74 | { 900, "GETDNS_RESPSTATUS_GOOD", GETDNS_RESPSTATUS_GOOD_TEXT }, | |
75 | { 901, "GETDNS_RESPSTATUS_NO_NAME", GETDNS_RESPSTATUS_NO_NAME_TEXT }, | |
76 | { 902, "GETDNS_RESPSTATUS_ALL_TIMEOUT", GETDNS_RESPSTATUS_ALL_TIMEOUT_TEXT }, | |
77 | { 903, "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", GETDNS_RESPSTATUS_NO_SECURE_ANSWERS_TEXT }, | |
78 | { 904, "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS_TEXT }, | |
9 | { -1, NULL, "/* <unknown getdns value> */" }, | |
10 | { 0, "GETDNS_RETURN_GOOD", GETDNS_RETURN_GOOD_TEXT }, | |
11 | { 1, "GETDNS_RETURN_GENERIC_ERROR", GETDNS_RETURN_GENERIC_ERROR_TEXT }, | |
12 | { 300, "GETDNS_RETURN_BAD_DOMAIN_NAME", GETDNS_RETURN_BAD_DOMAIN_NAME_TEXT }, | |
13 | { 301, "GETDNS_RETURN_BAD_CONTEXT", GETDNS_RETURN_BAD_CONTEXT_TEXT }, | |
14 | { 302, "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", GETDNS_RETURN_CONTEXT_UPDATE_FAIL_TEXT }, | |
15 | { 303, "GETDNS_RETURN_UNKNOWN_TRANSACTION", GETDNS_RETURN_UNKNOWN_TRANSACTION_TEXT }, | |
16 | { 304, "GETDNS_RETURN_NO_SUCH_LIST_ITEM", GETDNS_RETURN_NO_SUCH_LIST_ITEM_TEXT }, | |
17 | { 305, "GETDNS_RETURN_NO_SUCH_DICT_NAME", GETDNS_RETURN_NO_SUCH_DICT_NAME_TEXT }, | |
18 | { 306, "GETDNS_RETURN_WRONG_TYPE_REQUESTED", GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT }, | |
19 | { 307, "GETDNS_RETURN_NO_SUCH_EXTENSION", GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT }, | |
20 | { 308, "GETDNS_RETURN_EXTENSION_MISFORMAT", GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT }, | |
21 | { 309, "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED_TEXT }, | |
22 | { 310, "GETDNS_RETURN_MEMORY_ERROR", GETDNS_RETURN_MEMORY_ERROR_TEXT }, | |
23 | { 311, "GETDNS_RETURN_INVALID_PARAMETER", GETDNS_RETURN_INVALID_PARAMETER_TEXT }, | |
24 | { 312, "GETDNS_RETURN_NOT_IMPLEMENTED", GETDNS_RETURN_NOT_IMPLEMENTED_TEXT }, | |
25 | { 399, "GETDNS_RETURN_NEED_MORE_SPACE", GETDNS_RETURN_NEED_MORE_SPACE_TEXT }, | |
26 | { 400, "GETDNS_DNSSEC_SECURE", GETDNS_DNSSEC_SECURE_TEXT }, | |
27 | { 401, "GETDNS_DNSSEC_BOGUS", GETDNS_DNSSEC_BOGUS_TEXT }, | |
28 | { 402, "GETDNS_DNSSEC_INDETERMINATE", GETDNS_DNSSEC_INDETERMINATE_TEXT }, | |
29 | { 403, "GETDNS_DNSSEC_INSECURE", GETDNS_DNSSEC_INSECURE_TEXT }, | |
30 | { 404, "GETDNS_DNSSEC_NOT_PERFORMED", GETDNS_DNSSEC_NOT_PERFORMED_TEXT }, | |
31 | { 500, "GETDNS_NAMESPACE_DNS", GETDNS_NAMESPACE_DNS_TEXT }, | |
32 | { 501, "GETDNS_NAMESPACE_LOCALNAMES", GETDNS_NAMESPACE_LOCALNAMES_TEXT }, | |
33 | { 502, "GETDNS_NAMESPACE_NETBIOS", GETDNS_NAMESPACE_NETBIOS_TEXT }, | |
34 | { 503, "GETDNS_NAMESPACE_MDNS", GETDNS_NAMESPACE_MDNS_TEXT }, | |
35 | { 504, "GETDNS_NAMESPACE_NIS", GETDNS_NAMESPACE_NIS_TEXT }, | |
36 | { 520, "GETDNS_RESOLUTION_STUB", GETDNS_RESOLUTION_STUB_TEXT }, | |
37 | { 521, "GETDNS_RESOLUTION_RECURSING", GETDNS_RESOLUTION_RECURSING_TEXT }, | |
38 | { 530, "GETDNS_REDIRECTS_FOLLOW", GETDNS_REDIRECTS_FOLLOW_TEXT }, | |
39 | { 531, "GETDNS_REDIRECTS_DO_NOT_FOLLOW", GETDNS_REDIRECTS_DO_NOT_FOLLOW_TEXT }, | |
40 | { 540, "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP_TEXT }, | |
41 | { 541, "GETDNS_TRANSPORT_UDP_ONLY", GETDNS_TRANSPORT_UDP_ONLY_TEXT }, | |
42 | { 542, "GETDNS_TRANSPORT_TCP_ONLY", GETDNS_TRANSPORT_TCP_ONLY_TEXT }, | |
43 | { 543, "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT }, | |
44 | { 544, "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT }, | |
45 | { 545, "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT }, | |
46 | { 550, "GETDNS_APPEND_NAME_ALWAYS", GETDNS_APPEND_NAME_ALWAYS_TEXT }, | |
47 | { 551, "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT }, | |
48 | { 552, "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT }, | |
49 | { 553, "GETDNS_APPEND_NAME_NEVER", GETDNS_APPEND_NAME_NEVER_TEXT }, | |
50 | { 600, "GETDNS_CONTEXT_CODE_NAMESPACES", GETDNS_CONTEXT_CODE_NAMESPACES_TEXT }, | |
51 | { 601, "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", GETDNS_CONTEXT_CODE_RESOLUTION_TYPE_TEXT }, | |
52 | { 602, "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS_TEXT }, | |
53 | { 603, "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS_TEXT }, | |
54 | { 604, "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS_TEXT }, | |
55 | { 605, "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", GETDNS_CONTEXT_CODE_DNS_TRANSPORT_TEXT }, | |
56 | { 606, "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES_TEXT }, | |
57 | { 607, "GETDNS_CONTEXT_CODE_APPEND_NAME", GETDNS_CONTEXT_CODE_APPEND_NAME_TEXT }, | |
58 | { 608, "GETDNS_CONTEXT_CODE_SUFFIX", GETDNS_CONTEXT_CODE_SUFFIX_TEXT }, | |
59 | { 609, "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS_TEXT }, | |
60 | { 610, "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE_TEXT }, | |
61 | { 611, "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE_TEXT }, | |
62 | { 612, "GETDNS_CONTEXT_CODE_EDNS_VERSION", GETDNS_CONTEXT_CODE_EDNS_VERSION_TEXT }, | |
63 | { 613, "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", GETDNS_CONTEXT_CODE_EDNS_DO_BIT_TEXT }, | |
64 | { 614, "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT }, | |
65 | { 615, "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT }, | |
66 | { 616, "GETDNS_CONTEXT_CODE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_TEXT }, | |
67 | { 617, "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", GETDNS_CONTEXT_CODE_IDLE_TIMEOUT_TEXT }, | |
68 | { 618, "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT }, | |
69 | { 619, "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT }, | |
70 | { 620, "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT }, | |
71 | { 621, "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT }, | |
72 | { 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT }, | |
73 | { 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT }, | |
74 | { 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT }, | |
75 | { 703, "GETDNS_CALLBACK_ERROR", GETDNS_CALLBACK_ERROR_TEXT }, | |
76 | { 800, "GETDNS_NAMETYPE_DNS", GETDNS_NAMETYPE_DNS_TEXT }, | |
77 | { 801, "GETDNS_NAMETYPE_WINS", GETDNS_NAMETYPE_WINS_TEXT }, | |
78 | { 900, "GETDNS_RESPSTATUS_GOOD", GETDNS_RESPSTATUS_GOOD_TEXT }, | |
79 | { 901, "GETDNS_RESPSTATUS_NO_NAME", GETDNS_RESPSTATUS_NO_NAME_TEXT }, | |
80 | { 902, "GETDNS_RESPSTATUS_ALL_TIMEOUT", GETDNS_RESPSTATUS_ALL_TIMEOUT_TEXT }, | |
81 | { 903, "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", GETDNS_RESPSTATUS_NO_SECURE_ANSWERS_TEXT }, | |
82 | { 904, "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS_TEXT }, | |
79 | 83 | { 1000, "GETDNS_EXTENSION_TRUE", GETDNS_EXTENSION_TRUE_TEXT }, |
80 | 84 | { 1001, "GETDNS_EXTENSION_FALSE", GETDNS_EXTENSION_FALSE_TEXT }, |
81 | 85 | { 1100, "GETDNS_BAD_DNS_CNAME_IN_TARGET", GETDNS_BAD_DNS_CNAME_IN_TARGET_TEXT }, |
84 | 88 | { 1200, "GETDNS_TRANSPORT_UDP", GETDNS_TRANSPORT_UDP_TEXT }, |
85 | 89 | { 1201, "GETDNS_TRANSPORT_TCP", GETDNS_TRANSPORT_TCP_TEXT }, |
86 | 90 | { 1202, "GETDNS_TRANSPORT_TLS", GETDNS_TRANSPORT_TLS_TEXT }, |
87 | { 1203, "GETDNS_TRANSPORT_STARTTLS", GETDNS_TRANSPORT_STARTTLS_TEXT }, | |
88 | 91 | { 1300, "GETDNS_AUTHENTICATION_NONE", GETDNS_AUTHENTICATION_NONE_TEXT }, |
89 | { 1301, "GETDNS_AUTHENTICATION_HOSTNAME", GETDNS_AUTHENTICATION_HOSTNAME_TEXT }, | |
92 | { 1301, "GETDNS_AUTHENTICATION_REQUIRED", GETDNS_AUTHENTICATION_REQUIRED_TEXT }, | |
90 | 93 | }; |
91 | 94 | |
92 | 95 | static int const_info_cmp(const void *a, const void *b) |
33 | 33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | 34 | */ |
35 | 35 | |
36 | #include "config.h" | |
37 | ||
38 | #ifndef USE_WINSOCK | |
36 | 39 | #include <arpa/inet.h> |
40 | #include <sys/time.h> | |
41 | #include <netdb.h> | |
42 | #else | |
43 | #include <winsock2.h> | |
44 | #include <iphlpapi.h> | |
45 | typedef unsigned short in_port_t; | |
46 | #endif | |
47 | ||
48 | #include <sys/stat.h> | |
37 | 49 | #include <string.h> |
38 | 50 | #include <stdio.h> |
39 | 51 | #include <stdlib.h> |
40 | #include <sys/stat.h> | |
41 | #include <sys/time.h> | |
52 | ||
42 | 53 | #include <assert.h> |
43 | #include <netdb.h> | |
44 | 54 | #include <ctype.h> |
45 | 55 | |
46 | 56 | #include "config.h" |
57 | #include "debug.h" | |
47 | 58 | #include "gldns/str2wire.h" |
48 | 59 | #include "gldns/wire2str.h" |
49 | 60 | #include "context.h" |
52 | 63 | #include "dnssec.h" |
53 | 64 | #include "stub.h" |
54 | 65 | #include "list.h" |
66 | #include "dict.h" | |
67 | #include "pubkey-pinning.h" | |
55 | 68 | |
56 | 69 | #define GETDNS_PORT_ZERO 0 |
57 | 70 | #define GETDNS_PORT_DNS 53 |
69 | 82 | uint8_t host_name[]; |
70 | 83 | } host_name_addrs; |
71 | 84 | |
85 | ||
86 | /* If changing these lists also remember to | |
87 | change the value of GETDNS_UPSTREAM_TRANSPORTS */ | |
72 | 88 | static getdns_transport_list_t |
73 | 89 | getdns_upstream_transports[GETDNS_UPSTREAM_TRANSPORTS] = { |
74 | GETDNS_TRANSPORT_STARTTLS, // Define before TCP to ease fallback | |
75 | 90 | GETDNS_TRANSPORT_TCP, |
76 | 91 | GETDNS_TRANSPORT_TLS, |
77 | 92 | }; |
79 | 94 | static in_port_t |
80 | 95 | getdns_port_array[GETDNS_UPSTREAM_TRANSPORTS] = { |
81 | 96 | GETDNS_PORT_DNS, |
82 | GETDNS_PORT_DNS, | |
83 | 97 | GETDNS_PORT_DNS_OVER_TLS |
84 | 98 | }; |
85 | 99 | |
86 | char* | |
100 | static char* | |
87 | 101 | getdns_port_str_array[] = { |
88 | GETDNS_STR_PORT_DNS, | |
89 | 102 | GETDNS_STR_PORT_DNS, |
90 | 103 | GETDNS_STR_PORT_DNS_OVER_TLS |
91 | 104 | }; |
92 | 105 | |
106 | static const uint8_t no_suffixes[] = { 1, 0 }; | |
107 | ||
93 | 108 | /* Private functions */ |
94 | 109 | static getdns_return_t create_default_namespaces(struct getdns_context *context); |
95 | 110 | static getdns_return_t create_default_dns_transports(struct getdns_context *context); |
96 | static struct getdns_list *create_default_root_servers(void); | |
97 | static getdns_return_t set_os_defaults(struct getdns_context *); | |
98 | 111 | static int transaction_id_cmp(const void *, const void *); |
99 | 112 | static void dispatch_updated(struct getdns_context *, uint16_t); |
100 | 113 | static void cancel_dns_req(getdns_dns_req *); |
165 | 178 | { |
166 | 179 | uint8_t *next_label; |
167 | 180 | |
168 | while (*dname) { | |
181 | while (*dname && !(*dname & 0xC0)) { | |
169 | 182 | next_label = dname + *dname + 1; |
170 | 183 | dname += 1; |
171 | 184 | while (dname < next_label) { |
355 | 368 | int start_of_line = 1; |
356 | 369 | getdns_dict *address = NULL; |
357 | 370 | |
371 | #ifdef USE_WINSOCK | |
372 | in = fopen("c:\\WINDOWS\\system32\\drivers\\etc\\hosts", "r"); | |
373 | #else | |
358 | 374 | in = fopen("/etc/hosts", "r"); |
375 | #endif | |
359 | 376 | while (fgets(pos, (int)(sizeof(buf) - (pos - buf)), in)) { |
360 | 377 | pos = buf; |
361 | 378 | /* Break out of for to read more */ |
437 | 454 | } |
438 | 455 | |
439 | 456 | /** |
440 | * Helper to get the default root servers. | |
441 | * TODO: Implement | |
442 | */ | |
443 | static struct getdns_list * | |
444 | create_default_root_servers() | |
445 | { | |
446 | return NULL; | |
447 | } | |
448 | ||
449 | /** | |
450 | 457 | * check a file for changes since the last check |
451 | 458 | * and refresh the current data if changes are detected |
452 | 459 | * @param context pointer to a previously created context to be used for this call |
523 | 530 | ; upstreams->count |
524 | 531 | ; upstreams->count--, upstream++ ) { |
525 | 532 | |
533 | sha256_pin_t *pin = upstream->tls_pubkey_pinset; | |
526 | 534 | if (upstream->loop && ( upstream->event.read_cb |
527 | 535 | || upstream->event.write_cb |
528 | 536 | || upstream->event.timeout_cb) ) { |
538 | 546 | } |
539 | 547 | if (upstream->fd != -1) |
540 | 548 | close(upstream->fd); |
549 | while (pin) { | |
550 | sha256_pin_t *nextpin = pin->next; | |
551 | GETDNS_FREE(upstreams->mf, pin); | |
552 | pin = nextpin; | |
553 | } | |
554 | upstream->tls_pubkey_pinset = NULL; | |
541 | 555 | } |
542 | 556 | GETDNS_FREE(upstreams->mf, upstreams); |
543 | 557 | } |
556 | 570 | upstream->tcp.write_error = 0; |
557 | 571 | upstream->writes_done = 0; |
558 | 572 | upstream->responses_received = 0; |
573 | upstream->keepalive_timeout = 0; | |
559 | 574 | if (upstream->tls_hs_state != GETDNS_HS_FAILED) { |
560 | 575 | upstream->tls_hs_state = GETDNS_HS_NONE; |
561 | 576 | upstream->tls_auth_failed = 0; |
573 | 588 | static int |
574 | 589 | tls_is_in_transports_list(getdns_context *context) { |
575 | 590 | for (int i=0; i< context->dns_transport_count;i++) { |
576 | if (context->dns_transports[i] == GETDNS_TRANSPORT_TLS || | |
577 | context->dns_transports[i] == GETDNS_TRANSPORT_STARTTLS) | |
591 | if (context->dns_transports[i] == GETDNS_TRANSPORT_TLS) | |
578 | 592 | return 1; |
579 | 593 | } |
580 | 594 | return 0; |
584 | 598 | tls_only_is_in_transports_list(getdns_context *context) { |
585 | 599 | if (context->dns_transport_count != 1) |
586 | 600 | return 0; |
587 | if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS || | |
588 | context->dns_transports[0] == GETDNS_TRANSPORT_STARTTLS) | |
601 | if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS) | |
589 | 602 | return 1; |
590 | 603 | return 0; |
591 | 604 | } |
595 | 608 | net_req_query_id_cmp(const void *id1, const void *id2) |
596 | 609 | { |
597 | 610 | return (intptr_t)id1 - (intptr_t)id2; |
611 | } | |
612 | ||
613 | static getdns_tsig_info const tsig_info[] = { | |
614 | { GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 } | |
615 | , { GETDNS_HMAC_MD5 , "hmac-md5.sig-alg.reg.int", 24 | |
616 | , (uint8_t *)"\x08hmac-md5\x07sig-alg\x03reg\x03int", 26, 10, 16 } | |
617 | , { GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 } | |
618 | , { GETDNS_HMAC_SHA1 , "hmac-sha1" , 9 | |
619 | , (uint8_t *)"\x09hmac-sha1" , 11, 10, 20 } | |
620 | , { GETDNS_HMAC_SHA224, "hmac-sha224", 11 | |
621 | , (uint8_t *)"\x0bhmac-sha224", 13, 14, 28 } | |
622 | , { GETDNS_HMAC_SHA256, "hmac-sha256", 11 | |
623 | , (uint8_t *)"\x0bhmac-sha256", 13, 16, 32 } | |
624 | , { GETDNS_HMAC_SHA384, "hmac-sha384", 11 | |
625 | , (uint8_t *)"\x0bhmac-sha384", 13, 24, 48 } | |
626 | , { GETDNS_HMAC_SHA512, "hmac-sha512", 11 | |
627 | , (uint8_t *)"\x0bhmac-sha512", 13, 32, 64 } | |
628 | , { GETDNS_HMAC_MD5 , "hmac-md5" , 8 | |
629 | , (uint8_t *)"\x08hmac-md5" , 10, 10, 16 } | |
630 | }; | |
631 | static size_t const n_tsig_infos = | |
632 | sizeof(tsig_info) / sizeof(getdns_tsig_info); | |
633 | ||
634 | static getdns_tsig_info const * const last_tsig_info = | |
635 | tsig_info + (sizeof(tsig_info) / sizeof(getdns_tsig_info)); | |
636 | ||
637 | const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg) | |
638 | { | |
639 | return tsig_alg > n_tsig_infos - 1 | |
640 | || tsig_info[tsig_alg].alg == GETDNS_NO_TSIG ? NULL | |
641 | : &tsig_info[tsig_alg]; | |
642 | } | |
643 | ||
644 | static getdns_tsig_algo _getdns_get_tsig_algo(getdns_bindata *algo) | |
645 | { | |
646 | const getdns_tsig_info *i; | |
647 | ||
648 | if (!algo || algo->size == 0) | |
649 | return GETDNS_NO_TSIG; | |
650 | ||
651 | if (algo->data[algo->size-1] != 0) { | |
652 | /* Unterminated string */ | |
653 | for (i = tsig_info; i < last_tsig_info; i++) | |
654 | if ((algo->size == i->strlen_name || | |
655 | (algo->size - 1 == i->strlen_name && | |
656 | algo->data[algo->size - 1] == '.' | |
657 | ) | |
658 | )&& | |
659 | strncasecmp((const char *)algo->data, i->name, | |
660 | i->strlen_name) == 0) | |
661 | return i->alg; | |
662 | ||
663 | } else if (!_getdns_bindata_is_dname(algo)) { | |
664 | /* Terminated string */ | |
665 | for (i = tsig_info; i < last_tsig_info; i++) | |
666 | if (algo->size - 1 == i->strlen_name && | |
667 | strncasecmp((const char *)algo->data, i->name, | |
668 | i->strlen_name) == 0) | |
669 | return i->alg; | |
670 | ||
671 | } else { | |
672 | /* fqdn, canonical_dname_compare is now safe to use! */ | |
673 | for (i = tsig_info; i < last_tsig_info; i++) | |
674 | if (canonical_dname_compare(algo->data, i->dname) == 0) | |
675 | return i->alg; | |
676 | } | |
677 | return GETDNS_NO_TSIG; | |
598 | 678 | } |
599 | 679 | |
600 | 680 | static void |
609 | 689 | /* How is this upstream doing? */ |
610 | 690 | upstream->writes_done = 0; |
611 | 691 | upstream->responses_received = 0; |
692 | upstream->keepalive_timeout = 0; | |
612 | 693 | upstream->to_retry = 2; |
613 | 694 | upstream->back_off = 1; |
614 | 695 | |
615 | 696 | /* For sharing a socket to this upstream with TCP */ |
616 | 697 | upstream->fd = -1; |
617 | 698 | upstream->tls_obj = NULL; |
618 | upstream->starttls_req = NULL; | |
619 | 699 | upstream->transport = GETDNS_TRANSPORT_TCP; |
620 | 700 | upstream->tls_hs_state = GETDNS_HS_NONE; |
621 | 701 | upstream->tls_auth_failed = 0; |
622 | 702 | upstream->tls_auth_name[0] = '\0'; |
703 | upstream->tls_pubkey_pinset = NULL; | |
623 | 704 | upstream->tcp.write_error = 0; |
624 | 705 | upstream->loop = NULL; |
625 | 706 | (void) getdns_eventloop_event_init( |
633 | 714 | upstream->has_prev_client_cookie = 0; |
634 | 715 | upstream->has_server_cookie = 0; |
635 | 716 | |
717 | upstream->tsig_alg = GETDNS_NO_TSIG; | |
718 | upstream->tsig_dname_len = 0; | |
719 | upstream->tsig_size = 0; | |
720 | ||
636 | 721 | /* Tracking of network requests on this socket */ |
637 | 722 | _getdns_rbtree_init(&upstream->netreq_by_query_id, |
638 | 723 | net_req_query_id_cmp); |
639 | 724 | } |
640 | 725 | |
726 | #ifdef USE_WINSOCK | |
727 | static getdns_return_t | |
728 | set_os_defaults_windows(struct getdns_context *context) | |
729 | { | |
730 | char domain[1024] = ""; | |
731 | size_t upstreams_limit = 10; | |
732 | struct addrinfo hints; | |
733 | struct addrinfo *result; | |
734 | getdns_upstream *upstream; | |
735 | int s; | |
736 | ||
737 | if (context->fchg_resolvconf == NULL) { | |
738 | context->fchg_resolvconf = | |
739 | GETDNS_MALLOC(context->my_mf, struct filechg); | |
740 | if (context->fchg_resolvconf == NULL) | |
741 | return GETDNS_RETURN_MEMORY_ERROR; | |
742 | context->fchg_resolvconf->fn = "InvalidOnWindows"; | |
743 | context->fchg_resolvconf->prevstat = NULL; | |
744 | context->fchg_resolvconf->changes = GETDNS_FCHG_NOCHANGES; | |
745 | context->fchg_resolvconf->errors = GETDNS_FCHG_NOERROR; | |
746 | } | |
747 | _getdns_filechg_check(context, context->fchg_resolvconf); | |
748 | ||
749 | context->upstreams = upstreams_create(context, upstreams_limit); | |
750 | ||
751 | memset(&hints, 0, sizeof(struct addrinfo)); | |
752 | hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ | |
753 | hints.ai_socktype = 0; /* Datagram socket */ | |
754 | hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */ | |
755 | hints.ai_protocol = 0; /* Any protocol */ | |
756 | hints.ai_canonname = NULL; | |
757 | hints.ai_addr = NULL; | |
758 | hints.ai_next = NULL; | |
759 | ||
760 | FIXED_INFO *info; | |
761 | ULONG buflen = sizeof(*info); | |
762 | IP_ADDR_STRING *ptr = 0; | |
763 | ||
764 | info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); | |
765 | if (info == NULL) | |
766 | return GETDNS_RETURN_GENERIC_ERROR; | |
767 | ||
768 | if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { | |
769 | free(info); | |
770 | info = (FIXED_INFO *)malloc(buflen); | |
771 | if (info == NULL) | |
772 | return GETDNS_RETURN_GENERIC_ERROR; | |
773 | } | |
774 | ||
775 | if (GetNetworkParams(info, &buflen) == NO_ERROR) { | |
776 | ptr = info->DnsServerList.Next; | |
777 | *domain = 0; | |
778 | while (ptr) { | |
779 | for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { | |
780 | char *port_str = getdns_port_str_array[i]; | |
781 | if ((s = getaddrinfo(ptr->IpAddress.String, port_str, &hints, &result))) | |
782 | continue; | |
783 | if (!result) | |
784 | continue; | |
785 | ||
786 | upstream = &context->upstreams-> | |
787 | upstreams[context->upstreams->count++]; | |
788 | upstream_init(upstream, context->upstreams, result); | |
789 | upstream->transport = getdns_upstream_transports[i]; | |
790 | freeaddrinfo(result); | |
791 | } | |
792 | ptr = ptr->Next; | |
793 | ||
794 | } | |
795 | free(info); | |
796 | } | |
797 | return GETDNS_RETURN_GOOD; | |
798 | } /* set_os_defaults_windows */ | |
799 | #else | |
641 | 800 | static getdns_return_t |
642 | 801 | set_os_defaults(struct getdns_context *context) |
643 | 802 | { |
648 | 807 | struct addrinfo hints; |
649 | 808 | struct addrinfo *result; |
650 | 809 | getdns_upstream *upstream; |
810 | getdns_list *suffix; | |
651 | 811 | int s; |
652 | 812 | |
653 | 813 | if(context->fchg_resolvconf == NULL) { |
672 | 832 | upstream_count++; |
673 | 833 | fclose(in); |
674 | 834 | |
675 | context->suffix = getdns_list_create_with_context(context); | |
835 | suffix = getdns_list_create_with_context(context); | |
676 | 836 | context->upstreams = upstreams_create( |
677 | 837 | context, upstream_count * GETDNS_UPSTREAM_TRANSPORTS); |
678 | 838 | |
713 | 873 | prev_ch = *token; |
714 | 874 | *token = 0; |
715 | 875 | |
716 | _getdns_list_append_string(context->suffix, parse); | |
876 | _getdns_list_append_string(suffix, parse); | |
717 | 877 | |
718 | 878 | *token = prev_ch; |
719 | 879 | parse = token; |
744 | 904 | } |
745 | 905 | fclose(in); |
746 | 906 | |
747 | (void) getdns_list_get_length(context->suffix, &length); | |
907 | (void) getdns_list_get_length(suffix, &length); | |
748 | 908 | if (length == 0 && *domain != 0) |
749 | _getdns_list_append_string(context->suffix, domain); | |
909 | _getdns_list_append_string(suffix, domain); | |
910 | (void )getdns_context_set_suffix(context, suffix); | |
911 | getdns_list_destroy(suffix); | |
912 | ||
750 | 913 | return GETDNS_RETURN_GOOD; |
751 | 914 | } /* set_os_defaults */ |
915 | #endif | |
752 | 916 | |
753 | 917 | /* compare of transaction ids in DESCENDING order |
754 | 918 | so that 0 comes last |
846 | 1010 | result->timeout = 5000; |
847 | 1011 | result->idle_timeout = 0; |
848 | 1012 | result->follow_redirects = GETDNS_REDIRECTS_FOLLOW; |
849 | result->dns_root_servers = create_default_root_servers(); | |
1013 | result->dns_root_servers = NULL; | |
1014 | result->root_servers_fn[0] = 0; | |
850 | 1015 | result->append_name = GETDNS_APPEND_NAME_ALWAYS; |
851 | result->suffix = NULL; | |
1016 | result->suffixes = no_suffixes; | |
1017 | result->suffixes_len = sizeof(no_suffixes); | |
852 | 1018 | |
853 | 1019 | gldns_buffer_init_frm_data(&gbuf, result->trust_anchors_spc |
854 | 1020 | , sizeof(result->trust_anchors_spc)); |
890 | 1056 | result->fchg_resolvconf = NULL; |
891 | 1057 | result->fchg_hosts = NULL; |
892 | 1058 | |
1059 | // resolv.conf does not exist on Windows, handle differently | |
1060 | #ifndef USE_WINSOCK | |
893 | 1061 | if (set_from_os && (r = set_os_defaults(result))) |
894 | 1062 | goto error; |
1063 | #else | |
1064 | if (set_from_os && (r = set_os_defaults_windows(result))) | |
1065 | goto error; | |
1066 | #endif | |
895 | 1067 | |
896 | 1068 | result->dnssec_allowed_skew = 0; |
897 | 1069 | result->edns_maximum_udp_payload_size = -1; |
1010 | 1182 | if (context->tls_ctx) |
1011 | 1183 | SSL_CTX_free(context->tls_ctx); |
1012 | 1184 | |
1013 | getdns_list_destroy(context->dns_root_servers); | |
1014 | getdns_list_destroy(context->suffix); | |
1185 | if (context->dns_root_servers) | |
1186 | getdns_list_destroy(context->dns_root_servers); | |
1187 | if (context->root_servers_fn[0]) | |
1188 | unlink(context->root_servers_fn); | |
1189 | ||
1190 | if (context->suffixes && context->suffixes != no_suffixes) | |
1191 | GETDNS_FREE(context->mf, (void *)context->suffixes); | |
1015 | 1192 | |
1016 | 1193 | if (context->trust_anchors && |
1017 | 1194 | context->trust_anchors != context->trust_anchors_spc) |
1204 | 1381 | * |
1205 | 1382 | */ |
1206 | 1383 | getdns_return_t |
1207 | getdns_context_set_namespaces(struct getdns_context *context, | |
1384 | getdns_context_set_namespaces(getdns_context *context, | |
1208 | 1385 | size_t namespace_count, getdns_namespace_t *namespaces) |
1209 | 1386 | { |
1210 | 1387 | size_t i; |
1211 | ||
1212 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
1213 | if (namespace_count == 0 || namespaces == NULL) { | |
1214 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1215 | } | |
1216 | ||
1217 | for(i=0; i<namespace_count; i++) | |
1218 | { | |
1219 | if( namespaces[i] != GETDNS_NAMESPACE_DNS | |
1220 | && namespaces[i] != GETDNS_NAMESPACE_LOCALNAMES | |
1221 | && namespaces[i] != GETDNS_NAMESPACE_NETBIOS | |
1222 | && namespaces[i] != GETDNS_NAMESPACE_MDNS | |
1223 | && namespaces[i] != GETDNS_NAMESPACE_NIS) | |
1388 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
1389 | ||
1390 | if (!context) | |
1391 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1392 | ||
1393 | if (namespace_count == 0 || namespaces == NULL) | |
1394 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1395 | ||
1396 | for (i = 0; i < namespace_count; i++) { | |
1397 | if (namespaces[i] == GETDNS_NAMESPACE_NETBIOS || | |
1398 | namespaces[i] == GETDNS_NAMESPACE_MDNS || | |
1399 | namespaces[i] == GETDNS_NAMESPACE_NIS) | |
1400 | r = GETDNS_RETURN_NOT_IMPLEMENTED; | |
1401 | ||
1402 | else if (namespaces[i] != GETDNS_NAMESPACE_DNS && | |
1403 | namespaces[i] != GETDNS_NAMESPACE_LOCALNAMES) | |
1224 | 1404 | return GETDNS_RETURN_INVALID_PARAMETER; |
1225 | 1405 | } |
1226 | ||
1227 | GETDNS_FREE(context->my_mf, context->namespaces); | |
1228 | ||
1229 | /** duplicate **/ | |
1230 | context->namespaces = GETDNS_XMALLOC(context->my_mf, getdns_namespace_t, | |
1231 | namespace_count); | |
1232 | memcpy(context->namespaces, namespaces, | |
1233 | namespace_count * sizeof(getdns_namespace_t)); | |
1406 | GETDNS_FREE(context->my_mf, context->namespaces); | |
1407 | ||
1408 | /** duplicate **/ | |
1409 | context->namespaces = GETDNS_XMALLOC( | |
1410 | context->my_mf, getdns_namespace_t, namespace_count); | |
1411 | (void) memcpy(context->namespaces, namespaces, | |
1412 | namespace_count * sizeof(getdns_namespace_t)); | |
1234 | 1413 | context->namespace_count = namespace_count; |
1235 | dispatch_updated(context, GETDNS_CONTEXT_CODE_NAMESPACES); | |
1236 | ||
1237 | return GETDNS_RETURN_GOOD; | |
1414 | ||
1415 | dispatch_updated(context, GETDNS_CONTEXT_CODE_NAMESPACES); | |
1416 | ||
1417 | return r; | |
1238 | 1418 | } /* getdns_context_set_namespaces */ |
1239 | 1419 | |
1240 | 1420 | static getdns_return_t |
1248 | 1428 | return GETDNS_RETURN_INVALID_PARAMETER; |
1249 | 1429 | |
1250 | 1430 | /* Check for valid transports and that they are used only once*/ |
1251 | int u=0,t=0,l=0,s=0; | |
1431 | int u=0,t=0,l=0; | |
1252 | 1432 | for(i=0; i<transport_count; i++) |
1253 | 1433 | { |
1254 | 1434 | switch (transports[i]) { |
1255 | 1435 | case GETDNS_TRANSPORT_UDP: u++; break; |
1256 | 1436 | case GETDNS_TRANSPORT_TCP: t++; break; |
1257 | 1437 | case GETDNS_TRANSPORT_TLS: l++; break; |
1258 | case GETDNS_TRANSPORT_STARTTLS: s++; break; | |
1259 | 1438 | default: return GETDNS_RETURN_INVALID_PARAMETER; |
1260 | 1439 | } |
1261 | 1440 | } |
1262 | if ( u>1 || t>1 || l>1 || s>1) | |
1441 | if ( u>1 || t>1 || l>1) | |
1263 | 1442 | return GETDNS_RETURN_INVALID_PARAMETER; |
1264 | 1443 | |
1265 | 1444 | if (!(new_transports = GETDNS_XMALLOC(context->my_mf, |
1296 | 1475 | set_ub_string_opt(context, "do-tcp:", "yes"); |
1297 | 1476 | break; |
1298 | 1477 | case GETDNS_TRANSPORT_TLS: |
1299 | case GETDNS_TRANSPORT_STARTTLS: | |
1300 | 1478 | set_ub_string_opt(context, "do-udp:", "no"); |
1301 | 1479 | set_ub_string_opt(context, "do-tcp:", "yes"); |
1302 | 1480 | /* Find out if there is a fallback available. */ |
1313 | 1491 | break; |
1314 | 1492 | } |
1315 | 1493 | } |
1316 | if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS) { | |
1317 | if (fallback == 0) | |
1318 | /* Use TLS if it is the only thing.*/ | |
1319 | set_ub_string_opt(context, "ssl-upstream:", "yes"); | |
1320 | break; | |
1321 | } else if (fallback == 0) | |
1322 | /* Can't support STARTTLS with no fallback. This leads to | |
1323 | * timeouts with un stub validation.... */ | |
1324 | set_ub_string_opt(context, "do-tcp:", "no"); | |
1494 | if (fallback == 0) | |
1495 | /* Use TLS if it is the only thing.*/ | |
1496 | set_ub_string_opt(context, "ssl-upstream:", "yes"); | |
1325 | 1497 | break; |
1326 | 1498 | default: |
1327 | 1499 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; |
1378 | 1550 | context->dns_transports[0] = GETDNS_TRANSPORT_TLS; |
1379 | 1551 | context->dns_transports[1] = GETDNS_TRANSPORT_TCP; |
1380 | 1552 | break; |
1381 | case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: | |
1382 | context->dns_transports[0] = GETDNS_TRANSPORT_STARTTLS; | |
1383 | context->dns_transports[1] = GETDNS_TRANSPORT_TCP; | |
1384 | break; | |
1385 | 1553 | default: |
1386 | 1554 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; |
1387 | 1555 | } |
1432 | 1600 | { |
1433 | 1601 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); |
1434 | 1602 | if (value != GETDNS_AUTHENTICATION_NONE && |
1435 | value != GETDNS_AUTHENTICATION_HOSTNAME) { | |
1603 | value != GETDNS_AUTHENTICATION_REQUIRED) { | |
1436 | 1604 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; |
1437 | 1605 | } |
1438 | 1606 | context->tls_auth = value; |
1495 | 1663 | { |
1496 | 1664 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); |
1497 | 1665 | |
1498 | if (timeout == 0) { | |
1499 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1500 | } | |
1666 | /* Shuold we enforce maximum based on edns-tcp-keepalive spec? */ | |
1667 | /* 0 should be allowed as that is the default.*/ | |
1501 | 1668 | |
1502 | 1669 | context->idle_timeout = timeout; |
1503 | 1670 | |
1512 | 1679 | * |
1513 | 1680 | */ |
1514 | 1681 | getdns_return_t |
1515 | getdns_context_set_follow_redirects(struct getdns_context *context, | |
1516 | getdns_redirects_t value) | |
1517 | { | |
1518 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
1519 | if (value != GETDNS_REDIRECTS_FOLLOW && value != GETDNS_REDIRECTS_DO_NOT_FOLLOW) | |
1520 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1521 | ||
1522 | context->follow_redirects = value; | |
1523 | if (context->resolution_type_set != 0) { | |
1524 | /* already setup */ | |
1525 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1526 | } | |
1527 | ||
1528 | dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS); | |
1529 | return GETDNS_RETURN_GOOD; | |
1682 | getdns_context_set_follow_redirects( | |
1683 | getdns_context *context, getdns_redirects_t value) | |
1684 | { | |
1685 | if (!context) | |
1686 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1687 | ||
1688 | if (value != GETDNS_REDIRECTS_FOLLOW && | |
1689 | value != GETDNS_REDIRECTS_DO_NOT_FOLLOW) | |
1690 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1691 | ||
1692 | context->follow_redirects = value; | |
1693 | ||
1694 | dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS); | |
1695 | ||
1696 | return GETDNS_RETURN_NOT_IMPLEMENTED; | |
1530 | 1697 | } /* getdns_context_set_follow_redirects */ |
1531 | 1698 | |
1532 | 1699 | /* |
1534 | 1701 | * |
1535 | 1702 | */ |
1536 | 1703 | getdns_return_t |
1537 | getdns_context_set_dns_root_servers(struct getdns_context *context, | |
1538 | struct getdns_list * addresses) | |
1539 | { | |
1540 | struct getdns_list *copy = NULL; | |
1541 | size_t count = 0; | |
1542 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
1543 | if (context->resolution_type_set != 0) { | |
1544 | /* already setup */ | |
1545 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1546 | } | |
1547 | if (addresses != NULL) { | |
1548 | if (_getdns_list_copy(addresses, ©) != GETDNS_RETURN_GOOD) { | |
1549 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1550 | } | |
1551 | addresses = copy; | |
1552 | getdns_list_get_length(addresses, &count); | |
1553 | if (count == 0) { | |
1554 | getdns_list_destroy(addresses); | |
1555 | addresses = NULL; | |
1556 | } else { | |
1557 | size_t i = 0; | |
1558 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
1559 | /* validate and add ip str */ | |
1560 | for (i = 0; i < count; ++i) { | |
1561 | struct getdns_dict *dict = NULL; | |
1562 | getdns_list_get_dict(addresses, i, &dict); | |
1563 | if (r != GETDNS_RETURN_GOOD) { | |
1564 | break; | |
1565 | } | |
1566 | } | |
1567 | if (r != GETDNS_RETURN_GOOD) { | |
1568 | getdns_list_destroy(addresses); | |
1569 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1570 | } | |
1571 | } | |
1572 | } | |
1573 | ||
1574 | getdns_list_destroy(context->dns_root_servers); | |
1575 | context->dns_root_servers = addresses; | |
1576 | ||
1577 | dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS); | |
1578 | ||
1579 | return GETDNS_RETURN_GOOD; | |
1704 | getdns_context_set_dns_root_servers( | |
1705 | getdns_context *context, getdns_list *addresses) | |
1706 | { | |
1707 | char tmpfn[FILENAME_MAX] = P_tmpdir "/getdns-root-dns-servers-XXXXXX"; | |
1708 | FILE *fh; | |
1709 | int fd; | |
1710 | size_t i; | |
1711 | getdns_dict *rr_dict; | |
1712 | getdns_return_t r; | |
1713 | getdns_bindata *addr_bd; | |
1714 | char dst[2048]; | |
1715 | size_t dst_len; | |
1716 | getdns_list *newlist; | |
1717 | ||
1718 | if (!context) | |
1719 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1720 | ||
1721 | if (!addresses) { | |
1722 | #ifdef HAVE_LIBUNBOUND | |
1723 | if (ub_ctx_set_option( | |
1724 | context->unbound_ctx, "root-hints:", "")) | |
1725 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1726 | #endif | |
1727 | if (context->dns_root_servers) | |
1728 | getdns_list_destroy(context->dns_root_servers); | |
1729 | context->dns_root_servers = NULL; | |
1730 | ||
1731 | if (context->root_servers_fn[0]) | |
1732 | unlink(context->root_servers_fn); | |
1733 | context->root_servers_fn[0] = 0; | |
1734 | ||
1735 | dispatch_updated( | |
1736 | context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS); | |
1737 | return GETDNS_RETURN_GOOD; | |
1738 | } | |
1739 | if ((fd = mkstemp(tmpfn)) < 0) | |
1740 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1741 | ||
1742 | if (!(fh = fdopen(fd, "w"))) | |
1743 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1744 | ||
1745 | for (i=0; (!(r = getdns_list_get_dict(addresses, i, &rr_dict))); i++) { | |
1746 | dst_len = sizeof(dst); | |
1747 | if (!getdns_rr_dict2str_buf(rr_dict, dst, &dst_len)) | |
1748 | ||
1749 | fprintf(fh, "%s", dst); | |
1750 | ||
1751 | else if (getdns_dict_get_bindata( | |
1752 | rr_dict, "address_data", &addr_bd) && | |
1753 | getdns_dict_get_bindata( | |
1754 | rr_dict, "/rdata/ipv4_address", &addr_bd) && | |
1755 | getdns_dict_get_bindata( | |
1756 | rr_dict, "/rdata/ipv6_address", &addr_bd)) | |
1757 | ||
1758 | ; /* pass */ | |
1759 | ||
1760 | else if (addr_bd->size == 16 && | |
1761 | inet_ntop(AF_INET6, addr_bd->data, dst, sizeof(dst))) | |
1762 | ||
1763 | fprintf(fh, ". NS %zu.root-servers.getdnsapi.net.\n" | |
1764 | "%zu.root-servers.getdnsapi.net. AAAA %s\n", | |
1765 | i, i, dst); | |
1766 | ||
1767 | else if (addr_bd->size == 4 && | |
1768 | inet_ntop(AF_INET, addr_bd->data, dst, sizeof(dst))) | |
1769 | ||
1770 | fprintf(fh, ". NS %zu.root-servers.getdnsapi.net.\n" | |
1771 | "%zu.root-servers.getdnsapi.net. A %s\n", | |
1772 | i, i, dst); | |
1773 | } | |
1774 | fclose(fh); | |
1775 | #ifdef HAVE_LIBUNBOUND | |
1776 | if (ub_ctx_set_option( | |
1777 | context->unbound_ctx, "root-hints:", tmpfn)) { | |
1778 | unlink(tmpfn); | |
1779 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1780 | } | |
1781 | #endif | |
1782 | if (_getdns_list_copy(addresses, &newlist)) { | |
1783 | unlink(tmpfn); | |
1784 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1785 | } | |
1786 | if (context->dns_root_servers) | |
1787 | getdns_list_destroy(context->dns_root_servers); | |
1788 | context->dns_root_servers = newlist; | |
1789 | ||
1790 | if (context->root_servers_fn[0]) | |
1791 | unlink(context->root_servers_fn); | |
1792 | (void) memcpy(context->root_servers_fn, tmpfn, strlen(tmpfn)); | |
1793 | ||
1794 | dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS); | |
1795 | return GETDNS_RETURN_GOOD; | |
1580 | 1796 | } /* getdns_context_set_dns_root_servers */ |
1581 | 1797 | |
1582 | 1798 | /* |
1607 | 1823 | * |
1608 | 1824 | */ |
1609 | 1825 | getdns_return_t |
1610 | getdns_context_set_suffix(struct getdns_context *context, struct getdns_list * value) | |
1611 | { | |
1612 | struct getdns_list *copy = NULL; | |
1613 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
1614 | if (context->resolution_type_set != 0) { | |
1615 | /* already setup */ | |
1616 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1617 | } | |
1618 | if (value != NULL) { | |
1619 | if (_getdns_list_copy(value, ©) != GETDNS_RETURN_GOOD) { | |
1620 | return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; | |
1621 | } | |
1622 | value = copy; | |
1623 | } | |
1624 | getdns_list_destroy(context->suffix); | |
1625 | context->suffix = value; | |
1626 | ||
1627 | dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX); | |
1628 | ||
1629 | return GETDNS_RETURN_GOOD; | |
1826 | getdns_context_set_suffix(getdns_context *context, getdns_list *value) | |
1827 | { | |
1828 | getdns_return_t r; | |
1829 | size_t i; | |
1830 | gldns_buffer gbuf; | |
1831 | uint8_t buf_spc[1024], *suffixes = NULL; | |
1832 | size_t suffixes_len = 0; | |
1833 | uint8_t dname[256]; | |
1834 | size_t dname_len; | |
1835 | char name_spc[1025], *name; | |
1836 | getdns_bindata *bindata; | |
1837 | ||
1838 | if (!context) | |
1839 | return GETDNS_RETURN_INVALID_PARAMETER; | |
1840 | ||
1841 | if (value == NULL) { | |
1842 | if (context->suffixes && context->suffixes != no_suffixes) | |
1843 | GETDNS_FREE(context->mf, (void *)context->suffixes); | |
1844 | ||
1845 | context->suffixes = no_suffixes; | |
1846 | context->suffixes_len = sizeof(no_suffixes); | |
1847 | return GETDNS_RETURN_GOOD; | |
1848 | } | |
1849 | gldns_buffer_init_frm_data(&gbuf, buf_spc, sizeof(buf_spc)); | |
1850 | for (;;) { | |
1851 | for ( i = 0 | |
1852 | ; !(r = getdns_list_get_bindata(value, i, &bindata)) | |
1853 | ; i++) { | |
1854 | ||
1855 | if (bindata->size == 0 || bindata->size >= sizeof(name_spc)) | |
1856 | continue; | |
1857 | ||
1858 | if (bindata->data[bindata->size-1] != 0) { | |
1859 | /* Unterminated string */ | |
1860 | (void) memcpy(name_spc, bindata->data, bindata->size); | |
1861 | name_spc[bindata->size] = 0; | |
1862 | name = name_spc; | |
1863 | } else | |
1864 | /* Terminated string */ | |
1865 | name = (char *)bindata->data; | |
1866 | ||
1867 | dname_len = sizeof(dname); | |
1868 | if (gldns_str2wire_dname_buf(name, dname, &dname_len)) | |
1869 | return GETDNS_RETURN_GENERIC_ERROR; | |
1870 | ||
1871 | gldns_buffer_write_u8(&gbuf, dname_len); | |
1872 | gldns_buffer_write(&gbuf, dname, dname_len); | |
1873 | } | |
1874 | if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) | |
1875 | r = GETDNS_RETURN_GOOD; | |
1876 | else | |
1877 | break; | |
1878 | ||
1879 | gldns_buffer_write_u8(&gbuf, 1); | |
1880 | gldns_buffer_write_u8(&gbuf, 0); | |
1881 | ||
1882 | if (gldns_buffer_begin(&gbuf) != buf_spc) | |
1883 | break; | |
1884 | ||
1885 | suffixes_len = gldns_buffer_position(&gbuf); | |
1886 | if (!(suffixes = GETDNS_XMALLOC( | |
1887 | context->mf, uint8_t, suffixes_len))) { | |
1888 | r = GETDNS_RETURN_MEMORY_ERROR; | |
1889 | break; | |
1890 | } | |
1891 | if (suffixes_len <= gldns_buffer_limit(&gbuf)) { | |
1892 | (void) memcpy (suffixes, buf_spc, suffixes_len); | |
1893 | break; | |
1894 | } | |
1895 | gldns_buffer_init_frm_data(&gbuf, suffixes, suffixes_len); | |
1896 | } | |
1897 | if (r) { | |
1898 | if (gldns_buffer_begin(&gbuf) != buf_spc) | |
1899 | GETDNS_FREE(context->mf, suffixes); | |
1900 | return r; | |
1901 | } | |
1902 | if (context->suffixes && context->suffixes != no_suffixes) | |
1903 | GETDNS_FREE(context->mf, (void *)context->suffixes); | |
1904 | ||
1905 | context->suffixes = suffixes; | |
1906 | context->suffixes_len = suffixes_len; | |
1907 | ||
1908 | dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX); | |
1909 | return GETDNS_RETURN_GOOD; | |
1630 | 1910 | } /* getdns_context_set_suffix */ |
1631 | 1911 | |
1632 | 1912 | /* |
1713 | 1993 | upstreams = upstreams_create( |
1714 | 1994 | context, count * GETDNS_UPSTREAM_TRANSPORTS); |
1715 | 1995 | for (i = 0; i < count; i++) { |
1716 | getdns_dict *dict; | |
1996 | getdns_dict *dict; | |
1717 | 1997 | getdns_bindata *address_type; |
1718 | 1998 | getdns_bindata *address_data; |
1719 | 1999 | getdns_bindata *tls_auth_name; |
1720 | 2000 | struct sockaddr_storage addr; |
1721 | 2001 | |
1722 | getdns_bindata *scope_id; | |
2002 | getdns_bindata *scope_id; | |
1723 | 2003 | getdns_upstream *upstream; |
2004 | ||
2005 | getdns_bindata *tsig_alg_name, *tsig_name, *tsig_key; | |
2006 | getdns_tsig_algo tsig_alg; | |
2007 | char tsig_name_str[1024]; | |
2008 | uint8_t tsig_dname_spc[256], *tsig_dname; | |
2009 | size_t tsig_dname_len; | |
1724 | 2010 | |
1725 | 2011 | if ((r = getdns_list_get_dict(upstream_list, i, &dict))) |
1726 | 2012 | goto error; |
1758 | 2044 | eos[scope_id->size] = 0; |
1759 | 2045 | } |
1760 | 2046 | |
2047 | tsig_alg_name = tsig_name = tsig_key = NULL; | |
2048 | tsig_dname = NULL; | |
2049 | tsig_dname_len = 0; | |
2050 | ||
2051 | if (getdns_dict_get_bindata(dict, | |
2052 | "tsig_algorithm", &tsig_alg_name) == GETDNS_RETURN_GOOD) | |
2053 | tsig_alg = _getdns_get_tsig_algo(tsig_alg_name); | |
2054 | else | |
2055 | tsig_alg = GETDNS_HMAC_MD5; | |
2056 | ||
2057 | if (getdns_dict_get_bindata(dict, "tsig_name", &tsig_name)) | |
2058 | tsig_alg = GETDNS_NO_TSIG; /* No name, no TSIG */ | |
2059 | ||
2060 | else if (tsig_name->size == 0) | |
2061 | tsig_alg = GETDNS_NO_TSIG; | |
2062 | ||
2063 | else if (tsig_name->data[tsig_name->size - 1] != 0) { | |
2064 | /* Unterminated string */ | |
2065 | if (tsig_name->size >= sizeof(tsig_name_str) - 1) | |
2066 | tsig_alg = GETDNS_NO_TSIG; | |
2067 | else { | |
2068 | (void) memcpy(tsig_name_str, tsig_name->data | |
2069 | , tsig_name->size); | |
2070 | tsig_name_str[tsig_name->size] = 0; | |
2071 | ||
2072 | tsig_dname_len = sizeof(tsig_dname_spc); | |
2073 | if (gldns_str2wire_dname_buf(tsig_name_str, | |
2074 | tsig_dname_spc, &tsig_dname_len)) | |
2075 | tsig_alg = GETDNS_NO_TSIG; | |
2076 | else | |
2077 | tsig_dname = tsig_dname_spc; | |
2078 | } | |
2079 | } else if (!_getdns_bindata_is_dname(tsig_name)) { | |
2080 | /* Terminated string */ | |
2081 | tsig_dname_len = sizeof(tsig_dname_spc); | |
2082 | if (gldns_str2wire_dname_buf(tsig_name_str, | |
2083 | tsig_dname_spc, &tsig_dname_len)) | |
2084 | tsig_alg = GETDNS_NO_TSIG; | |
2085 | else | |
2086 | tsig_dname = tsig_dname_spc; | |
2087 | ||
2088 | } else if (tsig_name->size > sizeof(tsig_dname_spc)) | |
2089 | tsig_alg = GETDNS_NO_TSIG; | |
2090 | ||
2091 | else { | |
2092 | /* fqdn */ | |
2093 | tsig_dname = memcpy(tsig_dname_spc, tsig_name->data | |
2094 | , tsig_name->size); | |
2095 | tsig_dname_len = tsig_name->size; | |
2096 | } | |
2097 | if (getdns_dict_get_bindata(dict, "tsig_secret", &tsig_key)) | |
2098 | tsig_alg = GETDNS_NO_TSIG; /* No key, no TSIG */ | |
2099 | ||
2100 | /* Don't check TSIG length contraints here. | |
2101 | * Let the upstream decide what is secure enough. | |
2102 | */ | |
2103 | ||
1761 | 2104 | /* Loop to create upstreams as needed*/ |
1762 | 2105 | for (size_t j = 0; j < GETDNS_UPSTREAM_TRANSPORTS; j++) { |
1763 | 2106 | uint32_t port; |
1785 | 2128 | upstream->addr.ss_family = addr.ss_family; |
1786 | 2129 | upstream_init(upstream, upstreams, ai); |
1787 | 2130 | upstream->transport = getdns_upstream_transports[j]; |
1788 | if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS || | |
1789 | getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) { | |
2131 | if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) { | |
2132 | getdns_list *pubkey_pinset = NULL; | |
1790 | 2133 | if ((r = getdns_dict_get_bindata( |
1791 | 2134 | dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { |
1792 | 2135 | /*TODO: VALIDATE THIS STRING!*/ |
1795 | 2138 | tls_auth_name->size); |
1796 | 2139 | upstream->tls_auth_name[tls_auth_name->size] = '\0'; |
1797 | 2140 | } |
2141 | if ((r = getdns_dict_get_list(dict, "tls_pubkey_pinset", | |
2142 | &pubkey_pinset)) == GETDNS_RETURN_GOOD) { | |
2143 | /* TODO: what if the user supplies tls_pubkey_pinset with | |
2144 | * something other than a list? */ | |
2145 | r = _getdns_get_pubkey_pinset_from_list(pubkey_pinset, | |
2146 | &(upstreams->mf), | |
2147 | &(upstream->tls_pubkey_pinset)); | |
2148 | if (r != GETDNS_RETURN_GOOD) | |
2149 | goto invalid_parameter; | |
2150 | } | |
2151 | } | |
2152 | if ((upstream->tsig_alg = tsig_alg)) { | |
2153 | if (tsig_name) { | |
2154 | (void) memcpy(upstream->tsig_dname, | |
2155 | tsig_dname, tsig_dname_len); | |
2156 | upstream->tsig_dname_len = | |
2157 | tsig_dname_len; | |
2158 | } else | |
2159 | upstream->tsig_dname_len = 0; | |
2160 | ||
2161 | if (tsig_key) { | |
2162 | (void) memcpy(upstream->tsig_key, | |
2163 | tsig_key->data, tsig_key->size); | |
2164 | upstream->tsig_size = tsig_key->size; | |
2165 | } else | |
2166 | upstream->tsig_size = 0; | |
2167 | } else { | |
2168 | upstream->tsig_dname_len = 0; | |
2169 | upstream->tsig_size = 0; | |
1798 | 2170 | } |
1799 | 2171 | upstreams->count++; |
1800 | 2172 | freeaddrinfo(ai); |
2182 | 2554 | _getdns_rr_iter rr_spc, *rr; |
2183 | 2555 | char ta_str[8192]; |
2184 | 2556 | |
2185 | /* TODO: use the root servers via root hints file */ | |
2186 | 2557 | (void) ub_ctx_set_fwd(ctx, NULL); |
2187 | 2558 | if (!context->unbound_ta_set && context->trust_anchors) { |
2188 | 2559 | for ( rr = _getdns_rr_iter_init( &rr_spc |
2190 | 2561 | , context->trust_anchors_len) |
2191 | 2562 | ; rr ; rr = _getdns_rr_iter_next(rr) ) { |
2192 | 2563 | |
2193 | (void) gldns_wire2str_rr_buf(rr->pos, | |
2564 | (void) gldns_wire2str_rr_buf((UNCONST_UINT8_p)rr->pos, | |
2194 | 2565 | rr->nxt - rr->pos, ta_str, sizeof(ta_str)); |
2195 | 2566 | (void) ub_ctx_add_ta(ctx, ta_str); |
2196 | 2567 | } |
2249 | 2620 | /* Create client context, use TLS v1.2 only for now */ |
2250 | 2621 | context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); |
2251 | 2622 | if(context->tls_ctx == NULL) |
2623 | #ifndef USE_WINSOCK | |
2252 | 2624 | return GETDNS_RETURN_BAD_CONTEXT; |
2625 | #else | |
2626 | printf("Warning! Bad TLS context, check openssl version on Windows!\n");; | |
2627 | #endif | |
2253 | 2628 | /* Be strict and only use the cipher suites recommended in RFC7525 |
2254 | 2629 | Unless we later fallback to opportunistic. */ |
2255 | 2630 | const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; |
2265 | 2640 | #endif |
2266 | 2641 | } |
2267 | 2642 | if (tls_only_is_in_transports_list(context) == 1 && |
2268 | context->tls_auth == GETDNS_AUTHENTICATION_HOSTNAME) { | |
2269 | context->tls_auth_min = GETDNS_AUTHENTICATION_HOSTNAME; | |
2643 | context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) { | |
2644 | context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED; | |
2270 | 2645 | /* TODO: If no auth data provided for any upstream, fail here */ |
2271 | 2646 | } |
2272 | 2647 | else { |
2274 | 2649 | } |
2275 | 2650 | } |
2276 | 2651 | |
2277 | /* Block use of STARTTLS/TLS ONLY in recursive mode as it won't work */ | |
2652 | /* Block use of TLS ONLY in recursive mode as it won't work */ | |
2278 | 2653 | /* Note: If TLS is used in recursive mode this will try TLS on port |
2279 | * 53 so it is blocked here. So is 'STARTTLS only' at the moment. */ | |
2654 | * 53 so it is blocked here. */ | |
2280 | 2655 | if (context->resolution_type == GETDNS_RESOLUTION_RECURSING && |
2281 | 2656 | tls_only_is_in_transports_list(context) == 1) |
2282 | 2657 | return GETDNS_RETURN_BAD_CONTEXT; |
2378 | 2753 | } |
2379 | 2754 | |
2380 | 2755 | struct getdns_bindata * |
2381 | _getdns_bindata_copy(struct mem_funcs *mfs, | |
2382 | const struct getdns_bindata *src) | |
2756 | _getdns_bindata_copy(struct mem_funcs *mfs, size_t size, const uint8_t *data) | |
2383 | 2757 | { |
2384 | 2758 | /* Don't know why, but nodata allows |
2385 | 2759 | * empty bindatas with the python bindings |
2387 | 2761 | static uint8_t nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
2388 | 2762 | struct getdns_bindata *dst; |
2389 | 2763 | |
2390 | if (!src) | |
2391 | return NULL; | |
2392 | ||
2393 | 2764 | if (!(dst = GETDNS_MALLOC(*mfs, struct getdns_bindata))) |
2394 | 2765 | return NULL; |
2395 | 2766 | |
2396 | dst->size = src->size; | |
2397 | if ((dst->size = src->size)) { | |
2398 | dst->data = GETDNS_XMALLOC(*mfs, uint8_t, src->size); | |
2767 | if ((dst->size = size)) { | |
2768 | dst->data = GETDNS_XMALLOC(*mfs, uint8_t, size); | |
2399 | 2769 | if (!dst->data) { |
2400 | 2770 | GETDNS_FREE(*mfs, dst); |
2401 | 2771 | return NULL; |
2402 | 2772 | } |
2403 | (void) memcpy(dst->data, src->data, src->size); | |
2773 | (void) memcpy(dst->data, data, size); | |
2404 | 2774 | } else { |
2405 | 2775 | dst->data = nodata; |
2406 | 2776 | } |
2540 | 2910 | } |
2541 | 2911 | |
2542 | 2912 | static getdns_dict* |
2543 | _get_context_settings(getdns_context* context) { | |
2913 | _get_context_settings(getdns_context* context) | |
2914 | { | |
2544 | 2915 | getdns_return_t r = GETDNS_RETURN_GOOD; |
2545 | 2916 | getdns_dict* result = getdns_dict_create_with_context(context); |
2917 | getdns_list *list; | |
2918 | ||
2546 | 2919 | if (!result) { |
2547 | 2920 | return NULL; |
2548 | 2921 | } |
2559 | 2932 | r |= getdns_dict_set_int(result, "edns_do_bit", context->edns_do_bit); |
2560 | 2933 | r |= getdns_dict_set_int(result, "append_name", context->append_name); |
2561 | 2934 | /* list fields */ |
2562 | if (context->suffix) r |= getdns_dict_set_list(result, "suffix", context->suffix); | |
2563 | if (context->upstreams && context->upstreams->count > 0) { | |
2564 | size_t i; | |
2565 | getdns_upstream *upstream; | |
2566 | getdns_list *upstreams = | |
2567 | getdns_list_create_with_context(context); | |
2568 | ||
2569 | for (i = 0; i < context->upstreams->count;) { | |
2570 | size_t j; | |
2571 | getdns_dict *d; | |
2572 | upstream = &context->upstreams->upstreams[i]; | |
2573 | d = sockaddr_dict(context, | |
2574 | (struct sockaddr *)&upstream->addr); | |
2575 | for ( j = 1, i++ | |
2576 | ; j < GETDNS_UPSTREAM_TRANSPORTS && | |
2577 | i < context->upstreams->count | |
2578 | ; j++, i++) { | |
2579 | ||
2580 | upstream = &context->upstreams->upstreams[i]; | |
2581 | if (upstream->transport != GETDNS_TRANSPORT_TLS) | |
2582 | continue; | |
2583 | if (upstream_port(upstream) != getdns_port_array[j]) | |
2584 | continue; | |
2585 | (void) getdns_dict_set_int(d, "tls_port", | |
2586 | (uint32_t) upstream_port(upstream)); | |
2587 | } | |
2588 | r |= _getdns_list_append_dict(upstreams, d); | |
2589 | getdns_dict_destroy(d); | |
2590 | } | |
2935 | if (!getdns_context_get_suffix(context, &list)) { | |
2936 | r |= getdns_dict_set_list(result, "suffix", list); | |
2937 | getdns_list_destroy(list); | |
2938 | } | |
2939 | if (!getdns_context_get_upstream_recursive_servers(context, &list)) { | |
2591 | 2940 | r |= getdns_dict_set_list(result, "upstream_recursive_servers", |
2592 | upstreams); | |
2593 | getdns_list_destroy(upstreams); | |
2941 | list); | |
2942 | getdns_list_destroy(list); | |
2594 | 2943 | } |
2595 | 2944 | if (context->dns_transport_count > 0) { |
2596 | 2945 | /* create a namespace list */ |
2821 | 3170 | else |
2822 | 3171 | return GETDNS_RETURN_WRONG_TYPE_REQUESTED; |
2823 | 3172 | } |
2824 | if (transports[0] == GETDNS_TRANSPORT_STARTTLS) { | |
2825 | if (count == 2 && transports[1] == GETDNS_TRANSPORT_TCP) | |
2826 | *value = GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN; | |
2827 | else | |
2828 | return GETDNS_RETURN_WRONG_TYPE_REQUESTED; | |
2829 | } | |
2830 | 3173 | return GETDNS_RETURN_GOOD; |
2831 | 3174 | } |
2832 | 3175 | |
2883 | 3226 | } |
2884 | 3227 | |
2885 | 3228 | getdns_return_t |
2886 | getdns_context_get_follow_redirects(getdns_context *context, | |
2887 | getdns_redirects_t* value) { | |
2888 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
2889 | RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); | |
2890 | *value = context->follow_redirects; | |
2891 | return GETDNS_RETURN_GOOD; | |
3229 | getdns_context_get_follow_redirects( | |
3230 | getdns_context *context, getdns_redirects_t* value) | |
3231 | { | |
3232 | if (!context || !value) | |
3233 | return GETDNS_RETURN_INVALID_PARAMETER; | |
3234 | *value = context->follow_redirects; | |
3235 | return GETDNS_RETURN_NOT_IMPLEMENTED; | |
2892 | 3236 | } |
2893 | 3237 | |
2894 | 3238 | getdns_return_t |
2897 | 3241 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); |
2898 | 3242 | RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); |
2899 | 3243 | *value = NULL; |
2900 | if (context->dns_root_servers) { | |
3244 | if (context->dns_root_servers) | |
2901 | 3245 | return _getdns_list_copy(context->dns_root_servers, value); |
2902 | } | |
2903 | 3246 | return GETDNS_RETURN_GOOD; |
2904 | 3247 | } |
2905 | 3248 | |
2913 | 3256 | } |
2914 | 3257 | |
2915 | 3258 | getdns_return_t |
2916 | getdns_context_get_suffix(getdns_context *context, getdns_list **value) { | |
2917 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
2918 | RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); | |
2919 | *value = NULL; | |
2920 | if (context->suffix) { | |
2921 | return _getdns_list_copy(context->suffix, value); | |
2922 | } | |
2923 | return GETDNS_RETURN_GOOD; | |
3259 | getdns_context_get_suffix(getdns_context *context, getdns_list **value) | |
3260 | { | |
3261 | size_t dname_len; | |
3262 | const uint8_t *dname; | |
3263 | char name[1024]; | |
3264 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
3265 | getdns_list *list; | |
3266 | ||
3267 | if (!context || !value) | |
3268 | return GETDNS_RETURN_INVALID_PARAMETER; | |
3269 | ||
3270 | if (!(list = getdns_list_create_with_context(context))) | |
3271 | return GETDNS_RETURN_MEMORY_ERROR; | |
3272 | ||
3273 | assert(context->suffixes); | |
3274 | dname_len = context->suffixes[0]; | |
3275 | dname = context->suffixes + 1; | |
3276 | while (dname_len && *dname) { | |
3277 | if (! gldns_wire2str_dname_buf((UNCONST_UINT8_p) | |
3278 | dname, dname_len, name, sizeof(name))) { | |
3279 | r = GETDNS_RETURN_GENERIC_ERROR; | |
3280 | break; | |
3281 | } | |
3282 | if ((r = _getdns_list_append_const_bindata( | |
3283 | list, strlen(name) + 1, name))) | |
3284 | break; | |
3285 | dname += dname_len; | |
3286 | dname_len = *dname++; | |
3287 | } | |
3288 | if (r) | |
3289 | getdns_list_destroy(list); | |
3290 | else | |
3291 | *value = list; | |
3292 | ||
3293 | return GETDNS_RETURN_GOOD; | |
2924 | 3294 | } |
2925 | 3295 | |
2926 | 3296 | getdns_return_t |
2954 | 3324 | |
2955 | 3325 | getdns_return_t |
2956 | 3326 | getdns_context_get_upstream_recursive_servers(getdns_context *context, |
2957 | getdns_list **upstream_list) { | |
2958 | RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); | |
2959 | RETURN_IF_NULL(upstream_list, GETDNS_RETURN_INVALID_PARAMETER); | |
2960 | *upstream_list = NULL; | |
2961 | if (context->upstreams && context->upstreams->count > 0) { | |
2962 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
2963 | size_t i; | |
2964 | getdns_upstream *upstream; | |
2965 | getdns_list *upstreams = getdns_list_create(); | |
2966 | for (i = 0; i < context->upstreams->count;) { | |
3327 | getdns_list **upstreams_r) | |
3328 | { | |
3329 | size_t i; | |
3330 | getdns_list *upstreams; | |
3331 | getdns_return_t r; | |
3332 | ||
3333 | if (!context || !upstreams_r) | |
3334 | return GETDNS_RETURN_INVALID_PARAMETER; | |
3335 | ||
3336 | if (!(upstreams = getdns_list_create_with_context(context))) | |
3337 | return GETDNS_RETURN_MEMORY_ERROR; | |
3338 | ||
3339 | if (!context->upstreams || context->upstreams->count == 0) { | |
3340 | *upstreams_r = upstreams; | |
3341 | return GETDNS_RETURN_GOOD; | |
3342 | } | |
3343 | r = GETDNS_RETURN_GOOD; | |
3344 | i = 0; | |
3345 | while (!r && i < context->upstreams->count) { | |
2967 | 3346 | size_t j; |
2968 | 3347 | getdns_dict *d; |
2969 | upstream = &context->upstreams->upstreams[i]; | |
2970 | d = sockaddr_dict(context, (struct sockaddr *)&upstream->addr); | |
3348 | getdns_upstream *upstream = &context->upstreams->upstreams[i]; | |
3349 | getdns_bindata bindata; | |
3350 | const getdns_tsig_info *tsig_info; | |
3351 | ||
3352 | if (!(d = | |
3353 | sockaddr_dict(context, (struct sockaddr*)&upstream->addr))) { | |
3354 | r = GETDNS_RETURN_MEMORY_ERROR; | |
3355 | break; | |
3356 | } | |
3357 | if (upstream->tsig_alg) { | |
3358 | tsig_info = _getdns_get_tsig_info(upstream->tsig_alg); | |
3359 | ||
3360 | if ((r = _getdns_dict_set_const_bindata( | |
3361 | d, "tsig_algorithm", | |
3362 | tsig_info->dname_len, tsig_info->dname))) | |
3363 | break; | |
3364 | ||
3365 | if (upstream->tsig_dname_len) { | |
3366 | bindata.data = upstream->tsig_dname; | |
3367 | bindata.size = upstream->tsig_dname_len; | |
3368 | if ((r = getdns_dict_set_bindata( | |
3369 | d, "tsig_name", &bindata))) | |
3370 | break; | |
3371 | } | |
3372 | if (upstream->tsig_size) { | |
3373 | bindata.data = upstream->tsig_key; | |
3374 | bindata.size = upstream->tsig_size; | |
3375 | if ((r = getdns_dict_set_bindata( | |
3376 | d, "tsig_secret", &bindata))) | |
3377 | break; | |
3378 | } | |
3379 | } | |
2971 | 3380 | for ( j = 1, i++ |
2972 | 3381 | ; j < GETDNS_UPSTREAM_TRANSPORTS && |
2973 | 3382 | i < context->upstreams->count |
2974 | 3383 | ; j++, i++) { |
2975 | 3384 | |
2976 | 3385 | upstream = &context->upstreams->upstreams[i]; |
2977 | if (upstream->transport != GETDNS_TRANSPORT_TLS) | |
2978 | continue; | |
2979 | if (upstream_port(upstream) != getdns_port_array[j]) | |
2980 | continue; | |
2981 | (void) getdns_dict_set_int(d, "tls_port", | |
2982 | (uint32_t) upstream_port(upstream)); | |
3386 | ||
3387 | if (upstream->transport == GETDNS_TRANSPORT_UDP && | |
3388 | upstream_port(upstream) != getdns_port_array[j] && | |
3389 | (r = getdns_dict_set_int(d, "port", | |
3390 | (uint32_t)upstream_port(upstream)))) | |
3391 | break; | |
3392 | ||
3393 | if (upstream->transport == GETDNS_TRANSPORT_TLS) { | |
3394 | if (upstream_port(upstream) == getdns_port_array[j]) | |
3395 | (void) getdns_dict_set_int(d, "tls_port", | |
3396 | (uint32_t) upstream_port(upstream)); | |
3397 | if (upstream->tls_pubkey_pinset) { | |
3398 | getdns_list *pins = NULL; | |
3399 | if (_getdns_get_pubkey_pinset_list(context, | |
3400 | upstream->tls_pubkey_pinset, | |
3401 | &pins) == GETDNS_RETURN_GOOD) | |
3402 | (void) getdns_dict_set_list(d, "tls_pubkey_pinset", pins); | |
3403 | getdns_list_destroy(pins); | |
3404 | } | |
3405 | } | |
2983 | 3406 | } |
2984 | r |= _getdns_list_append_dict(upstreams, d); | |
3407 | if (!r) | |
3408 | r = _getdns_list_append_dict(upstreams, d); | |
2985 | 3409 | getdns_dict_destroy(d); |
2986 | 3410 | } |
2987 | if (r != GETDNS_RETURN_GOOD) { | |
2988 | getdns_list_destroy(upstreams); | |
2989 | return GETDNS_RETURN_MEMORY_ERROR; | |
2990 | } | |
2991 | *upstream_list = upstreams; | |
2992 | } | |
2993 | return GETDNS_RETURN_GOOD; | |
3411 | if (r) | |
3412 | getdns_list_destroy(upstreams); | |
3413 | else | |
3414 | *upstreams_r = upstreams; | |
3415 | return r; | |
2994 | 3416 | } |
2995 | 3417 | |
2996 | 3418 | getdns_return_t |
78 | 78 | GETDNS_HS_FAILED |
79 | 79 | } getdns_tls_hs_state_t; |
80 | 80 | |
81 | typedef enum getdns_tsig_algo { | |
82 | GETDNS_NO_TSIG = 0, /* Do not use tsig */ | |
83 | GETDNS_HMAC_MD5 = 1, /* 128 bits */ | |
84 | GETDNS_GSS_TSIG = 2, /* Not supported */ | |
85 | GETDNS_HMAC_SHA1 = 3, /* 160 bits */ | |
86 | GETDNS_HMAC_SHA224 = 4, | |
87 | GETDNS_HMAC_SHA256 = 5, | |
88 | GETDNS_HMAC_SHA384 = 6, | |
89 | GETDNS_HMAC_SHA512 = 7 | |
90 | } getdns_tsig_algo; | |
91 | ||
92 | typedef struct getdns_tsig_info { | |
93 | getdns_tsig_algo alg; | |
94 | const char *name; | |
95 | size_t strlen_name; | |
96 | const uint8_t *dname; | |
97 | size_t dname_len; | |
98 | size_t min_size; /* in # octets */ | |
99 | size_t max_size; /* Actual size in # octets */ | |
100 | } getdns_tsig_info; | |
101 | ||
102 | const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg); | |
103 | ||
104 | /* for doing public key pinning of TLS-capable upstreams: */ | |
105 | typedef struct sha256_pin { | |
106 | char pin[SHA256_DIGEST_LENGTH]; | |
107 | struct sha256_pin *next; | |
108 | } sha256_pin_t; | |
109 | ||
81 | 110 | typedef struct getdns_upstream { |
82 | 111 | /* backpointer to containing upstreams structure */ |
83 | 112 | struct getdns_upstreams *upstreams; |
88 | 117 | /* How is this upstream doing? */ |
89 | 118 | size_t writes_done; |
90 | 119 | size_t responses_received; |
120 | uint64_t keepalive_timeout; | |
91 | 121 | int to_retry; |
92 | 122 | int back_off; |
93 | 123 | |
96 | 126 | getdns_transport_list_t transport; |
97 | 127 | SSL* tls_obj; |
98 | 128 | getdns_tls_hs_state_t tls_hs_state; |
99 | getdns_dns_req * starttls_req; | |
100 | 129 | getdns_eventloop_event event; |
101 | 130 | getdns_eventloop *loop; |
102 | 131 | getdns_tcp_state tcp; |
103 | 132 | char tls_auth_name[256]; |
104 | 133 | size_t tls_auth_failed; |
134 | sha256_pin_t *tls_pubkey_pinset; | |
105 | 135 | |
106 | 136 | /* Pipelining of TCP network requests */ |
107 | 137 | getdns_network_req *write_queue; |
118 | 148 | unsigned has_prev_client_cookie : 1; |
119 | 149 | unsigned has_server_cookie : 1; |
120 | 150 | unsigned server_cookie_len : 5; |
151 | unsigned tls_fallback_ok : 1; | |
152 | ||
153 | /* TSIG */ | |
154 | uint8_t tsig_dname[256]; | |
155 | size_t tsig_dname_len; | |
156 | size_t tsig_size; | |
157 | uint8_t tsig_key[256]; | |
158 | getdns_tsig_algo tsig_alg; | |
121 | 159 | |
122 | 160 | } getdns_upstream; |
123 | 161 | |
137 | 175 | uint64_t timeout; |
138 | 176 | uint64_t idle_timeout; |
139 | 177 | getdns_redirects_t follow_redirects; |
140 | struct getdns_list *dns_root_servers; | |
178 | getdns_list *dns_root_servers; | |
179 | char root_servers_fn[FILENAME_MAX]; | |
141 | 180 | getdns_append_name_t append_name; |
142 | struct getdns_list *suffix; | |
181 | /* Suffix buffer containing a list of (length byte | dname) where | |
182 | * length bytes contains the length of the following dname. | |
183 | * The last dname should be the zero byte. | |
184 | */ | |
185 | const uint8_t *suffixes; | |
186 | /* Length of all suffixes in the suffix buffer */ | |
187 | size_t suffixes_len; | |
143 | 188 | uint8_t *trust_anchors; |
144 | 189 | size_t trust_anchors_len; |
145 | 190 | getdns_upstreams *upstreams; |
239 | 284 | char *_getdns_strdup(const struct mem_funcs *mfs, const char *str); |
240 | 285 | |
241 | 286 | struct getdns_bindata *_getdns_bindata_copy( |
242 | struct mem_funcs *mfs, | |
243 | const struct getdns_bindata *src); | |
287 | struct mem_funcs *mfs, size_t size, const uint8_t *data); | |
244 | 288 | |
245 | 289 | void _getdns_bindata_destroy( |
246 | 290 | struct mem_funcs *mfs, |
33 | 33 | |
34 | 34 | #include <stdio.h> |
35 | 35 | #include <string.h> |
36 | #include <arpa/inet.h> | |
37 | 36 | #include <locale.h> |
38 | 37 | #include "config.h" |
38 | #ifndef USE_WINSOCK | |
39 | #include <arpa/inet.h> | |
40 | #endif | |
39 | 41 | #ifdef HAVE_LIBIDN |
40 | 42 | #include <stringprep.h> |
41 | 43 | #include <idna.h> |
45 | 47 | #include "util-internal.h" |
46 | 48 | #include "gldns/wire2str.h" |
47 | 49 | #include "gldns/str2wire.h" |
50 | #include "dict.h" | |
51 | #include "list.h" | |
52 | #include "convert.h" | |
48 | 53 | |
49 | 54 | /* stuff to make it compile pedantically */ |
50 | 55 | #define UNUSED_PARAM(x) ((void)(x)) |
218 | 223 | return GETDNS_RETURN_GOOD; |
219 | 224 | } /* getdns_strerror */ |
220 | 225 | |
226 | ||
227 | /* --------------------- rr_dict, wire, str conversions --------------------- */ | |
228 | ||
229 | ||
230 | getdns_return_t | |
231 | getdns_rr_dict2wire( | |
232 | const getdns_dict *rr_dict, uint8_t **wire, size_t *wire_sz) | |
233 | { | |
234 | uint8_t buf_spc[4096], *buf; | |
235 | size_t buf_len = sizeof(buf_spc); | |
236 | getdns_return_t r = getdns_rr_dict2wire_buf( | |
237 | rr_dict, buf_spc, &buf_len); | |
238 | ||
239 | if (r != GETDNS_RETURN_GOOD && r != GETDNS_RETURN_NEED_MORE_SPACE) | |
240 | return r; | |
241 | ||
242 | if (!(buf = malloc(buf_len))) | |
243 | return GETDNS_RETURN_MEMORY_ERROR; | |
244 | ||
245 | if (!r) | |
246 | memcpy(buf, buf_spc, buf_len); | |
247 | ||
248 | else if ((r = getdns_rr_dict2wire_buf(rr_dict, buf, &buf_len))) { | |
249 | free(buf); | |
250 | return r; | |
251 | } | |
252 | *wire = buf; | |
253 | *wire_sz = buf_len; | |
254 | return GETDNS_RETURN_GOOD; | |
255 | } | |
256 | ||
257 | getdns_return_t | |
258 | getdns_rr_dict2wire_buf( | |
259 | const getdns_dict *rr_dict, uint8_t *wire, size_t *wire_sz) | |
260 | { | |
261 | int my_wire_sz; | |
262 | getdns_return_t r; | |
263 | ||
264 | if (!wire_sz) | |
265 | return GETDNS_RETURN_INVALID_PARAMETER; | |
266 | else | |
267 | my_wire_sz = *wire_sz; | |
268 | ||
269 | r = getdns_rr_dict2wire_scan(rr_dict, &wire, &my_wire_sz); | |
270 | if (r == GETDNS_RETURN_GOOD || r == GETDNS_RETURN_NEED_MORE_SPACE) | |
271 | *wire_sz -= my_wire_sz; | |
272 | return r; | |
273 | } | |
274 | ||
275 | getdns_return_t | |
276 | getdns_rr_dict2wire_scan( | |
277 | const getdns_dict *rr_dict, uint8_t **wire, int *wire_sz) | |
278 | { | |
279 | getdns_return_t r; | |
280 | gldns_buffer gbuf; | |
281 | ||
282 | if (!rr_dict || !wire || !*wire || !wire_sz) | |
283 | return GETDNS_RETURN_INVALID_PARAMETER; | |
284 | ||
285 | ||
286 | gldns_buffer_init_frm_data(&gbuf, *wire, *wire_sz); | |
287 | if ((r = _getdns_rr_dict2wire(rr_dict, &gbuf))) | |
288 | return r; | |
289 | ||
290 | if (gldns_buffer_position(&gbuf) == 0) | |
291 | return GETDNS_RETURN_GENERIC_ERROR; | |
292 | ||
293 | *wire += gldns_buffer_position(&gbuf); | |
294 | *wire_sz -= gldns_buffer_position(&gbuf); | |
295 | if (gldns_buffer_position(&gbuf) > gldns_buffer_limit(&gbuf)) | |
296 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
297 | else | |
298 | return GETDNS_RETURN_GOOD; | |
299 | } | |
300 | ||
301 | static struct mem_funcs _getdns_plain_mem_funcs = { | |
302 | MF_PLAIN, .mf.pln = { malloc, realloc, free } | |
303 | }; | |
304 | ||
305 | getdns_return_t | |
306 | _getdns_wire2rr_dict(struct mem_funcs *mf, | |
307 | const uint8_t *wire, size_t wire_len, getdns_dict **rr_dict) | |
308 | { | |
309 | return _getdns_wire2rr_dict_scan(mf, &wire, &wire_len, rr_dict); | |
310 | } | |
311 | getdns_return_t | |
312 | getdns_wire2rr_dict( | |
313 | const uint8_t *wire, size_t wire_len, getdns_dict **rr_dict) | |
314 | { | |
315 | return _getdns_wire2rr_dict( | |
316 | &_getdns_plain_mem_funcs, wire, wire_len, rr_dict); | |
317 | } | |
318 | ||
319 | getdns_return_t | |
320 | _getdns_wire2rr_dict_buf(struct mem_funcs *mf, | |
321 | const uint8_t *wire, size_t *wire_len, getdns_dict **rr_dict) | |
322 | { | |
323 | size_t my_wire_len; | |
324 | getdns_return_t r; | |
325 | ||
326 | if (!wire_len) | |
327 | return GETDNS_RETURN_INVALID_PARAMETER; | |
328 | else | |
329 | my_wire_len = *wire_len; | |
330 | ||
331 | if ((r = _getdns_wire2rr_dict_scan(mf, &wire, &my_wire_len, rr_dict))) | |
332 | return r; | |
333 | ||
334 | *wire_len -= my_wire_len; | |
335 | return GETDNS_RETURN_GOOD; | |
336 | } | |
337 | getdns_return_t | |
338 | getdns_wire2rr_dict_buf( | |
339 | const uint8_t *wire, size_t *wire_len, getdns_dict **rr_dict) | |
340 | { | |
341 | return _getdns_wire2rr_dict_buf( | |
342 | &_getdns_plain_mem_funcs, wire, wire_len, rr_dict); | |
343 | } | |
344 | ||
345 | getdns_return_t | |
346 | _getdns_wire2rr_dict_scan(struct mem_funcs *mf, | |
347 | const uint8_t **wire, size_t *wire_len, getdns_dict **rr_dict) | |
348 | { | |
349 | _getdns_rr_iter rr_iter_spc, *rr_iter; | |
350 | ||
351 | if (!wire || !*wire || !wire_len || !rr_dict) | |
352 | return GETDNS_RETURN_INVALID_PARAMETER; | |
353 | ||
354 | if (!(rr_iter = _getdns_single_rr_iter_init( | |
355 | &rr_iter_spc, *wire, *wire_len))) | |
356 | return GETDNS_RETURN_GENERIC_ERROR; | |
357 | ||
358 | if (!(*rr_dict = _getdns_rr_iter2rr_dict(mf, rr_iter))) | |
359 | return GETDNS_RETURN_MEMORY_ERROR; | |
360 | ||
361 | *wire_len -= (rr_iter->nxt - rr_iter->pos); | |
362 | *wire = rr_iter->nxt; | |
363 | ||
364 | return GETDNS_RETURN_GOOD; | |
365 | } | |
366 | getdns_return_t | |
367 | getdns_wire2rr_dict_scan( | |
368 | const uint8_t **wire, size_t *wire_len, getdns_dict **rr_dict) | |
369 | { | |
370 | return _getdns_wire2rr_dict_scan( | |
371 | &_getdns_plain_mem_funcs, wire, wire_len, rr_dict); | |
372 | } | |
373 | ||
374 | ||
375 | getdns_return_t | |
376 | getdns_rr_dict2str( | |
377 | const getdns_dict *rr_dict, char **str) | |
378 | { | |
379 | char buf_spc[4096], *buf; | |
380 | size_t buf_len = sizeof(buf_spc) - 1; | |
381 | getdns_return_t r = getdns_rr_dict2str_buf( | |
382 | rr_dict, buf_spc, &buf_len); | |
383 | ||
384 | if (r != GETDNS_RETURN_GOOD && r != GETDNS_RETURN_NEED_MORE_SPACE) | |
385 | return r; | |
386 | ||
387 | buf_len += 1; | |
388 | if (!(buf = malloc(buf_len))) | |
389 | return GETDNS_RETURN_MEMORY_ERROR; | |
390 | ||
391 | if (!r) | |
392 | memcpy(buf, buf_spc, buf_len); | |
393 | ||
394 | else if ((r = getdns_rr_dict2str_buf(rr_dict, buf, &buf_len))) { | |
395 | free(buf); | |
396 | return r; | |
397 | } | |
398 | *str = buf; | |
399 | return GETDNS_RETURN_GOOD; | |
400 | } | |
401 | ||
402 | getdns_return_t | |
403 | getdns_rr_dict2str_buf( | |
404 | const getdns_dict *rr_dict, char *str, size_t *str_len) | |
405 | { | |
406 | int my_str_len; | |
407 | getdns_return_t r; | |
408 | ||
409 | if (!str_len) | |
410 | return GETDNS_RETURN_INVALID_PARAMETER; | |
411 | else | |
412 | my_str_len = *str_len; | |
413 | ||
414 | r = getdns_rr_dict2str_scan(rr_dict, &str, &my_str_len); | |
415 | if (r == GETDNS_RETURN_GOOD || r == GETDNS_RETURN_NEED_MORE_SPACE) | |
416 | *str_len -= my_str_len; | |
417 | return r; | |
418 | ||
419 | } | |
420 | ||
421 | getdns_return_t | |
422 | getdns_rr_dict2str_scan( | |
423 | const getdns_dict *rr_dict, char **str, int *str_len) | |
424 | { | |
425 | getdns_return_t r; | |
426 | gldns_buffer gbuf; | |
427 | uint8_t buf_spc[4096], *buf = buf_spc, *scan_buf; | |
428 | size_t sz, scan_sz; | |
429 | int prev_str_len; | |
430 | char *prev_str; | |
431 | int sz_needed; | |
432 | ||
433 | if (!rr_dict || !str || !*str || !str_len) | |
434 | return GETDNS_RETURN_INVALID_PARAMETER; | |
435 | ||
436 | gldns_buffer_init_frm_data(&gbuf, buf, sizeof(buf_spc)); | |
437 | r = _getdns_rr_dict2wire(rr_dict, &gbuf); | |
438 | if (gldns_buffer_position(&gbuf) > sizeof(buf_spc)) { | |
439 | if (!(buf = GETDNS_XMALLOC( | |
440 | rr_dict->mf, uint8_t, (sz = gldns_buffer_position(&gbuf))))) { | |
441 | return GETDNS_RETURN_MEMORY_ERROR; | |
442 | } | |
443 | gldns_buffer_init_frm_data(&gbuf, buf, sz); | |
444 | r = _getdns_rr_dict2wire(rr_dict, &gbuf); | |
445 | } | |
446 | if (r) { | |
447 | if (buf != buf_spc) | |
448 | GETDNS_FREE(rr_dict->mf, buf); | |
449 | return r; | |
450 | } | |
451 | scan_buf = gldns_buffer_begin(&gbuf); | |
452 | scan_sz = gldns_buffer_position(&gbuf); | |
453 | prev_str = *str; | |
454 | prev_str_len = *str_len; | |
455 | sz = (size_t)*str_len; | |
456 | sz_needed = gldns_wire2str_rr_scan( | |
457 | &scan_buf, &scan_sz, str, &sz, NULL, 0); | |
458 | ||
459 | if (sz_needed > prev_str_len) { | |
460 | *str = prev_str + sz_needed; | |
461 | *str_len = prev_str_len - sz_needed; | |
462 | r = GETDNS_RETURN_NEED_MORE_SPACE; | |
463 | } else { | |
464 | *str_len = sz; | |
465 | **str = 0; | |
466 | } | |
467 | if (buf != buf_spc) | |
468 | GETDNS_FREE(rr_dict->mf, buf); | |
469 | return r; | |
470 | } | |
471 | ||
472 | ||
473 | getdns_return_t | |
474 | _getdns_str2rr_dict(struct mem_funcs *mf, | |
475 | const char *str, getdns_dict **rr_dict, const char *origin, uint32_t default_ttl) | |
476 | { | |
477 | uint8_t wire_spc[4096], *wire = wire_spc; | |
478 | uint8_t origin_spc[256], *origin_wf; | |
479 | size_t origin_len = sizeof(origin_spc), wire_len = sizeof(wire_spc); | |
480 | int e; | |
481 | getdns_return_t r; | |
482 | ||
483 | if (!str || !rr_dict) | |
484 | return GETDNS_RETURN_INVALID_PARAMETER; | |
485 | ||
486 | if (!origin) | |
487 | origin_wf = NULL; | |
488 | ||
489 | else if (gldns_str2wire_dname_buf(origin, origin_spc, &origin_len)) | |
490 | return GETDNS_RETURN_GENERIC_ERROR; | |
491 | else | |
492 | origin_wf = origin_spc; | |
493 | ||
494 | e = gldns_str2wire_rr_buf(str, wire, &wire_len, | |
495 | NULL, default_ttl, origin_wf, origin_len, NULL, 0); | |
496 | if (GLDNS_WIREPARSE_ERROR(e) == GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL) { | |
497 | ||
498 | if (!(wire = GETDNS_XMALLOC( | |
499 | *mf, uint8_t, (wire_len = GLDNS_RR_BUF_SIZE)))) | |
500 | return GETDNS_RETURN_MEMORY_ERROR; | |
501 | e = gldns_str2wire_rr_buf(str, wire, &wire_len, | |
502 | NULL, default_ttl, origin_wf, origin_len, NULL, 0); | |
503 | } | |
504 | if (e) { | |
505 | if (wire != wire_spc) | |
506 | GETDNS_FREE(*mf, wire); | |
507 | return GETDNS_RETURN_GENERIC_ERROR; | |
508 | } | |
509 | r = _getdns_wire2rr_dict(mf, wire, wire_len, rr_dict); | |
510 | if (wire != wire_spc) | |
511 | GETDNS_FREE(*mf, wire); | |
512 | return r; | |
513 | } | |
514 | getdns_return_t | |
515 | getdns_str2rr_dict( | |
516 | const char *str, getdns_dict **rr_dict, const char *origin, uint32_t default_ttl) | |
517 | { | |
518 | return _getdns_str2rr_dict( | |
519 | &_getdns_plain_mem_funcs, str, rr_dict, origin, default_ttl); | |
520 | } | |
521 | ||
522 | ||
523 | getdns_return_t | |
524 | _getdns_fp2rr_list(struct mem_funcs *mf, | |
525 | FILE *in, getdns_list **rr_list, const char *origin, uint32_t default_ttl) | |
526 | { | |
527 | struct gldns_file_parse_state pst; | |
528 | getdns_list *rrs; | |
529 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
530 | uint8_t *rr; | |
531 | size_t len, dname_len; | |
532 | getdns_dict *rr_dict; | |
533 | ||
534 | if (!in || !rr_list) | |
535 | return GETDNS_RETURN_INVALID_PARAMETER; | |
536 | ||
537 | if (!origin) { | |
538 | *pst.origin = 0; | |
539 | pst.origin_len = 1; | |
540 | ||
541 | } else if (gldns_str2wire_dname_buf(origin,pst.origin,&pst.origin_len)) | |
542 | return GETDNS_RETURN_GENERIC_ERROR; | |
543 | ||
544 | *pst.prev_rr = 0; | |
545 | pst.prev_rr_len = 1; | |
546 | pst.default_ttl = default_ttl; | |
547 | pst.lineno = 1; | |
548 | ||
549 | if (!(rrs = _getdns_list_create_with_mf(mf))) | |
550 | return GETDNS_RETURN_MEMORY_ERROR; | |
551 | ||
552 | ||
553 | if (!(rr = GETDNS_XMALLOC(*mf, uint8_t, GLDNS_RR_BUF_SIZE))) | |
554 | r = GETDNS_RETURN_MEMORY_ERROR; | |
555 | ||
556 | else while (r == GETDNS_RETURN_GOOD && !feof(in)) { | |
557 | len = GLDNS_RR_BUF_SIZE; | |
558 | dname_len = 0; | |
559 | if (gldns_fp2wire_rr_buf(in, rr, &len, &dname_len, &pst)) | |
560 | break; | |
561 | if (dname_len && dname_len < sizeof(pst.prev_rr)) { | |
562 | memcpy(pst.prev_rr, rr, dname_len); | |
563 | pst.prev_rr_len = dname_len; | |
564 | } | |
565 | if (len == 0) | |
566 | continue; | |
567 | if ((r = _getdns_wire2rr_dict(mf, rr, len, &rr_dict))) | |
568 | break; | |
569 | r = _getdns_list_append_dict(rrs, rr_dict); | |
570 | getdns_dict_destroy(rr_dict); | |
571 | } | |
572 | if (rr) | |
573 | GETDNS_FREE(*mf, rr); | |
574 | if (r) | |
575 | getdns_list_destroy(rrs); | |
576 | else | |
577 | *rr_list = rrs; | |
578 | return r; | |
579 | } | |
580 | ||
581 | getdns_return_t | |
582 | getdns_fp2rr_list( | |
583 | FILE *in, getdns_list **rr_list, const char *origin, uint32_t default_ttl) | |
584 | { | |
585 | return _getdns_fp2rr_list( | |
586 | &_getdns_plain_mem_funcs, in, rr_list, origin, default_ttl); | |
587 | } | |
588 | ||
221 | 589 | /* convert.c */ |
0 | /** | |
1 | * | |
2 | * \file convert.h | |
3 | * @brief getdns label conversion functions | |
4 | * | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2013, NLnet Labs, Verisign, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions are met: | |
13 | * * Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * * Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * * Neither the names of the copyright holders nor the | |
19 | * names of its contributors may be used to endorse or promote products | |
20 | * derived from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
25 | * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY | |
26 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
29 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef _GETDNS_CONVERT_H_ | |
35 | #define _GETDNS_CONVERT_H_ | |
36 | ||
37 | #include "types-internal.h" | |
38 | #include <stdio.h> | |
39 | ||
40 | getdns_return_t _getdns_wire2rr_dict(struct mem_funcs *mf, | |
41 | const uint8_t *wire, size_t wire_len, getdns_dict **rr_dict); | |
42 | ||
43 | getdns_return_t _getdns_wire2rr_dict_buf(struct mem_funcs *mf, | |
44 | const uint8_t *wire, size_t *wire_len, getdns_dict **rr_dict); | |
45 | ||
46 | getdns_return_t _getdns_wire2rr_dict_scan(struct mem_funcs *mf, | |
47 | const uint8_t **wire, size_t *wire_len, getdns_dict **rr_dict); | |
48 | ||
49 | getdns_return_t _getdns_str2rr_dict(struct mem_funcs *mf, const char *str, | |
50 | getdns_dict **rr_dict, const char *origin, uint32_t default_ttl); | |
51 | ||
52 | getdns_return_t _getdns_fp2rr_list(struct mem_funcs *mf, FILE *in, | |
53 | getdns_list **rr_list, const char *origin, uint32_t default_ttl); | |
54 | ||
55 | #endif | |
56 | /* convert.h */ |
0 | /** | |
1 | * | |
2 | * \file debug.h | |
3 | * /brief Macro's for debugging | |
4 | * | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2015, NLnet Labs, Verisign, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions are met: | |
13 | * * Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * * Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * * Neither the names of the copyright holders nor the | |
19 | * names of its contributors may be used to endorse or promote products | |
20 | * derived from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
25 | * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY | |
26 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
29 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef DEBUG_H | |
35 | #define DEBUG_H | |
36 | ||
37 | #include "config.h" | |
38 | ||
39 | #define DEBUG_ON(...) do { \ | |
40 | struct timeval tv; \ | |
41 | struct tm tm; \ | |
42 | char buf[10]; \ | |
43 | \ | |
44 | gettimeofday(&tv, NULL); \ | |
45 | gmtime_r(&tv.tv_sec, &tm); \ | |
46 | strftime(buf, 10, "%T", &tm); \ | |
47 | fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ | |
48 | fprintf(stderr, __VA_ARGS__); \ | |
49 | } while (0) | |
50 | ||
51 | #define DEBUG_NL(...) do { \ | |
52 | struct timeval tv; \ | |
53 | struct tm tm; \ | |
54 | char buf[10]; \ | |
55 | \ | |
56 | gettimeofday(&tv, NULL); \ | |
57 | gmtime_r(&tv.tv_sec, &tm); \ | |
58 | strftime(buf, 10, "%T", &tm); \ | |
59 | fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ | |
60 | fprintf(stderr, __VA_ARGS__); \ | |
61 | fprintf(stderr, "\n"); \ | |
62 | } while (0) | |
63 | ||
64 | ||
65 | #define DEBUG_OFF(...) do {} while (0) | |
66 | ||
67 | #if defined(SCHED_DEBUG) && SCHED_DEBUG | |
68 | #include <time.h> | |
69 | #define DEBUG_SCHED(...) DEBUG_ON(__VA_ARGS__) | |
70 | #else | |
71 | #define DEBUG_SCHED(...) DEBUG_OFF(__VA_ARGS__) | |
72 | #endif | |
73 | ||
74 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
75 | #include <time.h> | |
76 | #define DEBUG_STUB(...) DEBUG_ON(__VA_ARGS__) | |
77 | #else | |
78 | #define DEBUG_STUB(...) DEBUG_OFF(__VA_ARGS__) | |
79 | #endif | |
80 | ||
81 | #if defined(SEC_DEBUG) && SEC_DEBUG | |
82 | #include <time.h> | |
83 | #define DEBUG_SEC(...) DEBUG_ON(__VA_ARGS__) | |
84 | #else | |
85 | #define DEBUG_SEC(...) DEBUG_OFF(__VA_ARGS__) | |
86 | #endif | |
87 | ||
88 | #endif | |
89 | /* debug.h */ |
34 | 34 | */ |
35 | 35 | |
36 | 36 | #include <ctype.h> |
37 | #include "config.h" | |
38 | #ifndef USE_WINSOCK | |
37 | 39 | #include <sys/types.h> |
38 | 40 | #include <sys/socket.h> |
39 | 41 | #include <netinet/in.h> |
40 | 42 | #include <arpa/inet.h> |
43 | #endif | |
41 | 44 | |
42 | 45 | #include "types-internal.h" |
43 | 46 | #include "util-internal.h" |
276 | 279 | |
277 | 280 | RBTREE_FOR(item, struct getdns_dict_item *, |
278 | 281 | (_getdns_rbtree_t *)&(dict->root)) { |
279 | _getdns_list_append_string(*answer, item->node.key); | |
282 | _getdns_list_append_const_bindata(*answer, | |
283 | strlen(item->node.key) + 1, item->node.key); | |
280 | 284 | } |
281 | 285 | return GETDNS_RETURN_GOOD; |
282 | 286 | } /* getdns_dict_get_names */ |
573 | 577 | |
574 | 578 | /*---------------------------------------- getdns_dict_set_bindata */ |
575 | 579 | getdns_return_t |
576 | getdns_dict_set_bindata( | |
577 | getdns_dict *dict, const char *name, const getdns_bindata *child_bindata) | |
580 | _getdns_dict_set_const_bindata( | |
581 | getdns_dict *dict, const char *name, size_t size, const void *data) | |
578 | 582 | { |
579 | 583 | getdns_item *item; |
580 | 584 | getdns_bindata *newbindata; |
581 | 585 | getdns_return_t r; |
582 | 586 | |
583 | if (!dict || !name || !child_bindata) | |
587 | if (!dict || !name) | |
584 | 588 | return GETDNS_RETURN_INVALID_PARAMETER; |
585 | 589 | |
586 | if (!(newbindata = _getdns_bindata_copy(&dict->mf, child_bindata))) | |
590 | if (!(newbindata = _getdns_bindata_copy(&dict->mf, size, data))) | |
587 | 591 | return GETDNS_RETURN_MEMORY_ERROR; |
588 | 592 | |
589 | 593 | if ((r = _getdns_dict_find_and_add(dict, name, &item))) { |
595 | 599 | return GETDNS_RETURN_GOOD; |
596 | 600 | } /* getdns_dict_set_bindata */ |
597 | 601 | |
602 | getdns_return_t | |
603 | getdns_dict_set_bindata( | |
604 | getdns_dict *dict, const char *name, const getdns_bindata *child_bindata) | |
605 | { | |
606 | return !child_bindata ? GETDNS_RETURN_INVALID_PARAMETER | |
607 | : _getdns_dict_set_const_bindata( | |
608 | dict, name, child_bindata->size, child_bindata->data); | |
609 | } | |
610 | ||
598 | 611 | /*---------------------------------------- getdns_dict_set_bindata */ |
599 | 612 | getdns_return_t |
600 | 613 | getdns_dict_util_set_string(getdns_dict *dict, char *name, const char *value) |
601 | 614 | { |
602 | getdns_item *item; | |
603 | getdns_bindata *newbindata; | |
604 | getdns_return_t r; | |
605 | ||
606 | if (!dict || !name || !value) | |
607 | return GETDNS_RETURN_INVALID_PARAMETER; | |
608 | ||
609 | if (!(newbindata = GETDNS_MALLOC(dict->mf, getdns_bindata))) | |
610 | return GETDNS_RETURN_MEMORY_ERROR; | |
611 | ||
612 | newbindata->size = strlen(value); | |
613 | if (!(newbindata->data = (void *)_getdns_strdup(&dict->mf, value))) { | |
614 | GETDNS_FREE(dict->mf, newbindata); | |
615 | return GETDNS_RETURN_MEMORY_ERROR; | |
616 | } | |
617 | if ((r = _getdns_dict_find_and_add(dict, name, &item))) { | |
618 | _getdns_bindata_destroy(&dict->mf, newbindata); | |
619 | return r; | |
620 | } | |
621 | item->dtype = t_bindata; | |
622 | item->data.bindata = newbindata; | |
623 | return GETDNS_RETURN_GOOD; | |
615 | return value | |
616 | ? _getdns_dict_set_const_bindata(dict, name, strlen(value), value) | |
617 | : GETDNS_RETURN_INVALID_PARAMETER; | |
624 | 618 | } /* getdns_dict_util_set_dict */ |
625 | 619 | |
626 | 620 | /*---------------------------------------- getdns_dict_set_int */ |
655 | 649 | return spaces + 80 - (indent < 80 ? indent : 0); |
656 | 650 | } /* getdns_indent */ |
657 | 651 | |
658 | static int | |
652 | int | |
659 | 653 | _getdns_bindata_is_dname(getdns_bindata *bindata) |
660 | 654 | { |
661 | 655 | size_t i = 0, n_labels = 0; |
662 | 656 | |
663 | 657 | while (i < bindata->size && bindata->data[i]) { |
658 | if (bindata->data[i] & 0xC0) /* Compression pointer! */ | |
659 | return 0; | |
660 | ||
664 | 661 | i += ((size_t)bindata->data[i]) + 1; |
665 | 662 | n_labels++; |
666 | 663 | } |
991 | 988 | if (!json && |
992 | 989 | (strcmp(item->node.key, "answer_type") == 0 || |
993 | 990 | strcmp(item->node.key, "dnssec_status") == 0 || |
991 | strcmp(item->node.key, "tsig_status") == 0 || | |
994 | 992 | strcmp(item->node.key, "status") == 0 || |
995 | 993 | strcmp(item->node.key, "append_name") == 0 || |
996 | 994 | strcmp(item->node.key, "follow_redirects") == 0 || |
1059 | 1057 | return -1; |
1060 | 1058 | if (getdns_pp_list(buf, indent, item->i.data.list, |
1061 | 1059 | (strcmp(item->node.key, "namespaces") == 0 || |
1062 | strcmp(item->node.key, "dns_transport_list") == 0), | |
1060 | strcmp(item->node.key, "dns_transport_list") == 0 | |
1061 | || strcmp(item->node.key, "bad_dns") == 0), | |
1063 | 1062 | json) < 0) |
1064 | 1063 | return -1; |
1065 | 1064 | break; |
70 | 70 | getdns_return_t _getdns_dict_find_and_add( |
71 | 71 | getdns_dict *dict, const char *key, getdns_item **item); |
72 | 72 | |
73 | /* Return 1 (true) if bindata can be interpreted as an | |
74 | * uncompressed dname. | |
75 | */ | |
76 | int _getdns_bindata_is_dname(getdns_bindata *bindata); | |
77 | ||
73 | 78 | #endif |
74 | 79 | |
75 | 80 | /* dict.h */ |
187 | 187 | * "dnssec_return_validation_chain Extension". |
188 | 188 | */ |
189 | 189 | |
190 | #include "config.h" | |
191 | #include "debug.h" | |
190 | 192 | #include <sys/types.h> |
191 | 193 | #include <sys/stat.h> |
192 | 194 | #include <unistd.h> |
193 | 195 | #include <ctype.h> |
194 | 196 | #include <openssl/sha.h> |
195 | 197 | #include "getdns/getdns.h" |
196 | #include "config.h" | |
197 | 198 | #include "context.h" |
198 | 199 | #include "util-internal.h" |
199 | 200 | #include "types-internal.h" |
218 | 219 | /******************* Frequently Used Utility Functions ********************* |
219 | 220 | *****************************************************************************/ |
220 | 221 | |
221 | inline static size_t _dname_len(uint8_t *name) | |
222 | { | |
223 | uint8_t *p; | |
222 | inline static size_t _dname_len(const uint8_t *name) | |
223 | { | |
224 | const uint8_t *p; | |
224 | 225 | for (p = name; *p; p += *p + 1) |
225 | 226 | /* pass */ |
226 | 227 | ; |
227 | 228 | return p - name + 1; |
228 | 229 | } |
229 | 230 | |
230 | inline static size_t _dname_label_count(uint8_t *name) | |
231 | inline static size_t _dname_label_count(const uint8_t *name) | |
231 | 232 | { |
232 | 233 | size_t c; |
233 | 234 | for (c = 0; *name; name += *name + 1, c++) |
266 | 267 | return r; |
267 | 268 | } |
268 | 269 | |
269 | inline static void _dname_canonicalize(uint8_t *dname) | |
270 | { | |
271 | uint8_t *next_label; | |
272 | ||
273 | while (*dname) { | |
274 | next_label = dname + *dname + 1; | |
275 | dname += 1; | |
276 | while (dname < next_label) { | |
277 | *dname = (uint8_t)tolower((unsigned char)*dname); | |
278 | dname++; | |
279 | } | |
280 | } | |
281 | } | |
270 | inline static void _dname_canonicalize(const uint8_t *src, uint8_t *dst) | |
271 | { | |
272 | const uint8_t *next_label; | |
273 | ||
274 | while (*src) { | |
275 | next_label = src + *src + 1; | |
276 | *dst++ = *src++; | |
277 | while (src < next_label) | |
278 | *dst++ = (uint8_t)tolower((unsigned char)*src++); | |
279 | } | |
280 | } | |
281 | ||
282 | inline static void _dname_canonicalize2(uint8_t *dname) | |
283 | { | |
284 | _dname_canonicalize(dname, dname); | |
285 | } | |
286 | ||
282 | 287 | |
283 | 288 | /* Fills the array pointed to by labels (of at least 128 uint8_t * pointers) |
284 | 289 | * with pointers to labels in given dname in reversed order. So that |
293 | 298 | * labels[3] will be "www.getdnsapi.net." |
294 | 299 | * The returned value will be &labels[4] |
295 | 300 | */ |
296 | static uint8_t **reverse_labels(uint8_t *dname, uint8_t **labels) | |
301 | static const uint8_t **reverse_labels( | |
302 | const uint8_t *dname, const uint8_t **labels) | |
297 | 303 | { |
298 | 304 | if (*dname) |
299 | 305 | labels = reverse_labels(dname + *dname + 1, labels); |
301 | 307 | return labels + 1; |
302 | 308 | } |
303 | 309 | |
304 | static uint8_t *dname_shared_parent(uint8_t *left, uint8_t *right) | |
305 | { | |
306 | uint8_t *llabels[128], *rlabels[128], **last_llabel, **last_rlabel, | |
307 | **llabel, **rlabel, *l, *r, sz; | |
310 | static const uint8_t *dname_shared_parent( | |
311 | const uint8_t *left, const uint8_t *right) | |
312 | { | |
313 | const uint8_t *llabels[128], *rlabels[128], **last_llabel, **last_rlabel, | |
314 | **llabel, **rlabel, *l, *r; | |
315 | uint8_t sz; | |
308 | 316 | |
309 | 317 | last_llabel = reverse_labels(left, llabels); |
310 | 318 | last_rlabel = reverse_labels(right, rlabels); |
332 | 340 | return llabel[-1]; |
333 | 341 | } |
334 | 342 | |
335 | static int dname_compare(uint8_t *left, uint8_t *right) | |
336 | { | |
337 | uint8_t *llabels[128], *rlabels[128], **last_llabel, **last_rlabel, | |
338 | **llabel, **rlabel, *l, *r, lsz, rsz; | |
343 | static int dname_compare(const uint8_t *left, const uint8_t *right) | |
344 | { | |
345 | const uint8_t *llabels[128], *rlabels[128], **last_llabel, **last_rlabel, | |
346 | **llabel, **rlabel, *l, *r; | |
347 | uint8_t lsz, rsz; | |
339 | 348 | |
340 | 349 | last_llabel = reverse_labels(left, llabels); |
341 | 350 | last_rlabel = reverse_labels(right, rlabels); |
372 | 381 | |
373 | 382 | static int bitmap_has_type(_getdns_rdf_iter *bitmap, uint16_t rr_type) |
374 | 383 | { |
375 | uint8_t *dptr, *dend; | |
384 | const uint8_t *dptr, *dend; | |
376 | 385 | uint8_t window = rr_type >> 8; |
377 | 386 | uint8_t subtype = rr_type & 0xFF; |
378 | 387 | |
396 | 405 | { |
397 | 406 | char str_spc[8192], *str = str_spc; |
398 | 407 | size_t str_len = sizeof(str_spc); |
399 | uint8_t *data = rr->pos; | |
408 | const uint8_t *data = rr->pos; | |
400 | 409 | size_t data_len = rr->nxt - rr->pos; |
401 | 410 | |
402 | 411 | if (!rr || !rr->pos) { |
404 | 413 | return; |
405 | 414 | } |
406 | 415 | (void) gldns_wire2str_rr_scan( |
407 | &data, &data_len, &str, &str_len, rr->pkt, rr->pkt_end - rr->pkt); | |
416 | (UNCONST_UINT8_p *) &data, &data_len, &str, &str_len, | |
417 | (UNCONST_UINT8_p) rr->pkt, rr->pkt_end - rr->pkt); | |
408 | 418 | DEBUG_SEC("%s%s", msg, str_spc); |
409 | 419 | } |
410 | inline static void debug_sec_print_dname(const char *msg, uint8_t *label) | |
420 | inline static void debug_sec_print_dname(const char *msg, const uint8_t *label) | |
411 | 421 | { |
412 | 422 | char str[1024]; |
413 | 423 | |
414 | if (label && gldns_wire2str_dname_buf(label, 256, str, sizeof(str))) | |
424 | if (label && gldns_wire2str_dname_buf( | |
425 | (UNCONST_UINT8_p)label, 256, str, sizeof(str))) | |
415 | 426 | DEBUG_SEC("%s%s\n", msg, str); |
416 | 427 | else |
417 | 428 | DEBUG_SEC("%s<nil>\n", msg); |
418 | } | |
419 | inline static void debug_sec_print_pkt( | |
420 | const char *msg, uint8_t *pkt, size_t pkt_len) | |
421 | { | |
422 | char *str; | |
423 | DEBUG_SEC("%s%s\n", msg, (str = gldns_wire2str_pkt(pkt, pkt_len))); | |
424 | if (str) free(str); | |
425 | 429 | } |
426 | 430 | #else |
427 | 431 | #define debug_sec_print_rr(...) DEBUG_OFF(__VA_ARGS__) |
441 | 445 | { return rr->rr_type + 4 <= rr->nxt ? gldns_read_uint16(rr->rr_type + 2) : 0; } |
442 | 446 | |
443 | 447 | /* Utility function to compare owner name of rr with name */ |
444 | static int rr_owner_equal(_getdns_rr_iter *rr, uint8_t *name) | |
445 | { | |
446 | uint8_t owner_spc[256], *owner; | |
448 | static int rr_owner_equal(_getdns_rr_iter *rr, const uint8_t *name) | |
449 | { | |
450 | uint8_t owner_spc[256]; | |
451 | const uint8_t *owner; | |
447 | 452 | size_t owner_len = sizeof(owner_spc); |
448 | 453 | |
449 | 454 | return (owner = _getdns_owner_if_or_as_decompressed(rr, owner_spc |
469 | 474 | |
470 | 475 | /* Filter that only iterates over RRs with a certain name/class/type */ |
471 | 476 | static _getdns_rr_iter *rr_iter_name_class_type(_getdns_rr_iter *rr, |
472 | uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
477 | const uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
473 | 478 | { |
474 | 479 | while (rr_iter_ansauth(rr) && !( |
475 | 480 | rr_iter_type(rr) == rr_type && |
483 | 488 | |
484 | 489 | /* Filter that only iterates over RRs that do not have a name/class/type */ |
485 | 490 | static _getdns_rr_iter *rr_iter_not_name_class_type(_getdns_rr_iter *rr, |
486 | uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
491 | const uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
487 | 492 | { |
488 | 493 | while (rr_iter_ansauth(rr) && ( |
489 | 494 | rr_iter_type(rr) == GETDNS_RRTYPE_RRSIG || ( |
500 | 505 | * a RRset with a certain name/class/type |
501 | 506 | */ |
502 | 507 | static _getdns_rr_iter *rr_iter_rrsig_covering(_getdns_rr_iter *rr, |
503 | uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
508 | const uint8_t *name, uint16_t rr_class, uint16_t rr_type) | |
504 | 509 | { |
505 | 510 | while (rr_iter_ansauth(rr) && !( |
506 | 511 | rr_iter_type(rr) == GETDNS_RRTYPE_RRSIG && |
515 | 520 | } |
516 | 521 | |
517 | 522 | typedef struct getdns_rrset { |
518 | uint8_t *name; | |
519 | uint16_t rr_class; | |
520 | uint16_t rr_type; | |
521 | uint8_t *pkt; | |
522 | size_t pkt_len; | |
523 | const uint8_t *name; | |
524 | uint16_t rr_class; | |
525 | uint16_t rr_type; | |
526 | uint8_t *pkt; | |
527 | size_t pkt_len; | |
523 | 528 | } getdns_rrset; |
524 | 529 | |
525 | 530 | typedef struct rrtype_iter { |
589 | 594 | return; |
590 | 595 | } |
591 | 596 | gldns_buffer_init_frm_data(&buf, buf_space, sizeof(buf_space)); |
592 | if (gldns_wire2str_dname_buf(rrset->name, 256, owner, sizeof(owner))) | |
597 | if (gldns_wire2str_dname_buf( | |
598 | (UNCONST_UINT8_p)rrset->name, 256, owner, sizeof(owner))) | |
593 | 599 | gldns_buffer_printf(&buf, "%s ", owner); |
594 | 600 | else gldns_buffer_printf(&buf, "<nil> "); |
595 | 601 | |
763 | 769 | * to equip the chain nodes with their RR sets are done alongside construction. |
764 | 770 | * Hence they need to be enumerated before the construction functions. |
765 | 771 | */ |
766 | static void val_chain_sched(chain_head *head, uint8_t *dname); | |
767 | static void val_chain_sched_ds(chain_head *head, uint8_t *dname); | |
772 | static void val_chain_sched(chain_head *head, const uint8_t *dname); | |
773 | static void val_chain_sched_ds(chain_head *head, const uint8_t *dname); | |
768 | 774 | static void val_chain_sched_signer(chain_head *head, rrsig_iter *rrsig); |
769 | static void val_chain_sched_soa(chain_head *head, uint8_t *dname); | |
775 | static void val_chain_sched_soa(chain_head *head, const uint8_t *dname); | |
770 | 776 | |
771 | 777 | static chain_head *add_rrset2val_chain(struct mem_funcs *mf, |
772 | 778 | chain_head **chain_p, getdns_rrset *rrset, getdns_network_req *netreq) |
773 | 779 | { |
774 | 780 | chain_head *head; |
775 | uint8_t *labels[128], **last_label, **label; | |
781 | const uint8_t *labels[128], **last_label, **label; | |
776 | 782 | |
777 | 783 | size_t max_labels; /* max labels in common */ |
778 | 784 | chain_head *max_head; |
779 | 785 | chain_node *max_node; |
780 | 786 | |
781 | 787 | size_t dname_len, head_sz, node_count, n; |
782 | uint8_t *dname, *region; | |
788 | const uint8_t *dname; | |
789 | uint8_t *region; | |
783 | 790 | chain_node *node; |
784 | 791 | |
785 | 792 | last_label = reverse_labels(rrset->name, labels); |
905 | 912 | _getdns_rdf_iter rdf_spc, *rdf; |
906 | 913 | rrtype_iter drr_spc, *drr; |
907 | 914 | _getdns_rdf_iter drdf_spc, *drdf; |
908 | uint8_t cname_rdata_spc[256], *cname_rdata, | |
909 | dname_rdata_spc[256], *dname_rdata, | |
915 | uint8_t cname_rdata_spc[256], | |
916 | dname_rdata_spc[256], | |
910 | 917 | synth_name[256], |
911 | *synth_name_end = synth_name + sizeof(synth_name) - 1, *s, *c; | |
918 | *synth_name_end = synth_name + sizeof(synth_name) - 1, *s; | |
919 | const uint8_t *cname_rdata, *dname_rdata, *c; | |
912 | 920 | size_t cname_rdata_len = sizeof(cname_rdata_spc), |
913 | 921 | dname_rdata_len = sizeof(dname_rdata_len), |
914 | 922 | cname_labels, dname_labels; |
1048 | 1056 | */ |
1049 | 1057 | static void add_question2val_chain(struct mem_funcs *mf, |
1050 | 1058 | chain_head **chain_p, uint8_t *pkt, size_t pkt_len, |
1051 | uint8_t *qname, uint16_t qtype, uint16_t qclass, | |
1059 | const uint8_t *qname, uint16_t qtype, uint16_t qclass, | |
1052 | 1060 | getdns_network_req *netreq) |
1053 | 1061 | { |
1054 | 1062 | getdns_rrset q_rrset; |
1132 | 1140 | context = node->chains->netreq->owner->context; |
1133 | 1141 | loop = node->chains->netreq->owner->loop; |
1134 | 1142 | |
1135 | if (!gldns_wire2str_dname_buf(node->ds.name, 256, name, sizeof(name))) | |
1143 | if (!gldns_wire2str_dname_buf( | |
1144 | (UNCONST_UINT8_p)node->ds.name, 256, name, sizeof(name))) | |
1136 | 1145 | return; |
1137 | 1146 | |
1138 | 1147 | DEBUG_SEC("schedule SOA lookup for %s\n", name); |
1150 | 1159 | * answer, then a DS/DNSKEY lookup will follow the acquire the link of the |
1151 | 1160 | * authentication chain. |
1152 | 1161 | */ |
1153 | static void val_chain_sched_soa(chain_head *head, uint8_t *dname) | |
1162 | static void val_chain_sched_soa(chain_head *head, const uint8_t *dname) | |
1154 | 1163 | { |
1155 | 1164 | chain_node *node; |
1156 | 1165 | |
1179 | 1188 | context = node->chains->netreq->owner->context; |
1180 | 1189 | loop = node->chains->netreq->owner->loop; |
1181 | 1190 | |
1182 | if (!gldns_wire2str_dname_buf(node->ds.name, 256, name, sizeof(name))) | |
1191 | if (!gldns_wire2str_dname_buf( | |
1192 | (UNCONST_UINT8_p)node->ds.name, 256, name, sizeof(name))) | |
1183 | 1193 | return; |
1184 | 1194 | |
1185 | 1195 | DEBUG_SEC("schedule DS & DNSKEY lookup for %s\n", name); |
1199 | 1209 | node->ds_req = dnsreq->netreqs[0]; |
1200 | 1210 | } |
1201 | 1211 | |
1202 | static void val_chain_sched(chain_head *head, uint8_t *dname) | |
1212 | static void val_chain_sched(chain_head *head, const uint8_t *dname) | |
1203 | 1213 | { |
1204 | 1214 | chain_node *node; |
1205 | 1215 | |
1223 | 1233 | context = node->chains->netreq->owner->context; |
1224 | 1234 | loop = node->chains->netreq->owner->loop; |
1225 | 1235 | |
1226 | if (!gldns_wire2str_dname_buf(node->ds.name, 256, name, sizeof(name))) | |
1236 | if (!gldns_wire2str_dname_buf( | |
1237 | (UNCONST_UINT8_p)node->ds.name, 256, name, sizeof(name))) | |
1238 | ||
1227 | 1239 | return; |
1228 | 1240 | |
1229 | 1241 | DEBUG_SEC("schedule DS lookup for %s\n", name); |
1236 | 1248 | node->ds_req = ds_req->netreqs[0]; |
1237 | 1249 | } |
1238 | 1250 | |
1239 | static void val_chain_sched_ds(chain_head *head, uint8_t *dname) | |
1251 | static void val_chain_sched_ds(chain_head *head, const uint8_t *dname) | |
1240 | 1252 | { |
1241 | 1253 | chain_node *node; |
1242 | 1254 | |
1253 | 1265 | static void val_chain_sched_signer_node(chain_node *node, rrsig_iter *rrsig) |
1254 | 1266 | { |
1255 | 1267 | _getdns_rdf_iter rdf_spc, *rdf; |
1256 | uint8_t signer_spc[256], *signer; | |
1257 | size_t signer_len; | |
1268 | uint8_t signer_spc[256]; | |
1269 | const uint8_t *signer; | |
1270 | size_t signer_len; | |
1258 | 1271 | |
1259 | 1272 | if (!(rdf = _getdns_rdf_iter_init_at(&rdf_spc, &rrsig->rr_i, 7))) |
1260 | 1273 | return; |
1368 | 1381 | rrsig_iter rrsig_spc, *rrsig; |
1369 | 1382 | uint16_t keytag; |
1370 | 1383 | _getdns_rdf_iter rdf_spc, *rdf; |
1371 | uint8_t signer_spc[256], *signer; | |
1384 | uint8_t signer_spc[256]; | |
1385 | const uint8_t *signer; | |
1372 | 1386 | size_t signer_len = sizeof(signer_spc); |
1373 | 1387 | |
1374 | 1388 | assert(dnskey->rr_type == GETDNS_RRTYPE_DNSKEY); |
1383 | 1397 | continue; |
1384 | 1398 | |
1385 | 1399 | /* Then we have at least 4 bytes to calculate keytag */ |
1386 | keytag = gldns_calc_keytag_raw(rr->rr_i.rr_type + 10, | |
1387 | rr->rr_i.nxt - rr->rr_i.rr_type - 10); | |
1400 | keytag = gldns_calc_keytag_raw( | |
1401 | (UNCONST_UINT8_p)rr->rr_i.rr_type + 10, | |
1402 | rr->rr_i.nxt - rr->rr_i.rr_type - 10); | |
1388 | 1403 | |
1389 | 1404 | for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset) |
1390 | 1405 | ; rrsig ; rrsig = rrsig_iter_next(rrsig) ) { |
1456 | 1471 | _getdns_rdf_iter rdf_spc; |
1457 | 1472 | _getdns_rdf_iter *rdf; |
1458 | 1473 | uint8_t cdname[256]; /* Canonical dname */ |
1459 | uint8_t *pos; | |
1474 | const uint8_t *pos; | |
1460 | 1475 | size_t len; |
1461 | 1476 | } canon_rdata_iter; |
1462 | 1477 | |
1466 | 1481 | if ((i->rdf->rdd_pos->type & GETDNS_RDF_N) == GETDNS_RDF_N) { |
1467 | 1482 | i->len = sizeof(i->cdname); |
1468 | 1483 | if ((i->pos = _getdns_rdf_if_or_as_decompressed( |
1469 | i->rdf, i->cdname, &i->len))) | |
1470 | _dname_canonicalize(i->pos); | |
1484 | i->rdf, i->cdname, &i->len))) { | |
1485 | _dname_canonicalize(i->pos, i->cdname); | |
1486 | i->pos = i->cdname; | |
1487 | } | |
1471 | 1488 | } else { |
1472 | 1489 | i->pos = i->rdf->pos; |
1473 | 1490 | i->len = i->rdf->nxt - i->rdf->pos; |
1557 | 1574 | */ |
1558 | 1575 | #define VAL_RRSET_SPC_SZ 1024 |
1559 | 1576 | static int _getdns_verify_rrsig(struct mem_funcs *mf, |
1560 | getdns_rrset *rrset, rrsig_iter *rrsig, rrtype_iter *key, uint8_t **nc_name) | |
1577 | getdns_rrset *rrset, rrsig_iter *rrsig, rrtype_iter *key, const uint8_t **nc_name) | |
1561 | 1578 | { |
1562 | 1579 | int r; |
1563 | 1580 | int to_skip; |
1567 | 1584 | size_t n_rrs, i, valbuf_sz, owner_len; |
1568 | 1585 | _getdns_rdf_iter *signer, signer_spc, *rdf, rdf_spc; |
1569 | 1586 | uint8_t valbuf_spc[4096], *valbuf_buf = valbuf_spc; |
1570 | uint8_t cdname_spc[256], *cdname, owner[256]; | |
1587 | uint8_t cdname_spc[256], owner[256]; | |
1588 | const uint8_t *cdname; | |
1571 | 1589 | size_t cdname_len, pos; |
1572 | 1590 | uint32_t orig_ttl; |
1573 | 1591 | gldns_buffer valbuf; |
1619 | 1637 | gldns_buffer_init_frm_data(&valbuf, valbuf_buf, valbuf_sz); |
1620 | 1638 | gldns_buffer_write(&valbuf, |
1621 | 1639 | rrsig->rr_i.rr_type + 10, signer->nxt - rrsig->rr_i.rr_type - 10); |
1622 | _dname_canonicalize(gldns_buffer_at(&valbuf, 18)); | |
1640 | _dname_canonicalize2(gldns_buffer_at(&valbuf, 18)); | |
1623 | 1641 | |
1624 | 1642 | orig_ttl = gldns_read_uint32(rrsig->rr_i.rr_type + 14); |
1625 | 1643 | |
1626 | 1644 | (void) memcpy(owner, rrset->name, owner_len); |
1627 | _dname_canonicalize(owner); | |
1645 | _dname_canonicalize2(owner); | |
1628 | 1646 | |
1629 | 1647 | if (!_dnssec_rdata_to_canonicalize(rrset->rr_type)) |
1630 | 1648 | for (i = 0; i < n_rrs; i++) { |
1649 | if (i && !_rr_iter_rdata_cmp( | |
1650 | &val_rrset[i], &val_rrset[i-1])) | |
1651 | continue; | |
1652 | ||
1631 | 1653 | gldns_buffer_write(&valbuf, owner, owner_len); |
1632 | 1654 | gldns_buffer_write_u16(&valbuf, rrset->rr_type); |
1633 | 1655 | gldns_buffer_write_u16(&valbuf, rrset->rr_class); |
1636 | 1658 | val_rrset[i].nxt - val_rrset[i].rr_type - 8); |
1637 | 1659 | } |
1638 | 1660 | else for (i = 0; i < n_rrs; i++) { |
1661 | if (i && !_rr_iter_rdata_cmp(&val_rrset[i], &val_rrset[i-1])) | |
1662 | continue; | |
1639 | 1663 | gldns_buffer_write(&valbuf, owner, owner_len); |
1640 | 1664 | gldns_buffer_write_u16(&valbuf, rrset->rr_type); |
1641 | 1665 | gldns_buffer_write_u16(&valbuf, rrset->rr_class); |
1655 | 1679 | rdf, cdname_spc, &cdname_len))) |
1656 | 1680 | continue; |
1657 | 1681 | gldns_buffer_write(&valbuf, cdname, cdname_len); |
1658 | _dname_canonicalize( | |
1682 | _dname_canonicalize2( | |
1659 | 1683 | gldns_buffer_current(&valbuf) - cdname_len); |
1660 | 1684 | } |
1661 | 1685 | gldns_buffer_write_u16_at(&valbuf, pos, |
1663 | 1687 | } |
1664 | 1688 | DEBUG_SEC( "written to valbuf: %zu bytes\n" |
1665 | 1689 | , gldns_buffer_position(&valbuf)); |
1666 | assert(gldns_buffer_position(&valbuf) == valbuf_sz); | |
1667 | ||
1690 | assert(gldns_buffer_position(&valbuf) <= valbuf_sz); | |
1691 | ||
1692 | gldns_buffer_flip(&valbuf); | |
1668 | 1693 | r = _getdns_verify_canonrrset(&valbuf, key->rr_i.rr_type[13], |
1669 | signer->nxt, rrsig->rr_i.nxt - signer->nxt, | |
1670 | key->rr_i.rr_type+14, key->rr_i.nxt - key->rr_i.rr_type-14, | |
1694 | (UNCONST_UINT8_p)signer->nxt, rrsig->rr_i.nxt - signer->nxt, | |
1695 | (UNCONST_UINT8_p)key->rr_i.rr_type+14, | |
1696 | key->rr_i.nxt - key->rr_i.rr_type-14, | |
1671 | 1697 | &reason); |
1672 | 1698 | |
1673 | 1699 | #if defined(SEC_DEBUG) && SEC_DEBUG |
1674 | if (r == 0) | |
1700 | if (r == 0) { | |
1675 | 1701 | DEBUG_SEC("verification failed: %s\n", reason); |
1702 | debug_sec_print_rrset("verification failed: ", rrset); | |
1703 | debug_sec_print_rr("verification failed: ", &rrsig->rr_i); | |
1704 | debug_sec_print_rr("verification failed: ", &key->rr_i); | |
1705 | } | |
1676 | 1706 | #endif |
1677 | 1707 | if (val_rrset != val_rrset_spc) |
1678 | 1708 | GETDNS_FREE(*mf, val_rrset); |
1709 | 1739 | |
1710 | 1740 | /* Calculates NSEC3 hash for name, and stores that into label */ |
1711 | 1741 | static uint8_t *_getdns_nsec3_hash_label(uint8_t *label, size_t label_len, |
1712 | uint8_t *name, uint8_t algorithm, uint16_t iterations, uint8_t *salt) | |
1742 | const uint8_t *name, uint8_t algorithm, | |
1743 | uint16_t iterations, const uint8_t *salt) | |
1713 | 1744 | { |
1714 | 1745 | uint8_t buf[512], *dst, *eob; |
1715 | 1746 | const uint8_t *src; |
1746 | 1777 | } |
1747 | 1778 | |
1748 | 1779 | static uint8_t *name2nsec3_label( |
1749 | getdns_rrset *nsec3, uint8_t *name, uint8_t *label, size_t label_len) | |
1780 | getdns_rrset *nsec3, const uint8_t *name, uint8_t *label, size_t label_len) | |
1750 | 1781 | { |
1751 | 1782 | rrsig_iter rrsig_spc, *rrsig; |
1752 | 1783 | _getdns_rdf_iter rdf_spc, *rdf; |
1753 | uint8_t signer_spc[256], *signer; | |
1784 | uint8_t signer_spc[256]; | |
1785 | const uint8_t *signer; | |
1754 | 1786 | size_t signer_len = sizeof(signer_spc); |
1755 | 1787 | rrtype_iter rr_spc, *rr; |
1756 | 1788 | |
1831 | 1863 | * expansion, nc_name will point to the next closer part of the name in rrset. |
1832 | 1864 | */ |
1833 | 1865 | static int dnskey_signed_rrset(struct mem_funcs *mf, time_t now, uint32_t skew, |
1834 | rrtype_iter *dnskey, getdns_rrset *rrset, uint8_t **nc_name) | |
1866 | rrtype_iter *dnskey, getdns_rrset *rrset, const uint8_t **nc_name) | |
1835 | 1867 | { |
1836 | 1868 | rrsig_iter rrsig_spc, *rrsig; |
1837 | 1869 | _getdns_rdf_iter rdf_spc, *rdf; |
1838 | uint8_t signer_spc[256], *signer; | |
1870 | uint8_t signer_spc[256]; | |
1871 | const uint8_t *signer; | |
1839 | 1872 | size_t signer_len = sizeof(signer_spc); |
1840 | 1873 | uint16_t keytag; |
1841 | 1874 | |
1849 | 1882 | return 0; |
1850 | 1883 | |
1851 | 1884 | /* Then we have at least 4 bytes to calculate keytag */ |
1852 | keytag = gldns_calc_keytag_raw(dnskey->rr_i.rr_type + 10, | |
1885 | keytag = gldns_calc_keytag_raw((UNCONST_UINT8_p)dnskey->rr_i.rr_type + 10, | |
1853 | 1886 | dnskey->rr_i.nxt - dnskey->rr_i.rr_type - 10); |
1854 | 1887 | |
1855 | 1888 | for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset) |
1898 | 1931 | } |
1899 | 1932 | |
1900 | 1933 | static int find_nsec_covering_name( |
1901 | struct mem_funcs *mf, time_t now, uint32_t skew, | |
1902 | getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *name, int *opt_out); | |
1934 | struct mem_funcs *mf, time_t now, uint32_t skew, getdns_rrset *dnskey, | |
1935 | getdns_rrset *rrset, const uint8_t *name, int *opt_out); | |
1903 | 1936 | |
1904 | 1937 | /* Returns whether a dnskey for keyset signed rrset. */ |
1905 | 1938 | static int a_key_signed_rrset(struct mem_funcs *mf, time_t now, uint32_t skew, |
1906 | 1939 | getdns_rrset *keyset, getdns_rrset *rrset) |
1907 | 1940 | { |
1908 | 1941 | rrtype_iter dnskey_spc, *dnskey; |
1909 | uint8_t *nc_name; | |
1942 | const uint8_t *nc_name; | |
1910 | 1943 | int keytag; |
1911 | 1944 | |
1912 | 1945 | assert(keyset->rr_type == GETDNS_RRTYPE_DNSKEY); |
1948 | 1981 | rrtype_iter dnskey_spc, *dnskey; |
1949 | 1982 | rrtype_iter ds_spc, *ds; |
1950 | 1983 | uint16_t keytag; |
1951 | uint8_t *nc_name; | |
1984 | const uint8_t *nc_name; | |
1952 | 1985 | size_t valid_dsses = 0, supported_dsses = 0; |
1953 | 1986 | uint8_t max_supported_digest = 0; |
1954 | 1987 | int max_supported_result = 0; |
1971 | 2004 | return 0; |
1972 | 2005 | |
1973 | 2006 | (void) memcpy(digest_buf_spc, dnskey_set->name, dnskey_owner_len); |
1974 | _dname_canonicalize(digest_buf_spc); | |
2007 | _dname_canonicalize2(digest_buf_spc); | |
1975 | 2008 | |
1976 | 2009 | for ( dnskey = rrtype_iter_init(&dnskey_spc, dnskey_set) |
1977 | 2010 | ; dnskey ; dnskey = rrtype_iter_next(dnskey)) { |
1980 | 2013 | if (dnskey->rr_i.nxt < dnskey->rr_i.rr_type + 14) |
1981 | 2014 | continue; |
1982 | 2015 | |
1983 | keytag = gldns_calc_keytag_raw(dnskey->rr_i.rr_type + 10, | |
1984 | dnskey->rr_i.nxt - dnskey->rr_i.rr_type - 10); | |
2016 | keytag = gldns_calc_keytag_raw( | |
2017 | (UNCONST_UINT8_p) dnskey->rr_i.rr_type + 10, | |
2018 | dnskey->rr_i.nxt - dnskey->rr_i.rr_type - 10); | |
1985 | 2019 | |
1986 | 2020 | for ( ds = rrtype_iter_init(&ds_spc, ds_set) |
1987 | 2021 | ; ds ; ds = rrtype_iter_next(ds)) { |
2104 | 2138 | } |
2105 | 2139 | |
2106 | 2140 | static int nsec_covers_name( |
2107 | getdns_rrset *nsec, uint8_t *name, uint8_t **ce_name) | |
2108 | { | |
2109 | uint8_t owner_spc[256], *owner; | |
2110 | size_t owner_len = sizeof(owner_spc); | |
2111 | uint8_t next_spc[256], *next; | |
2112 | size_t next_len = sizeof(next_spc); | |
2141 | getdns_rrset *nsec, const uint8_t *name, const uint8_t **ce_name) | |
2142 | { | |
2143 | uint8_t owner_spc[256], next_spc[256]; | |
2144 | const uint8_t *owner, *next; | |
2145 | size_t owner_len = sizeof(owner_spc), next_len = sizeof(next_spc); | |
2146 | ||
2113 | 2147 | rrtype_iter rr_spc, *rr; |
2114 | 2148 | _getdns_rdf_iter rdf_spc, *rdf; |
2115 | 2149 | int nsec_cmp; |
2116 | uint8_t *common1, *common2; | |
2150 | const uint8_t *common1, *common2; | |
2117 | 2151 | |
2118 | 2152 | if (/* Get owner and next, nicely decompressed */ |
2119 | 2153 | !(rr = rrtype_iter_init(&rr_spc, nsec)) |
2162 | 2196 | } |
2163 | 2197 | } |
2164 | 2198 | |
2165 | static int nsec3_matches_name(getdns_rrset *nsec3, uint8_t *name) | |
2199 | static int nsec3_matches_name(getdns_rrset *nsec3, const uint8_t *name) | |
2166 | 2200 | { |
2167 | 2201 | uint8_t label[64], owner[64]; |
2168 | 2202 | |
2175 | 2209 | return 0; |
2176 | 2210 | } |
2177 | 2211 | |
2178 | static int nsec3_covers_name(getdns_rrset *nsec3, uint8_t *name, int *opt_out) | |
2212 | static int nsec3_covers_name( | |
2213 | getdns_rrset *nsec3, const uint8_t *name, int *opt_out) | |
2179 | 2214 | { |
2180 | 2215 | uint8_t label[65], next[65], owner[65]; |
2181 | 2216 | rrtype_iter rr_spc, *rr; |
2226 | 2261 | } |
2227 | 2262 | |
2228 | 2263 | static int find_nsec_covering_name( |
2229 | struct mem_funcs *mf, time_t now, uint32_t skew, | |
2230 | getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *name, int *opt_out) | |
2264 | struct mem_funcs *mf, time_t now, uint32_t skew, getdns_rrset *dnskey, | |
2265 | getdns_rrset *rrset, const uint8_t *name, int *opt_out) | |
2231 | 2266 | { |
2232 | 2267 | rrset_iter i_spc, *i; |
2233 | 2268 | getdns_rrset *n; |
2324 | 2359 | |
2325 | 2360 | static int nsec3_find_next_closer( |
2326 | 2361 | struct mem_funcs *mf, time_t now, uint32_t skew, |
2327 | getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *nc_name, int *opt_out) | |
2362 | getdns_rrset *dnskey, getdns_rrset *rrset, | |
2363 | const uint8_t *nc_name, int *opt_out) | |
2328 | 2364 | { |
2329 | 2365 | uint8_t wc_name[256] = { 1, (uint8_t)'*' }; |
2330 | 2366 | int my_opt_out, keytag; |
2381 | 2417 | rrtype_iter nsec_spc, *nsec_rr; |
2382 | 2418 | _getdns_rdf_iter bitmap_spc, *bitmap; |
2383 | 2419 | rrset_iter i_spc, *i; |
2384 | uint8_t *ce_name, *nc_name; | |
2420 | const uint8_t *ce_name, *nc_name; | |
2385 | 2421 | uint8_t wc_name[256] = { 1, (uint8_t)'*' }; |
2386 | 2422 | int keytag; |
2387 | 2423 | |
2765 | 2801 | |
2766 | 2802 | if ((s = chain_node_get_trusted_keys( |
2767 | 2803 | mf, now, skew, head->parent, ta, &keys)) != GETDNS_DNSSEC_SECURE) |
2768 | return s; | |
2804 | return s; | |
2769 | 2805 | |
2770 | 2806 | if (rrset_has_rrs(&head->rrset)) { |
2771 | 2807 | if ((keytag = a_key_signed_rrset( |
2979 | 3015 | return count + count_outstanding_requests(head->next); |
2980 | 3016 | } |
2981 | 3017 | |
3018 | static int rrset_in_list(getdns_rrset *rrset, getdns_list *list) | |
3019 | { | |
3020 | size_t i; | |
3021 | getdns_dict *rr_dict; | |
3022 | uint32_t rr_type; | |
3023 | uint32_t rr_class; | |
3024 | getdns_bindata *name; | |
3025 | ||
3026 | for (i = 0; !getdns_list_get_dict(list, i, &rr_dict); i++) { | |
3027 | if (!getdns_dict_get_int(rr_dict, "type", &rr_type) && | |
3028 | rrset->rr_type == rr_type && | |
3029 | !getdns_dict_get_int(rr_dict, "class", &rr_class) && | |
3030 | rrset->rr_class == rr_class && | |
3031 | !getdns_dict_get_bindata(rr_dict, "name", &name) && | |
3032 | dname_compare(rrset->name, name->data) == 0) | |
3033 | return 1; | |
3034 | } | |
3035 | return 0; | |
3036 | } | |
3037 | ||
2982 | 3038 | static void append_rrs2val_chain_list(getdns_context *ctxt, |
2983 | 3039 | getdns_list *val_chain_list, getdns_network_req *netreq, int signer) |
2984 | 3040 | { |
2994 | 3050 | |
2995 | 3051 | rrset = rrset_iter_value(i); |
2996 | 3052 | |
2997 | if (rrset->rr_type != GETDNS_RRTYPE_DNSKEY && | |
2998 | rrset->rr_type != GETDNS_RRTYPE_DS && | |
2999 | rrset->rr_type != GETDNS_RRTYPE_NSEC && | |
3000 | rrset->rr_type != GETDNS_RRTYPE_NSEC3) | |
3053 | if (rrset->rr_type == GETDNS_RRTYPE_NSEC || | |
3054 | rrset->rr_type == GETDNS_RRTYPE_NSEC3) { | |
3055 | ||
3056 | if (rrset_in_list(rrset, val_chain_list)) | |
3057 | continue; | |
3058 | ||
3059 | } else if (rrset->rr_type != GETDNS_RRTYPE_DNSKEY && | |
3060 | rrset->rr_type != GETDNS_RRTYPE_DS) | |
3001 | 3061 | continue; |
3002 | 3062 | |
3003 | 3063 | for ( rr = rrtype_iter_init(&rr_spc, rrset) |
3043 | 3103 | return; |
3044 | 3104 | |
3045 | 3105 | bindata.size = _dname_len(ds->name); |
3046 | bindata.data = ds->name; | |
3106 | bindata.data = (UNCONST_UINT8_p)ds->name; | |
3047 | 3107 | (void) getdns_dict_set_bindata(rr_dict, "name", &bindata); |
3048 | 3108 | (void) getdns_dict_set_int(rr_dict, "class", ds->rr_class); |
3049 | 3109 | (void) getdns_dict_set_int(rr_dict, "type", ds->rr_type); |
3201 | 3261 | , netreq->response, netreq->response_len |
3202 | 3262 | , netreq->owner->name |
3203 | 3263 | , netreq->request_type |
3204 | , netreq->request_class | |
3264 | , netreq->owner->request_class | |
3205 | 3265 | , netreq |
3206 | 3266 | ); |
3207 | 3267 | } |
3224 | 3284 | chain_head *chain, *head, *next_head; |
3225 | 3285 | chain_node *node; |
3226 | 3286 | |
3227 | uint8_t qname_spc[256], *qname = NULL; | |
3287 | uint8_t qname_spc[256]; | |
3288 | const uint8_t *qname = NULL; | |
3228 | 3289 | size_t qname_len = sizeof(qname_spc); |
3229 | 3290 | uint16_t qtype = 0, qclass = GETDNS_RRCLASS_IN; |
3230 | 3291 |
30 | 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | 31 | */ |
32 | 32 | |
33 | #include "config.h" | |
34 | #include "types-internal.h" | |
33 | 35 | #include "getdns/getdns_ext_libev.h" |
34 | #include "types-internal.h" | |
35 | #include "config.h" | |
36 | 36 | |
37 | 37 | #ifdef HAVE_LIBEV_EV_H |
38 | 38 | #include <libev/ev.h> |
30 | 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | 31 | */ |
32 | 32 | |
33 | #include "config.h" | |
34 | #include "types-internal.h" | |
33 | 35 | #include <sys/time.h> |
34 | 36 | #include "getdns/getdns_ext_libevent.h" |
35 | #include "types-internal.h" | |
36 | #include "config.h" | |
37 | 37 | |
38 | 38 | #ifdef HAVE_EVENT2_EVENT_H |
39 | 39 | # include <event2/event.h> |
31 | 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | 32 | */ |
33 | 33 | |
34 | #include "config.h" | |
35 | #include "debug.h" | |
36 | #include "types-internal.h" | |
34 | 37 | #include "extension/libmini_event.h" |
35 | #include "context.h" | |
36 | #include "util-internal.h" | |
37 | 38 | #if defined(SCHED_DEBUG) && SCHED_DEBUG |
38 | 39 | #include <inttypes.h> |
39 | 40 | #endif |
204 | 205 | if (!ext) |
205 | 206 | return GETDNS_RETURN_INVALID_PARAMETER; |
206 | 207 | |
208 | #ifdef USE_WINSOCK | |
209 | int r; | |
210 | WSADATA wsa_data; | |
211 | ||
212 | if ((r = WSAStartup(MAKEWORD(2, 2), &wsa_data)) != 0) { | |
213 | printf("could not init winsock. WSAStartup: %s", | |
214 | wsa_strerror(r)); | |
215 | return GETDNS_RETURN_GENERIC_ERROR; | |
216 | } | |
217 | #endif | |
218 | ||
207 | 219 | ext->n_events = 0; |
208 | 220 | ext->loop.vmt = &_getdns_mini_event_vmt; |
209 | 221 | ext->base = _getdns_event_init(&ext->time_secs, &ext->time_tv); |
210 | 222 | if (!ext->base) |
211 | 223 | return GETDNS_RETURN_MEMORY_ERROR; |
212 | 224 | |
213 | ext->mf = context->mf; | |
225 | ext->mf = *priv_getdns_context_mf(context); | |
214 | 226 | return GETDNS_RETURN_GOOD; |
215 | 227 | } |
216 | 228 | |
220 | 232 | if (!context) return GETDNS_RETURN_BAD_CONTEXT; |
221 | 233 | if (!ext) return GETDNS_RETURN_INVALID_PARAMETER; |
222 | 234 | |
223 | *ext = GETDNS_MALLOC(context->mf, _getdns_mini_event); | |
235 | *ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), _getdns_mini_event); | |
224 | 236 | return _getdns_mini_event_init(context, *ext); |
225 | 237 | } |
34 | 34 | #define _GETDNS_LIBMINI_EVENT_H_ |
35 | 35 | |
36 | 36 | #include "config.h" |
37 | #ifndef USE_WINSOCK | |
37 | 38 | #include "util/mini_event.h" |
39 | #else | |
40 | #include "util/winsock_event.h" | |
41 | #endif | |
38 | 42 | #include "types-internal.h" |
39 | 43 | |
40 | 44 | typedef struct _getdns_mini_event { |
31 | 31 | */ |
32 | 32 | |
33 | 33 | #include "config.h" |
34 | #include "debug.h" | |
35 | #include "types-internal.h" | |
34 | 36 | #include <uv.h> |
35 | 37 | #include "getdns/getdns_ext_libuv.h" |
36 | #include "util-internal.h" | |
37 | 38 | |
38 | 39 | #define UV_DEBUG 0 |
39 | 40 |
43 | 43 | #include "util-internal.h" |
44 | 44 | #include "dnssec.h" |
45 | 45 | #include "stub.h" |
46 | #include "general.h" | |
46 | 47 | |
47 | 48 | /* cancel, cleanup and send timeout to callback */ |
48 | 49 | static void |
69 | 70 | (response ? GETDNS_CALLBACK_COMPLETE : GETDNS_CALLBACK_ERROR), |
70 | 71 | response, user_arg, trans_id); |
71 | 72 | context->processing = 0; |
73 | } | |
74 | ||
75 | static int | |
76 | no_answer(getdns_dns_req *dns_req) | |
77 | { | |
78 | getdns_network_req **netreq_p, *netreq; | |
79 | int new_canonical = 0; | |
80 | uint8_t canon_spc[256]; | |
81 | const uint8_t *canon; | |
82 | size_t canon_len; | |
83 | uint8_t owner_spc[256]; | |
84 | const uint8_t *owner; | |
85 | size_t owner_len; | |
86 | ||
87 | _getdns_rr_iter rr_spc, *rr; | |
88 | _getdns_rdf_iter rdf_spc, *rdf; | |
89 | ||
90 | for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) { | |
91 | if (netreq->response_len == 0 || | |
92 | GLDNS_ANCOUNT(netreq->response) == 0) | |
93 | continue; | |
94 | canon = netreq->owner->name; | |
95 | canon_len = netreq->owner->name_len; | |
96 | if (netreq->request_type != GETDNS_RRTYPE_CNAME | |
97 | && GLDNS_ANCOUNT(netreq->response) > 1) do { | |
98 | new_canonical = 0; | |
99 | for ( rr = _getdns_rr_iter_init(&rr_spc | |
100 | , netreq->response | |
101 | , netreq->response_len) | |
102 | ; rr && _getdns_rr_iter_section(rr) | |
103 | <= GLDNS_SECTION_ANSWER | |
104 | ; rr = _getdns_rr_iter_next(rr)) { | |
105 | ||
106 | if (_getdns_rr_iter_section(rr) != | |
107 | GLDNS_SECTION_ANSWER) | |
108 | continue; | |
109 | ||
110 | if (gldns_read_uint16(rr->rr_type) != | |
111 | GETDNS_RRTYPE_CNAME) | |
112 | continue; | |
113 | ||
114 | owner = _getdns_owner_if_or_as_decompressed( | |
115 | rr, owner_spc, &owner_len); | |
116 | if (!_getdns_dname_equal(canon, owner)) | |
117 | continue; | |
118 | ||
119 | if (!(rdf = _getdns_rdf_iter_init( | |
120 | &rdf_spc, rr))) | |
121 | continue; | |
122 | ||
123 | canon = _getdns_rdf_if_or_as_decompressed( | |
124 | rdf, canon_spc, &canon_len); | |
125 | new_canonical = 1; | |
126 | } | |
127 | } while (new_canonical); | |
128 | for ( rr = _getdns_rr_iter_init(&rr_spc | |
129 | , netreq->response | |
130 | , netreq->response_len) | |
131 | ; rr && _getdns_rr_iter_section(rr) | |
132 | <= GLDNS_SECTION_ANSWER | |
133 | ; rr = _getdns_rr_iter_next(rr)) { | |
134 | ||
135 | if (_getdns_rr_iter_section(rr) != | |
136 | GLDNS_SECTION_ANSWER) | |
137 | continue; | |
138 | ||
139 | if (gldns_read_uint16(rr->rr_type) != | |
140 | netreq->request_type) | |
141 | continue; | |
142 | ||
143 | owner = _getdns_owner_if_or_as_decompressed( | |
144 | rr, owner_spc, &owner_len); | |
145 | if (_getdns_dname_equal(canon, owner)) | |
146 | return 0; | |
147 | } | |
148 | } | |
149 | return 1; | |
72 | 150 | } |
73 | 151 | |
74 | 152 | void |
84 | 162 | else if (netreq->response_len > 0) |
85 | 163 | results_found = 1; |
86 | 164 | |
165 | /* Do we have to check more suffixes on nxdomain/nodata? | |
166 | */ | |
167 | if (dns_req->suffix_appended && /* Something was appended */ | |
168 | dns_req->suffix_len > 1 && /* Next suffix available */ | |
169 | no_answer(dns_req)) { | |
170 | /* Remove suffix from name */ | |
171 | dns_req->name_len -= dns_req->suffix_len - 1; | |
172 | dns_req->name[dns_req->name_len - 1] = 0; | |
173 | do { | |
174 | dns_req->suffix += dns_req->suffix_len; | |
175 | dns_req->suffix_len = *dns_req->suffix++; | |
176 | if (dns_req->suffix_len + dns_req->name_len - 1 < | |
177 | sizeof(dns_req->name)) { | |
178 | memcpy(dns_req->name + dns_req->name_len - 1, | |
179 | dns_req->suffix, dns_req->suffix_len); | |
180 | dns_req->name_len += dns_req->suffix_len - 1; | |
181 | dns_req->suffix_appended = 1; | |
182 | break; | |
183 | } | |
184 | } while (dns_req->suffix_len > 1 && *dns_req->suffix); | |
185 | if (dns_req->append_name == GETDNS_APPEND_NAME_ALWAYS || | |
186 | (dns_req->suffix_len > 1 && *dns_req->suffix)) { | |
187 | for ( netreq_p = dns_req->netreqs | |
188 | ; (netreq = *netreq_p) | |
189 | ; netreq_p++ ) { | |
190 | _getdns_netreq_reinit(netreq); | |
191 | if (_getdns_submit_netreq(netreq)) | |
192 | netreq->state = NET_REQ_FINISHED; | |
193 | } | |
194 | _getdns_check_dns_req_complete(dns_req); | |
195 | return; | |
196 | } | |
197 | } else if ( | |
198 | ( dns_req->append_name == | |
199 | GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE || | |
200 | dns_req->append_name == | |
201 | GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE | |
202 | ) && | |
203 | !dns_req->suffix_appended && | |
204 | dns_req->suffix_len > 1 && | |
205 | no_answer(dns_req)) { | |
206 | /* Initial suffix append */ | |
207 | for ( | |
208 | ; dns_req->suffix_len > 1 && *dns_req->suffix | |
209 | ; dns_req->suffix += dns_req->suffix_len | |
210 | , dns_req->suffix_len = *dns_req->suffix++) { | |
211 | ||
212 | if (dns_req->suffix_len + dns_req->name_len - 1 < | |
213 | sizeof(dns_req->name)) { | |
214 | memcpy(dns_req->name + dns_req->name_len - 1, | |
215 | dns_req->suffix, dns_req->suffix_len); | |
216 | dns_req->name_len += dns_req->suffix_len - 1; | |
217 | dns_req->suffix_appended = 1; | |
218 | break; | |
219 | } | |
220 | } | |
221 | if (dns_req->suffix_appended) { | |
222 | for ( netreq_p = dns_req->netreqs | |
223 | ; (netreq = *netreq_p) | |
224 | ; netreq_p++ ) { | |
225 | _getdns_netreq_reinit(netreq); | |
226 | if (_getdns_submit_netreq(netreq)) | |
227 | netreq->state = NET_REQ_FINISHED; | |
228 | } | |
229 | _getdns_check_dns_req_complete(dns_req); | |
230 | return; | |
231 | } | |
232 | } | |
87 | 233 | if (dns_req->internal_cb) |
88 | 234 | dns_req->internal_cb(dns_req); |
89 | 235 | else if (! results_found) |
172 | 318 | |
173 | 319 | #ifdef HAVE_LIBUNBOUND |
174 | 320 | return ub_resolve_async(dns_req->context->unbound_ctx, |
175 | name, netreq->request_type, netreq->request_class, | |
321 | name, netreq->request_type, netreq->owner->request_class, | |
176 | 322 | netreq, ub_resolve_callback, &(netreq->unbound_id)) ? |
177 | 323 | GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD; |
178 | 324 | #else |
345 | 491 | switch (address_data->size) { |
346 | 492 | case 4: |
347 | 493 | (void)snprintf(name, sizeof(name), |
348 | "%hhu.%hhu.%hhu.%hhu.in-addr.arpa.", | |
349 | ((uint8_t *)address_data->data)[3], | |
350 | ((uint8_t *)address_data->data)[2], | |
351 | ((uint8_t *)address_data->data)[1], | |
352 | ((uint8_t *)address_data->data)[0]); | |
494 | "%d.%d.%d.%d.in-addr.arpa.", | |
495 | (int)((uint8_t *)address_data->data)[3], | |
496 | (int)((uint8_t *)address_data->data)[2], | |
497 | (int)((uint8_t *)address_data->data)[1], | |
498 | (int)((uint8_t *)address_data->data)[0]); | |
353 | 499 | break; |
354 | 500 | case 16: |
355 | 501 | (void)snprintf(name, sizeof(name), |
356 | "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." | |
357 | "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." | |
358 | "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx." | |
359 | "%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.ip6.arpa.", | |
360 | (uint8_t)(((uint8_t *)address_data->data)[15] & 0x0F), | |
361 | (uint8_t)(((uint8_t *)address_data->data)[15] >> 4), | |
362 | (uint8_t)(((uint8_t *)address_data->data)[14] & 0x0F), | |
363 | (uint8_t)(((uint8_t *)address_data->data)[14] >> 4), | |
364 | (uint8_t)(((uint8_t *)address_data->data)[13] & 0x0F), | |
365 | (uint8_t)(((uint8_t *)address_data->data)[13] >> 4), | |
366 | (uint8_t)(((uint8_t *)address_data->data)[12] & 0x0F), | |
367 | (uint8_t)(((uint8_t *)address_data->data)[12] >> 4), | |
368 | (uint8_t)(((uint8_t *)address_data->data)[11] & 0x0F), | |
369 | (uint8_t)(((uint8_t *)address_data->data)[11] >> 4), | |
370 | (uint8_t)(((uint8_t *)address_data->data)[10] & 0x0F), | |
371 | (uint8_t)(((uint8_t *)address_data->data)[10] >> 4), | |
372 | (uint8_t)(((uint8_t *)address_data->data)[9] & 0x0F), | |
373 | (uint8_t)(((uint8_t *)address_data->data)[9] >> 4), | |
374 | (uint8_t)(((uint8_t *)address_data->data)[8] & 0x0F), | |
375 | (uint8_t)(((uint8_t *)address_data->data)[8] >> 4), | |
376 | (uint8_t)(((uint8_t *)address_data->data)[7] & 0x0F), | |
377 | (uint8_t)(((uint8_t *)address_data->data)[7] >> 4), | |
378 | (uint8_t)(((uint8_t *)address_data->data)[6] & 0x0F), | |
379 | (uint8_t)(((uint8_t *)address_data->data)[6] >> 4), | |
380 | (uint8_t)(((uint8_t *)address_data->data)[5] & 0x0F), | |
381 | (uint8_t)(((uint8_t *)address_data->data)[5] >> 4), | |
382 | (uint8_t)(((uint8_t *)address_data->data)[4] & 0x0F), | |
383 | (uint8_t)(((uint8_t *)address_data->data)[4] >> 4), | |
384 | (uint8_t)(((uint8_t *)address_data->data)[3] & 0x0F), | |
385 | (uint8_t)(((uint8_t *)address_data->data)[3] >> 4), | |
386 | (uint8_t)(((uint8_t *)address_data->data)[2] & 0x0F), | |
387 | (uint8_t)(((uint8_t *)address_data->data)[2] >> 4), | |
388 | (uint8_t)(((uint8_t *)address_data->data)[1] & 0x0F), | |
389 | (uint8_t)(((uint8_t *)address_data->data)[1] >> 4), | |
390 | (uint8_t)(((uint8_t *)address_data->data)[0] & 0x0F), | |
391 | (uint8_t)(((uint8_t *)address_data->data)[0] >> 4)); | |
502 | "%x.%x.%x.%x.%x.%x.%x.%x." | |
503 | "%x.%x.%x.%x.%x.%x.%x.%x." | |
504 | "%x.%x.%x.%x.%x.%x.%x.%x." | |
505 | "%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.", | |
506 | (int)(((uint8_t *)address_data->data)[15] & 0x0F), | |
507 | (int)(((uint8_t *)address_data->data)[15] >> 4), | |
508 | (int)(((uint8_t *)address_data->data)[14] & 0x0F), | |
509 | (int)(((uint8_t *)address_data->data)[14] >> 4), | |
510 | (int)(((uint8_t *)address_data->data)[13] & 0x0F), | |
511 | (int)(((uint8_t *)address_data->data)[13] >> 4), | |
512 | (int)(((uint8_t *)address_data->data)[12] & 0x0F), | |
513 | (int)(((uint8_t *)address_data->data)[12] >> 4), | |
514 | (int)(((uint8_t *)address_data->data)[11] & 0x0F), | |
515 | (int)(((uint8_t *)address_data->data)[11] >> 4), | |
516 | (int)(((uint8_t *)address_data->data)[10] & 0x0F), | |
517 | (int)(((uint8_t *)address_data->data)[10] >> 4), | |
518 | (int)(((uint8_t *)address_data->data)[9] & 0x0F), | |
519 | (int)(((uint8_t *)address_data->data)[9] >> 4), | |
520 | (int)(((uint8_t *)address_data->data)[8] & 0x0F), | |
521 | (int)(((uint8_t *)address_data->data)[8] >> 4), | |
522 | (int)(((uint8_t *)address_data->data)[7] & 0x0F), | |
523 | (int)(((uint8_t *)address_data->data)[7] >> 4), | |
524 | (int)(((uint8_t *)address_data->data)[6] & 0x0F), | |
525 | (int)(((uint8_t *)address_data->data)[6] >> 4), | |
526 | (int)(((uint8_t *)address_data->data)[5] & 0x0F), | |
527 | (int)(((uint8_t *)address_data->data)[5] >> 4), | |
528 | (int)(((uint8_t *)address_data->data)[4] & 0x0F), | |
529 | (int)(((uint8_t *)address_data->data)[4] >> 4), | |
530 | (int)(((uint8_t *)address_data->data)[3] & 0x0F), | |
531 | (int)(((uint8_t *)address_data->data)[3] >> 4), | |
532 | (int)(((uint8_t *)address_data->data)[2] & 0x0F), | |
533 | (int)(((uint8_t *)address_data->data)[2] >> 4), | |
534 | (int)(((uint8_t *)address_data->data)[1] & 0x0F), | |
535 | (int)(((uint8_t *)address_data->data)[1] >> 4), | |
536 | (int)(((uint8_t *)address_data->data)[0] & 0x0F), | |
537 | (int)(((uint8_t *)address_data->data)[0] >> 4)); | |
392 | 538 | break; |
393 | 539 | default: |
394 | 540 | return GETDNS_RETURN_INVALID_PARAMETER; |
184 | 184 | GETDNS_TRANSPORT_UDP = 1200, |
185 | 185 | GETDNS_TRANSPORT_TCP = 1201, |
186 | 186 | GETDNS_TRANSPORT_TLS = 1202, |
187 | GETDNS_TRANSPORT_STARTTLS = 1203 | |
188 | 187 | } getdns_transport_list_t; |
189 | 188 | |
190 | 189 | /** |
194 | 193 | #define GETDNS_TRANSPORT_UDP_TEXT "See getdns_context_set_dns_transport_list()" |
195 | 194 | #define GETDNS_TRANSPORT_TCP_TEXT "See getdns_context_set_dns_transport_list()" |
196 | 195 | #define GETDNS_TRANSPORT_TLS_TEXT "See getdns_context_set_dns_transport_list()" |
197 | #define GETDNS_TRANSPORT_STARTTLS_TEXT "See getdns_context_set_dns_transport_list()" | |
198 | 196 | /** @} |
199 | 197 | */ |
200 | 198 |
29 | 29 | |
30 | 30 | #include <getdns/getdns.h> |
31 | 31 | #include <sys/time.h> |
32 | #include <stdio.h> | |
32 | 33 | |
33 | 34 | #ifdef __cplusplus |
34 | 35 | extern "C" { |
340 | 341 | */ |
341 | 342 | const char *getdns_get_errorstr_by_id(uint16_t err); |
342 | 343 | |
343 | ||
344 | ||
345 | ||
346 | /** | |
347 | * Public Key Pinning functionality: | |
348 | * | |
349 | * a public key pinset is a list of dicts. each dict should have a | |
350 | * "digest" and a "value". | |
351 | * | |
352 | * "digest": a string indicating the type of digest. at the moment, we | |
353 | * only support a "digest" of "sha256". | |
354 | * | |
355 | * "value": a binary representation of the digest provided. | |
356 | * | |
357 | * given a such a pinset, we should be able to validate a chain | |
358 | * properly according to section 2.6 of RFC 7469. | |
359 | */ | |
360 | ||
361 | /** | |
362 | * convert an HPKP-style pin description to an appropriate getdns data | |
363 | * structure. An example string is: (with the quotes, without any | |
364 | * leading or trailing whitespace): | |
365 | * | |
366 | * pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" | |
367 | * | |
368 | * It is the caller's responsibility to call getdns_dict_destroy() on | |
369 | * the dict returned when it is no longer needed. | |
370 | * | |
371 | * @param context a context to use to create the dict, or NULL to create | |
372 | * it generically | |
373 | * @param str the pinning string to parse | |
374 | * @return a dict created from ctx, or NULL if the string did not match. | |
375 | */ | |
376 | getdns_dict* getdns_pubkey_pin_create_from_string( | |
377 | getdns_context* context, | |
378 | const char* str); | |
379 | ||
380 | ||
381 | /** | |
382 | * Test whether a given pinset is reasonable, including: | |
383 | * | |
384 | * is it well-formed? | |
385 | * are there at least two pins? | |
386 | * are the digests used sane? | |
387 | * | |
388 | * @param pinset the set of public key pins to check for sanity. This | |
389 | * should be a list of dicts. | |
390 | * @return errorlist if not NULL, a list of human-readable strings is | |
391 | * appended to errorlist. | |
392 | * @return GETDNS_RETURN_GOOD if the pinset passes the sanity check. | |
393 | */ | |
394 | getdns_return_t getdns_pubkey_pinset_sanity_check( | |
395 | const getdns_list* pinset, | |
396 | getdns_list* errorlist); | |
397 | ||
398 | ||
399 | ||
344 | 400 | /* WARNING! Function getdns_strerror is not in the API specification and |
345 | 401 | * is likely to be removed from future versions of our implementation, to be |
346 | 402 | * replaced by getdns_get_errorstr_by_id or something similar. |
348 | 404 | */ |
349 | 405 | getdns_return_t getdns_strerror(getdns_return_t err, char *buf, size_t buflen); |
350 | 406 | |
351 | #define GETDNS_VERSION "0.5.1" | |
352 | #define GETDNS_NUMERIC_VERSION 0x00050100 | |
353 | #define GETDNS_API_VERSION "October 2015" | |
354 | #define GETDNS_API_NUMERIC_VERSION 0x07df0a00 | |
407 | #define GETDNS_VERSION "0.9.0" | |
408 | #define GETDNS_NUMERIC_VERSION 0x00090000 | |
409 | #define GETDNS_API_VERSION "December 2015" | |
410 | #define GETDNS_API_NUMERIC_VERSION 0x07df0c00 | |
355 | 411 | |
356 | 412 | const char *getdns_get_version(void); |
357 | 413 | uint32_t getdns_get_version_number(void); |
361 | 417 | /* Authentication options used when doing TLS */ |
362 | 418 | typedef enum getdns_tls_authentication_t { |
363 | 419 | GETDNS_AUTHENTICATION_NONE = 1300, |
364 | GETDNS_AUTHENTICATION_HOSTNAME = 1301, | |
420 | GETDNS_AUTHENTICATION_REQUIRED = 1301 | |
365 | 421 | } getdns_tls_authentication_t; |
422 | ||
423 | /* an alias for REQUIRED */ | |
424 | #define GETDNS_AUTHENTICATION_HOSTNAME GETDNS_AUTHENTICATION_REQUIRED | |
366 | 425 | |
367 | 426 | /** |
368 | 427 | * \defgroup Base authentication texts |
369 | 428 | * @{ |
370 | 429 | */ |
371 | 430 | #define GETDNS_AUTHENTICATION_NONE_TEXT "See getdns_context_set_tls_authentication()" |
372 | #define GETDNS_AUTHENTICATION_HOSTNAME_TEXT "See getdns_context_set_tls_authentication()" | |
431 | #define GETDNS_AUTHENTICATION_REQUIRED_TEXT "See getdns_context_set_tls_authentication()" | |
373 | 432 | /** @} |
374 | 433 | */ |
375 | 434 | |
379 | 438 | #define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private" |
380 | 439 | #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE 620 |
381 | 440 | #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize" |
441 | #define GETDNS_CONTEXT_CODE_PUBKEY_PINSET 621 | |
442 | #define GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT "Change related to getdns_context_set_pubkey_pinset" | |
382 | 443 | |
383 | 444 | getdns_return_t |
384 | 445 | getdns_context_set_tls_authentication( |
398 | 459 | #define GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" |
399 | 460 | #define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN 545 |
400 | 461 | #define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" |
401 | #define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN 546 | |
402 | #define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" | |
462 | ||
463 | #define GETDNS_RETURN_NEED_MORE_SPACE ((getdns_return_t) 399 ) | |
464 | #define GETDNS_RETURN_NEED_MORE_SPACE_TEXT "The buffer was too small" | |
465 | ||
466 | /** | |
467 | * Convert rr_dict to wireformat representation of the resource record. | |
468 | * | |
469 | * @param rr_dict The getdns dict representation of the resource record | |
470 | * @return wire A newly allocated buffer which will contain the wireformat. | |
471 | * @return wire_sz The size of the allocated buffer and the wireformat. | |
472 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
473 | */ | |
474 | getdns_return_t | |
475 | getdns_rr_dict2wire( | |
476 | const getdns_dict *rr_dict, uint8_t **wire, size_t *wire_sz); | |
477 | ||
478 | /** | |
479 | * Convert rr_dict to wireformat representation of the resource record. | |
480 | * | |
481 | * @param rr_dict The getdns dict representation of the resource record | |
482 | * @param wire The buffer in which the wireformat will be written | |
483 | * @param wire_sz On input the size of the wire buffer, | |
484 | * On output the amount of wireformat needed for the | |
485 | * wireformat representation of the resource record; | |
486 | * even if it did not fit. | |
487 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
488 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
489 | * small. wire_sz will be set to the needed buffer space then. | |
490 | */ | |
491 | getdns_return_t | |
492 | getdns_rr_dict2wire_buf( | |
493 | const getdns_dict *rr_dict, uint8_t *wire, size_t *wire_sz); | |
494 | ||
495 | /** | |
496 | * Convert rr_dict to wireformat representation of the resource record. | |
497 | * | |
498 | * @param rr_dict The getdns dict representation of the resource record | |
499 | * @param wire A pointer to the buffer pointer in which the wireformat | |
500 | * will be written. | |
501 | * On output the buffer pointer will have moved along | |
502 | * the buffer and point right after the just written RR. | |
503 | * @param wire_sz On input the size of the wire buffer, | |
504 | * On output the amount of wireformat needed for the | |
505 | * wireformat will have been substracted from wire_sz. | |
506 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
507 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
508 | * small. The function will pretend that it had written beyond the end | |
509 | * of the buffer, and wire will point past the buffer and wire_sz will | |
510 | * contain a negative value. | |
511 | */ | |
512 | getdns_return_t | |
513 | getdns_rr_dict2wire_scan( | |
514 | const getdns_dict *rr_dict, uint8_t **wire, int *wire_sz); | |
515 | ||
516 | ||
517 | /** | |
518 | * Convert wireformat resource record in a getdns rr_dict representation. | |
519 | * | |
520 | * @param wire Buffer containing the wireformat rr | |
521 | * @param wire_sz Size of the wire buffer | |
522 | * @return rr_dict The returned rr_dict | |
523 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
524 | */ | |
525 | getdns_return_t | |
526 | getdns_wire2rr_dict( | |
527 | const uint8_t *wire, size_t wire_sz, getdns_dict **rr_dict); | |
528 | ||
529 | /** | |
530 | * Convert wireformat resource record in a getdns rr_dict representation. | |
531 | * | |
532 | * @param wire Buffer containing the wireformat rr | |
533 | * @param wire_sz On input the size of the wire buffer | |
534 | * On output the length of the wireformat rr. | |
535 | * @return rr_dict The returned rr_dict | |
536 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
537 | */ | |
538 | getdns_return_t | |
539 | getdns_wire2rr_dict_buf( | |
540 | const uint8_t *wire, size_t *wire_sz, getdns_dict **rr_dict); | |
541 | ||
542 | /** | |
543 | * Convert wireformat resource record in a getdns rr_dict representation. | |
544 | * | |
545 | * @param wire A pointer to the pointer of the wireformat buffer. | |
546 | * On return this pointer is moved to after first read | |
547 | * in resource record. | |
548 | * @param wire_sz On input the size of the wire buffer | |
549 | * On output the size is decreased with the length | |
550 | * of the wireformat resource record. | |
551 | * @return rr_dict The returned rr_dict | |
552 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
553 | */ | |
554 | getdns_return_t | |
555 | getdns_wire2rr_dict_scan( | |
556 | const uint8_t **wire, size_t *wire_sz, getdns_dict **rr_dict); | |
557 | ||
558 | ||
559 | /** | |
560 | * Convert rr_dict to the string representation of the resource record. | |
561 | * | |
562 | * @param rr_dict The getdns dict representation of the resource record | |
563 | * @return str A newly allocated string representation of the rr | |
564 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
565 | */ | |
566 | getdns_return_t | |
567 | getdns_rr_dict2str( | |
568 | const getdns_dict *rr_dict, char **str); | |
569 | ||
570 | /** | |
571 | * Convert rr_dict to the string representation of the resource record. | |
572 | * | |
573 | * @param rr_dict The getdns dict representation of the resource record | |
574 | * @param str The buffer in which the string will be written | |
575 | * @param str_len On input the size of the text buffer, | |
576 | * On output the amount of characters needed to write | |
577 | * the string representation of the rr. Even if it does | |
578 | * not fit. | |
579 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
580 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
581 | * small. str_len will be set to the needed buffer space then. | |
582 | */ | |
583 | getdns_return_t | |
584 | getdns_rr_dict2str_buf( | |
585 | const getdns_dict *rr_dict, char *str, size_t *str_len); | |
586 | ||
587 | /** | |
588 | * Convert rr_dict to the string representation of the resource record. | |
589 | * | |
590 | * @param rr_dict The getdns dict representation of the resource record | |
591 | * @param str A pointer to the buffer pointer in which the string | |
592 | * will be written. | |
593 | * On output the buffer pointer will have moved along | |
594 | * the buffer and point right after the just written RR. | |
595 | * @param str_len On input the size of the str buffer, | |
596 | * On output the number of characters needed for the | |
597 | * string will have been substracted from strlen. | |
598 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
599 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
600 | * small. The function will pretend that it had written beyond the end | |
601 | * of the buffer, and str will point past the buffer and str_len will | |
602 | * contain a negative value. | |
603 | */ | |
604 | getdns_return_t | |
605 | getdns_rr_dict2str_scan( | |
606 | const getdns_dict *rr_dict, char **str, int *str_len); | |
607 | ||
608 | ||
609 | /** | |
610 | * Convert the string representation of the resource record to rr_dict format. | |
611 | * | |
612 | * @param str String representation of the resource record. | |
613 | * @return rr_dict The result getdns dict representation of the resource record | |
614 | * @param origin Default suffix for not fully qualified domain names | |
615 | * @param default_ttl Default ttl | |
616 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
617 | */ | |
618 | getdns_return_t | |
619 | getdns_str2rr_dict( | |
620 | const char *str, getdns_dict **rr_dict, | |
621 | const char *origin, uint32_t default_ttl); | |
622 | ||
623 | /** | |
624 | * Read the zonefile and convert to a list of rr_dict's. | |
625 | * | |
626 | * @param fp String representation of the resource record. | |
627 | * @return rr_list The result list of rr_dicts representing the zone file. | |
628 | * @param origin Default suffix for not fully qualified domain names | |
629 | * @param default_ttl Default ttl | |
630 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
631 | */ | |
632 | getdns_return_t | |
633 | getdns_fp2rr_list( | |
634 | FILE *in, getdns_list **rr_list, | |
635 | const char *origin, uint32_t default_ttl); | |
403 | 636 | |
404 | 637 | #ifdef __cplusplus |
405 | 638 | } |
29 | 29 | |
30 | 30 | #include <getdns/getdns.h> |
31 | 31 | #include <sys/time.h> |
32 | #include <stdio.h> | |
32 | 33 | |
33 | 34 | #ifdef __cplusplus |
34 | 35 | extern "C" { |
340 | 341 | */ |
341 | 342 | const char *getdns_get_errorstr_by_id(uint16_t err); |
342 | 343 | |
343 | ||
344 | ||
345 | ||
346 | /** | |
347 | * Public Key Pinning functionality: | |
348 | * | |
349 | * a public key pinset is a list of dicts. each dict should have a | |
350 | * "digest" and a "value". | |
351 | * | |
352 | * "digest": a string indicating the type of digest. at the moment, we | |
353 | * only support a "digest" of "sha256". | |
354 | * | |
355 | * "value": a binary representation of the digest provided. | |
356 | * | |
357 | * given a such a pinset, we should be able to validate a chain | |
358 | * properly according to section 2.6 of RFC 7469. | |
359 | */ | |
360 | ||
361 | /** | |
362 | * convert an HPKP-style pin description to an appropriate getdns data | |
363 | * structure. An example string is: (with the quotes, without any | |
364 | * leading or trailing whitespace): | |
365 | * | |
366 | * pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" | |
367 | * | |
368 | * It is the caller's responsibility to call getdns_dict_destroy() on | |
369 | * the dict returned when it is no longer needed. | |
370 | * | |
371 | * @param context a context to use to create the dict, or NULL to create | |
372 | * it generically | |
373 | * @param str the pinning string to parse | |
374 | * @return a dict created from ctx, or NULL if the string did not match. | |
375 | */ | |
376 | getdns_dict* getdns_pubkey_pin_create_from_string( | |
377 | getdns_context* context, | |
378 | const char* str); | |
379 | ||
380 | ||
381 | /** | |
382 | * Test whether a given pinset is reasonable, including: | |
383 | * | |
384 | * is it well-formed? | |
385 | * are there at least two pins? | |
386 | * are the digests used sane? | |
387 | * | |
388 | * @param pinset the set of public key pins to check for sanity. This | |
389 | * should be a list of dicts. | |
390 | * @return errorlist if not NULL, a list of human-readable strings is | |
391 | * appended to errorlist. | |
392 | * @return GETDNS_RETURN_GOOD if the pinset passes the sanity check. | |
393 | */ | |
394 | getdns_return_t getdns_pubkey_pinset_sanity_check( | |
395 | const getdns_list* pinset, | |
396 | getdns_list* errorlist); | |
397 | ||
398 | ||
399 | ||
344 | 400 | /* WARNING! Function getdns_strerror is not in the API specification and |
345 | 401 | * is likely to be removed from future versions of our implementation, to be |
346 | 402 | * replaced by getdns_get_errorstr_by_id or something similar. |
361 | 417 | /* Authentication options used when doing TLS */ |
362 | 418 | typedef enum getdns_tls_authentication_t { |
363 | 419 | GETDNS_AUTHENTICATION_NONE = 1300, |
364 | GETDNS_AUTHENTICATION_HOSTNAME = 1301, | |
420 | GETDNS_AUTHENTICATION_REQUIRED = 1301 | |
365 | 421 | } getdns_tls_authentication_t; |
422 | ||
423 | /* an alias for REQUIRED */ | |
424 | #define GETDNS_AUTHENTICATION_HOSTNAME GETDNS_AUTHENTICATION_REQUIRED | |
366 | 425 | |
367 | 426 | /** |
368 | 427 | * \defgroup Base authentication texts |
369 | 428 | * @{ |
370 | 429 | */ |
371 | 430 | #define GETDNS_AUTHENTICATION_NONE_TEXT "See getdns_context_set_tls_authentication()" |
372 | #define GETDNS_AUTHENTICATION_HOSTNAME_TEXT "See getdns_context_set_tls_authentication()" | |
431 | #define GETDNS_AUTHENTICATION_REQUIRED_TEXT "See getdns_context_set_tls_authentication()" | |
373 | 432 | /** @} |
374 | 433 | */ |
375 | 434 | |
379 | 438 | #define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private" |
380 | 439 | #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE 620 |
381 | 440 | #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize" |
441 | #define GETDNS_CONTEXT_CODE_PUBKEY_PINSET 621 | |
442 | #define GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT "Change related to getdns_context_set_pubkey_pinset" | |
382 | 443 | |
383 | 444 | getdns_return_t |
384 | 445 | getdns_context_set_tls_authentication( |
398 | 459 | #define GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" |
399 | 460 | #define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN 545 |
400 | 461 | #define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" |
401 | #define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN 546 | |
402 | #define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" | |
462 | ||
463 | #define GETDNS_RETURN_NEED_MORE_SPACE ((getdns_return_t) 399 ) | |
464 | #define GETDNS_RETURN_NEED_MORE_SPACE_TEXT "The buffer was too small" | |
465 | ||
466 | /** | |
467 | * Convert rr_dict to wireformat representation of the resource record. | |
468 | * | |
469 | * @param rr_dict The getdns dict representation of the resource record | |
470 | * @return wire A newly allocated buffer which will contain the wireformat. | |
471 | * @return wire_sz The size of the allocated buffer and the wireformat. | |
472 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
473 | */ | |
474 | getdns_return_t | |
475 | getdns_rr_dict2wire( | |
476 | const getdns_dict *rr_dict, uint8_t **wire, size_t *wire_sz); | |
477 | ||
478 | /** | |
479 | * Convert rr_dict to wireformat representation of the resource record. | |
480 | * | |
481 | * @param rr_dict The getdns dict representation of the resource record | |
482 | * @param wire The buffer in which the wireformat will be written | |
483 | * @param wire_sz On input the size of the wire buffer, | |
484 | * On output the amount of wireformat needed for the | |
485 | * wireformat representation of the resource record; | |
486 | * even if it did not fit. | |
487 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
488 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
489 | * small. wire_sz will be set to the needed buffer space then. | |
490 | */ | |
491 | getdns_return_t | |
492 | getdns_rr_dict2wire_buf( | |
493 | const getdns_dict *rr_dict, uint8_t *wire, size_t *wire_sz); | |
494 | ||
495 | /** | |
496 | * Convert rr_dict to wireformat representation of the resource record. | |
497 | * | |
498 | * @param rr_dict The getdns dict representation of the resource record | |
499 | * @param wire A pointer to the buffer pointer in which the wireformat | |
500 | * will be written. | |
501 | * On output the buffer pointer will have moved along | |
502 | * the buffer and point right after the just written RR. | |
503 | * @param wire_sz On input the size of the wire buffer, | |
504 | * On output the amount of wireformat needed for the | |
505 | * wireformat will have been substracted from wire_sz. | |
506 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
507 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
508 | * small. The function will pretend that it had written beyond the end | |
509 | * of the buffer, and wire will point past the buffer and wire_sz will | |
510 | * contain a negative value. | |
511 | */ | |
512 | getdns_return_t | |
513 | getdns_rr_dict2wire_scan( | |
514 | const getdns_dict *rr_dict, uint8_t **wire, int *wire_sz); | |
515 | ||
516 | ||
517 | /** | |
518 | * Convert wireformat resource record in a getdns rr_dict representation. | |
519 | * | |
520 | * @param wire Buffer containing the wireformat rr | |
521 | * @param wire_sz Size of the wire buffer | |
522 | * @return rr_dict The returned rr_dict | |
523 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
524 | */ | |
525 | getdns_return_t | |
526 | getdns_wire2rr_dict( | |
527 | const uint8_t *wire, size_t wire_sz, getdns_dict **rr_dict); | |
528 | ||
529 | /** | |
530 | * Convert wireformat resource record in a getdns rr_dict representation. | |
531 | * | |
532 | * @param wire Buffer containing the wireformat rr | |
533 | * @param wire_sz On input the size of the wire buffer | |
534 | * On output the length of the wireformat rr. | |
535 | * @return rr_dict The returned rr_dict | |
536 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
537 | */ | |
538 | getdns_return_t | |
539 | getdns_wire2rr_dict_buf( | |
540 | const uint8_t *wire, size_t *wire_sz, getdns_dict **rr_dict); | |
541 | ||
542 | /** | |
543 | * Convert wireformat resource record in a getdns rr_dict representation. | |
544 | * | |
545 | * @param wire A pointer to the pointer of the wireformat buffer. | |
546 | * On return this pointer is moved to after first read | |
547 | * in resource record. | |
548 | * @param wire_sz On input the size of the wire buffer | |
549 | * On output the size is decreased with the length | |
550 | * of the wireformat resource record. | |
551 | * @return rr_dict The returned rr_dict | |
552 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
553 | */ | |
554 | getdns_return_t | |
555 | getdns_wire2rr_dict_scan( | |
556 | const uint8_t **wire, size_t *wire_sz, getdns_dict **rr_dict); | |
557 | ||
558 | ||
559 | /** | |
560 | * Convert rr_dict to the string representation of the resource record. | |
561 | * | |
562 | * @param rr_dict The getdns dict representation of the resource record | |
563 | * @return str A newly allocated string representation of the rr | |
564 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
565 | */ | |
566 | getdns_return_t | |
567 | getdns_rr_dict2str( | |
568 | const getdns_dict *rr_dict, char **str); | |
569 | ||
570 | /** | |
571 | * Convert rr_dict to the string representation of the resource record. | |
572 | * | |
573 | * @param rr_dict The getdns dict representation of the resource record | |
574 | * @param str The buffer in which the string will be written | |
575 | * @param str_len On input the size of the text buffer, | |
576 | * On output the amount of characters needed to write | |
577 | * the string representation of the rr. Even if it does | |
578 | * not fit. | |
579 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
580 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
581 | * small. str_len will be set to the needed buffer space then. | |
582 | */ | |
583 | getdns_return_t | |
584 | getdns_rr_dict2str_buf( | |
585 | const getdns_dict *rr_dict, char *str, size_t *str_len); | |
586 | ||
587 | /** | |
588 | * Convert rr_dict to the string representation of the resource record. | |
589 | * | |
590 | * @param rr_dict The getdns dict representation of the resource record | |
591 | * @param str A pointer to the buffer pointer in which the string | |
592 | * will be written. | |
593 | * On output the buffer pointer will have moved along | |
594 | * the buffer and point right after the just written RR. | |
595 | * @param str_len On input the size of the str buffer, | |
596 | * On output the number of characters needed for the | |
597 | * string will have been substracted from strlen. | |
598 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
599 | * GETDNS_RETURN_NEED_MORE_SPACE will be returned when the buffer was too | |
600 | * small. The function will pretend that it had written beyond the end | |
601 | * of the buffer, and str will point past the buffer and str_len will | |
602 | * contain a negative value. | |
603 | */ | |
604 | getdns_return_t | |
605 | getdns_rr_dict2str_scan( | |
606 | const getdns_dict *rr_dict, char **str, int *str_len); | |
607 | ||
608 | ||
609 | /** | |
610 | * Convert the string representation of the resource record to rr_dict format. | |
611 | * | |
612 | * @param str String representation of the resource record. | |
613 | * @return rr_dict The result getdns dict representation of the resource record | |
614 | * @param origin Default suffix for not fully qualified domain names | |
615 | * @param default_ttl Default ttl | |
616 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
617 | */ | |
618 | getdns_return_t | |
619 | getdns_str2rr_dict( | |
620 | const char *str, getdns_dict **rr_dict, | |
621 | const char *origin, uint32_t default_ttl); | |
622 | ||
623 | /** | |
624 | * Read the zonefile and convert to a list of rr_dict's. | |
625 | * | |
626 | * @param fp String representation of the resource record. | |
627 | * @return rr_list The result list of rr_dicts representing the zone file. | |
628 | * @param origin Default suffix for not fully qualified domain names | |
629 | * @param default_ttl Default ttl | |
630 | * @return GETDNS_RETURN_GOOD on success or an error code on failure. | |
631 | */ | |
632 | getdns_return_t | |
633 | getdns_fp2rr_list( | |
634 | FILE *in, getdns_list **rr_list, | |
635 | const char *origin, uint32_t default_ttl); | |
403 | 636 | |
404 | 637 | #ifdef __cplusplus |
405 | 638 | } |
83 | 83 | p[2] = (uint8_t) ((data >> 8) & 0xff); |
84 | 84 | p[3] = (uint8_t) (data & 0xff); |
85 | 85 | #endif |
86 | } | |
87 | ||
88 | ||
89 | INLINE void | |
90 | gldns_write_uint48(void *dst, uint64_t data) | |
91 | { | |
92 | uint8_t *p = (uint8_t *) dst; | |
93 | p[0] = (uint8_t) ((data >> 40) & 0xff); | |
94 | p[1] = (uint8_t) ((data >> 32) & 0xff); | |
95 | p[2] = (uint8_t) ((data >> 24) & 0xff); | |
96 | p[3] = (uint8_t) ((data >> 16) & 0xff); | |
97 | p[4] = (uint8_t) ((data >> 8) & 0xff); | |
98 | p[5] = (uint8_t) (data & 0xff); | |
86 | 99 | } |
87 | 100 | |
88 | 101 | |
534 | 547 | } |
535 | 548 | |
536 | 549 | /** |
550 | * writes the given 6 byte integer at the given position in the buffer | |
551 | * \param[in] buffer the buffer | |
552 | * \param[in] at the position in the buffer | |
553 | * \param[in] data the (lower) 48 bits to write | |
554 | */ | |
555 | INLINE void | |
556 | gldns_buffer_write_u48_at(gldns_buffer *buffer, size_t at, uint64_t data) | |
557 | { | |
558 | if (buffer->_fixed && at + 6 > buffer->_limit) return; | |
559 | assert(gldns_buffer_available_at(buffer, at, 6)); | |
560 | gldns_write_uint48(buffer->_data + at, data); | |
561 | } | |
562 | ||
563 | /** | |
537 | 564 | * writes the given 4 byte integer at the current position in the buffer |
538 | 565 | * \param[in] buffer the buffer |
539 | 566 | * \param[in] data the 32 bits to write |
543 | 570 | { |
544 | 571 | gldns_buffer_write_u32_at(buffer, buffer->_position, data); |
545 | 572 | buffer->_position += sizeof(data); |
573 | } | |
574 | ||
575 | /** | |
576 | * writes the given 6 byte integer at the current position in the buffer | |
577 | * \param[in] buffer the buffer | |
578 | * \param[in] data the 48 bits to write | |
579 | */ | |
580 | INLINE void | |
581 | gldns_buffer_write_u48(gldns_buffer *buffer, uint64_t data) | |
582 | { | |
583 | gldns_buffer_write_u48_at(buffer, buffer->_position, data); | |
584 | buffer->_position += 6; | |
546 | 585 | } |
547 | 586 | |
548 | 587 | /** |
416 | 416 | GLDNS_EDNS_DAU = 5, /* RFC6975 */ |
417 | 417 | GLDNS_EDNS_DHU = 6, /* RFC6975 */ |
418 | 418 | GLDNS_EDNS_N3U = 7, /* RFC6975 */ |
419 | GLDNS_EDNS_CLIENT_SUBNET = 8 /* draft-vandergaast-edns-client-subnet */ | |
419 | GLDNS_EDNS_CLIENT_SUBNET = 8, /* draft-vandergaast-edns-client-subnet */ | |
420 | GLDNS_EDNS_KEEPALIVE = 11 /* draft-ietf-dnsop-edns-tcp-keepalive*/ | |
420 | 421 | }; |
421 | 422 | typedef enum gldns_enum_edns_option gldns_edns_option; |
422 | 423 |
866 | 866 | return s; |
867 | 867 | } else if(strncmp(line, "$TTL", 4) == 0 && isspace(line[4])) { |
868 | 868 | const char* end = NULL; |
869 | size_t off = 8; | |
869 | size_t off = 5; | |
870 | 870 | *len = 0; |
871 | 871 | *dname_len = 0; |
872 | 872 | if(!parse_state) return GLDNS_WIREPARSE_ERR_OK; |
164 | 164 | { 6, "DHU" }, |
165 | 165 | { 7, "N3U" }, |
166 | 166 | { 8, "edns-client-subnet" }, |
167 | { 11, "edns-tcp-keepalive"}, | |
167 | 168 | { 0, NULL} |
168 | 169 | }; |
169 | 170 | gldns_lookup_table* gldns_edns_options = gldns_edns_options_data; |
1832 | 1833 | return w; |
1833 | 1834 | } |
1834 | 1835 | |
1836 | int gldns_wire2str_edns_keepalive_print(char** s, size_t* sl, uint8_t* data, | |
1837 | size_t len) | |
1838 | { | |
1839 | int w = 0; | |
1840 | uint16_t timeout; | |
1841 | if(!(len == 0 || len == 2)) { | |
1842 | w += gldns_str_print(s, sl, "malformed keepalive "); | |
1843 | w += print_hex_buf(s, sl, data, len); | |
1844 | return w; | |
1845 | } | |
1846 | if(len == 0 ) { | |
1847 | w += gldns_str_print(s, sl, "no timeout value (only valid for client option) "); | |
1848 | } else { | |
1849 | timeout = gldns_read_uint16(data); | |
1850 | w += gldns_str_print(s, sl, "timeout value in units of 100ms %u", (int)timeout); | |
1851 | } | |
1852 | return w; | |
1853 | } | |
1854 | ||
1835 | 1855 | int gldns_wire2str_edns_option_print(char** s, size_t* sl, |
1836 | 1856 | uint16_t option_code, uint8_t* optdata, size_t optlen) |
1837 | 1857 | { |
1860 | 1880 | case GLDNS_EDNS_CLIENT_SUBNET: |
1861 | 1881 | w += gldns_wire2str_edns_subnet_print(s, sl, optdata, optlen); |
1862 | 1882 | break; |
1883 | case GLDNS_EDNS_KEEPALIVE: | |
1884 | w += gldns_wire2str_edns_keepalive_print(s, sl, optdata, optlen); | |
1885 | break; | |
1863 | 1886 | default: |
1864 | 1887 | /* unknown option code */ |
1865 | 1888 | w += print_hex_buf(s, sl, optdata, optlen); |
12 | 12 | getdns_context_get_dnssec_trust_anchors |
13 | 13 | getdns_context_get_dns_transport |
14 | 14 | getdns_context_get_dns_transport_list |
15 | getdns_context_get_tls_authentication | |
16 | 15 | getdns_context_get_edns_client_subnet_private |
17 | 16 | getdns_context_get_edns_do_bit |
18 | 17 | getdns_context_get_edns_extended_rcode |
26 | 25 | getdns_context_get_resolution_type |
27 | 26 | getdns_context_get_suffix |
28 | 27 | getdns_context_get_timeout |
28 | getdns_context_get_tls_authentication | |
29 | 29 | getdns_context_get_tls_query_padding_blocksize |
30 | 30 | getdns_context_get_update_callback |
31 | 31 | getdns_context_get_upstream_recursive_servers |
82 | 82 | getdns_dict_util_get_string |
83 | 83 | getdns_dict_util_set_string |
84 | 84 | getdns_display_ip_address |
85 | getdns_fp2rr_list | |
85 | 86 | getdns_general |
86 | 87 | getdns_general_sync |
87 | 88 | getdns_get_api_version |
112 | 113 | getdns_pretty_snprint_list |
113 | 114 | getdns_print_json_dict |
114 | 115 | getdns_print_json_list |
116 | getdns_pubkey_pin_create_from_string | |
117 | getdns_pubkey_pinset_sanity_check | |
115 | 118 | getdns_root_trust_anchor |
119 | getdns_rr_dict2str | |
120 | getdns_rr_dict2str_buf | |
121 | getdns_rr_dict2str_scan | |
122 | getdns_rr_dict2wire | |
123 | getdns_rr_dict2wire_buf | |
124 | getdns_rr_dict2wire_scan | |
116 | 125 | getdns_service |
117 | 126 | getdns_service_sync |
118 | 127 | getdns_snprint_json_dict |
119 | 128 | getdns_snprint_json_list |
129 | getdns_str2rr_dict | |
120 | 130 | getdns_strerror |
121 | 131 | getdns_validate_dnssec |
132 | getdns_wire2rr_dict | |
133 | getdns_wire2rr_dict_buf | |
134 | getdns_wire2rr_dict_scan | |
122 | 135 | plain_mem_funcs_user_arg |
123 | 136 | priv_getdns_context_mf |
106 | 106 | |
107 | 107 | i = &list->items[index]; |
108 | 108 | if (!*next) { |
109 | switch (i->dtype) { | |
110 | case t_dict : getdns_dict_destroy(i->data.dict); break; | |
111 | case t_list : getdns_list_destroy(i->data.list); break; | |
112 | case t_bindata: _getdns_bindata_destroy( | |
113 | &list->mf, i->data.bindata); | |
114 | default : break; | |
115 | } | |
109 | 116 | if (index < list->numinuse - 1) |
110 | 117 | (void) memmove( i, &i[1], |
111 | 118 | (list->numinuse - index) * sizeof(getdns_item)); |
544 | 551 | } /* getdns_list_set_list */ |
545 | 552 | |
546 | 553 | /*---------------------------------------- getdns_list_set_bindata */ |
547 | getdns_return_t | |
548 | getdns_list_set_bindata( | |
549 | getdns_list *list, size_t index, const getdns_bindata *child_bindata) | |
554 | static getdns_return_t | |
555 | _getdns_list_set_const_bindata( | |
556 | getdns_list *list, size_t index, size_t size, const void *data) | |
550 | 557 | { |
551 | 558 | getdns_bindata *newbindata; |
552 | 559 | getdns_return_t r; |
553 | 560 | |
554 | if (!list || !child_bindata) | |
555 | return GETDNS_RETURN_INVALID_PARAMETER; | |
556 | ||
557 | if (!(newbindata = _getdns_bindata_copy(&list->mf, child_bindata))) | |
561 | if (!list) | |
562 | return GETDNS_RETURN_INVALID_PARAMETER; | |
563 | ||
564 | if (!(newbindata = _getdns_bindata_copy(&list->mf, size, data))) | |
558 | 565 | return GETDNS_RETURN_MEMORY_ERROR; |
559 | 566 | |
560 | 567 | if ((r = _getdns_list_request_index(list, index))) { |
566 | 573 | return GETDNS_RETURN_GOOD; |
567 | 574 | } /* getdns_list_set_bindata */ |
568 | 575 | |
576 | getdns_return_t | |
577 | getdns_list_set_bindata( | |
578 | getdns_list *list, size_t index, const getdns_bindata *child_bindata) | |
579 | { | |
580 | return !child_bindata ? GETDNS_RETURN_INVALID_PARAMETER | |
581 | : _getdns_list_set_const_bindata( | |
582 | list, index, child_bindata->size, child_bindata->data); | |
583 | } | |
584 | ||
569 | 585 | /*----------------------------------------- getdns_list_set_string */ |
570 | 586 | static getdns_return_t |
571 | 587 | getdns_list_set_string(getdns_list *list, size_t index, const char *value) |
572 | 588 | { |
573 | getdns_bindata *newbindata; | |
574 | getdns_return_t r; | |
575 | ||
576 | if (!list || !value) | |
577 | return GETDNS_RETURN_INVALID_PARAMETER; | |
578 | ||
579 | if (!(newbindata = GETDNS_MALLOC(list->mf, getdns_bindata))) | |
580 | return GETDNS_RETURN_MEMORY_ERROR; | |
581 | ||
582 | newbindata->size = strlen(value); | |
583 | if (!(newbindata->data = (void *)_getdns_strdup(&list->mf, value))) { | |
584 | GETDNS_FREE(list->mf, newbindata); | |
585 | return GETDNS_RETURN_MEMORY_ERROR; | |
586 | } | |
587 | if ((r = _getdns_list_request_index(list, index))) { | |
588 | GETDNS_FREE(list->mf, newbindata->data); | |
589 | GETDNS_FREE(list->mf, newbindata); | |
590 | return r; | |
591 | } | |
592 | list->items[index].dtype = t_bindata; | |
593 | list->items[index].data.bindata = newbindata; | |
594 | return GETDNS_RETURN_GOOD; | |
589 | return value | |
590 | ? _getdns_list_set_const_bindata(list, index, strlen(value), value) | |
591 | : GETDNS_RETURN_INVALID_PARAMETER; | |
595 | 592 | } /* getdns_list_set_string */ |
596 | 593 | |
597 | 594 | /*---------------------------------------- getdns_list_set_int */ |
630 | 627 | return getdns_list_set_bindata(list, list->numinuse, child_bindata); |
631 | 628 | } |
632 | 629 | getdns_return_t |
630 | _getdns_list_append_const_bindata( | |
631 | getdns_list *list, size_t size, const void *data) | |
632 | { | |
633 | if (!list) return GETDNS_RETURN_INVALID_PARAMETER; | |
634 | return _getdns_list_set_const_bindata(list, list->numinuse, size, data); | |
635 | } | |
636 | getdns_return_t | |
633 | 637 | _getdns_list_append_string(getdns_list *list, const char *value) |
634 | 638 | { |
635 | 639 | if (!list) return GETDNS_RETURN_INVALID_PARAMETER; |
0 | /** | |
1 | * | |
2 | * /brief functions for Public Key Pinning | |
3 | * | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2015, Daniel Kahn Gillmor | |
8 | * All rights reserved. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions are met: | |
12 | * * Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * * Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * * Neither the names of the copyright holders nor the | |
18 | * names of its contributors may be used to endorse or promote products | |
19 | * derived from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY | |
25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | /** | |
34 | * getdns Public Key Pinning | |
35 | * | |
36 | * a public key pinset is a list of dicts. each dict should have a | |
37 | * "digest" and a "value". | |
38 | * | |
39 | * "digest": a string indicating the type of digest. at the moment, we | |
40 | * only support a "digest" of "sha256". | |
41 | * | |
42 | * "value": a binary representation of the digest provided. | |
43 | * | |
44 | * given a such a pinset, we should be able to validate a chain | |
45 | * properly according to section 2.6 of RFC 7469. | |
46 | */ | |
47 | #include "config.h" | |
48 | #include "debug.h" | |
49 | #include <getdns/getdns.h> | |
50 | #include <openssl/evp.h> | |
51 | #include <openssl/bio.h> | |
52 | #include <openssl/sha.h> | |
53 | #include <openssl/x509.h> | |
54 | #include <string.h> | |
55 | #include "context.h" | |
56 | ||
57 | /* we only support sha256 at the moment. adding support for another | |
58 | digest is more complex than just adding another entry here. in | |
59 | particular, you'll probably need a match for a particular cert | |
60 | against all supported algorithms. better to wait on doing that | |
61 | until it is a better-understood problem (i.e. wait until hpkp is | |
62 | updated and follow the guidance in rfc7469bis) | |
63 | */ | |
64 | ||
65 | static const getdns_bindata sha256 = { | |
66 | .size = sizeof("sha256") - 1, | |
67 | .data = (uint8_t*)"sha256" | |
68 | }; | |
69 | ||
70 | ||
71 | #define PIN_PREFIX "pin-sha256=\"" | |
72 | #define PIN_PREFIX_LENGTH (sizeof(PIN_PREFIX) - 1) | |
73 | /* b64 turns every 3 octets (or fraction thereof) into 4 octets */ | |
74 | #define B64_ENCODED_SHA256_LENGTH (((SHA256_DIGEST_LENGTH + 2)/3) * 4) | |
75 | ||
76 | /* convert an HPKP-style pin description to an appropriate getdns data | |
77 | structure. An example string is: (with the quotes, without any | |
78 | leading or trailing whitespace): | |
79 | ||
80 | pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" | |
81 | ||
82 | getdns_build_pin_from_string returns a dict created from ctx, or | |
83 | NULL if the string did not match. If ctx is NULL, the dict is | |
84 | created via getdns_dict_create(). | |
85 | ||
86 | It is the caller's responsibility to call getdns_dict_destroy when | |
87 | it is no longer needed. | |
88 | */ | |
89 | getdns_dict* getdns_pubkey_pin_create_from_string( | |
90 | getdns_context* context, | |
91 | const char* str) | |
92 | { | |
93 | BIO *bio = NULL; | |
94 | int i; | |
95 | uint8_t buf[SHA256_DIGEST_LENGTH]; | |
96 | char inbuf[B64_ENCODED_SHA256_LENGTH + 1]; | |
97 | getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; | |
98 | getdns_dict* out = NULL; | |
99 | ||
100 | /* we only do sha256 right now, make sure this is well-formed */ | |
101 | if (strncmp(PIN_PREFIX, str, PIN_PREFIX_LENGTH)) | |
102 | return NULL; | |
103 | for (i = PIN_PREFIX_LENGTH; i < PIN_PREFIX_LENGTH + B64_ENCODED_SHA256_LENGTH - 1; i++) | |
104 | if (!((str[i] >= 'a' && str[i] <= 'z') || | |
105 | (str[i] >= 'A' && str[i] <= 'Z') || | |
106 | (str[i] >= '0' && str[i] <= '9') || | |
107 | (str[i] == '+') || (str[i] == '/'))) | |
108 | return NULL; | |
109 | if (str[i++] != '=') | |
110 | return NULL; | |
111 | if (str[i++] != '"') | |
112 | return NULL; | |
113 | if (str[i++] != '\0') | |
114 | return NULL; | |
115 | ||
116 | /* openssl needs a trailing newline to base64 decode */ | |
117 | memcpy(inbuf, str + PIN_PREFIX_LENGTH, B64_ENCODED_SHA256_LENGTH); | |
118 | inbuf[B64_ENCODED_SHA256_LENGTH] = '\n'; | |
119 | ||
120 | bio = BIO_push(BIO_new(BIO_f_base64()), | |
121 | BIO_new_mem_buf(inbuf, sizeof(inbuf))); | |
122 | if (BIO_read(bio, buf, sizeof(buf)) != sizeof(buf)) | |
123 | goto fail; | |
124 | ||
125 | if (context) | |
126 | out = getdns_dict_create_with_context(context); | |
127 | else | |
128 | out = getdns_dict_create(); | |
129 | if (out == NULL) | |
130 | goto fail; | |
131 | if (getdns_dict_set_bindata(out, "digest", &sha256)) | |
132 | goto fail; | |
133 | if (getdns_dict_set_bindata(out, "value", &value)) | |
134 | goto fail; | |
135 | return out; | |
136 | ||
137 | fail: | |
138 | BIO_free_all(bio); | |
139 | getdns_dict_destroy(out); | |
140 | return NULL; | |
141 | } | |
142 | ||
143 | ||
144 | /* Test whether a given pinset is reasonable, including: | |
145 | ||
146 | * is it well-formed? | |
147 | * are there at least two pins? | |
148 | * are the digests used sane? | |
149 | ||
150 | if errorlist is NULL, the sanity check just returns success or | |
151 | failure. | |
152 | ||
153 | if errorlist is not NULL, we append human-readable strings to | |
154 | report the errors. | |
155 | */ | |
156 | ||
157 | #define PKP_SC_ERR(e) { \ | |
158 | err.size = sizeof(e); \ | |
159 | err.data = (uint8_t*)e; \ | |
160 | if (errorlist) \ | |
161 | getdns_list_set_bindata(errorlist, \ | |
162 | preverrs + errorcount, &err); \ | |
163 | errorcount++; \ | |
164 | } | |
165 | #define PKP_SC_HARDERR(e, val) { \ | |
166 | PKP_SC_ERR(e); return val; \ | |
167 | } | |
168 | getdns_return_t getdns_pubkey_pinset_sanity_check( | |
169 | const getdns_list* pinset, | |
170 | getdns_list* errorlist) | |
171 | { | |
172 | size_t errorcount = 0, preverrs = 0, pins = 0, i; | |
173 | getdns_bindata err; | |
174 | getdns_dict * pin; | |
175 | getdns_bindata * data; | |
176 | ||
177 | if (errorlist) | |
178 | if (getdns_list_get_length(errorlist, &preverrs)) | |
179 | return GETDNS_RETURN_INVALID_PARAMETER; | |
180 | ||
181 | if (getdns_list_get_length(pinset, &pins)) | |
182 | PKP_SC_HARDERR("Can't get length of pinset", | |
183 | GETDNS_RETURN_INVALID_PARAMETER); | |
184 | if (pins < 2) | |
185 | PKP_SC_ERR("This pinset has fewer than 2 pins"); | |
186 | for (i = 0; i < pins; i++) | |
187 | { | |
188 | /* is it a dict? */ | |
189 | if (getdns_list_get_dict(pinset, i, &pin)) { | |
190 | PKP_SC_ERR("Could not retrieve a pin"); | |
191 | } else { | |
192 | /* does the pin have the right digest type? */ | |
193 | if (getdns_dict_get_bindata(pin, "digest", &data)) { | |
194 | PKP_SC_ERR("Pin has no 'digest' entry"); | |
195 | } else { | |
196 | if (data->size != sha256.size || | |
197 | memcmp(data->data, sha256.data, sha256.size)) | |
198 | PKP_SC_ERR("Pin has 'digest' other than sha256"); | |
199 | } | |
200 | /* if it does, is the value the right length? */ | |
201 | if (getdns_dict_get_bindata(pin, "value", &data)) { | |
202 | PKP_SC_ERR("Pin has no 'value' entry"); | |
203 | } else { | |
204 | if (data->size != SHA256_DIGEST_LENGTH) | |
205 | PKP_SC_ERR("Pin has the wrong size 'value' (should be 32 octets for sha256)"); | |
206 | } | |
207 | ||
208 | /* should we choke if it has some other key? for | |
209 | * extensibility, we will not treat this as an | |
210 | * error.*/ | |
211 | } | |
212 | } | |
213 | ||
214 | if (errorcount > 0) | |
215 | return GETDNS_RETURN_GENERIC_ERROR; | |
216 | return GETDNS_RETURN_GOOD; | |
217 | } | |
218 | ||
219 | getdns_return_t | |
220 | _getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, | |
221 | struct mem_funcs *mf, | |
222 | sha256_pin_t **pinset_out) | |
223 | { | |
224 | getdns_return_t r; | |
225 | size_t pins, i; | |
226 | sha256_pin_t *out = NULL, *onext = NULL; | |
227 | getdns_dict * pin; | |
228 | getdns_bindata * data = NULL; | |
229 | ||
230 | if (r = getdns_list_get_length(pinset_list, &pins), r) | |
231 | return r; | |
232 | for (i = 0; i < pins; i++) | |
233 | { | |
234 | if (r = getdns_list_get_dict(pinset_list, i, &pin), r) | |
235 | goto fail; | |
236 | /* does the pin have the right digest type? */ | |
237 | if (r = getdns_dict_get_bindata(pin, "digest", &data), r) | |
238 | goto fail; | |
239 | if (data->size != sha256.size || | |
240 | memcmp(data->data, sha256.data, sha256.size)) { | |
241 | r = GETDNS_RETURN_INVALID_PARAMETER; | |
242 | goto fail; | |
243 | } | |
244 | /* if it does, is the value the right length? */ | |
245 | if (r = getdns_dict_get_bindata(pin, "value", &data), r) | |
246 | goto fail; | |
247 | if (data->size != SHA256_DIGEST_LENGTH) { | |
248 | r = GETDNS_RETURN_INVALID_PARAMETER; | |
249 | goto fail; | |
250 | } | |
251 | /* make a new pin */ | |
252 | onext = GETDNS_MALLOC(*mf, sha256_pin_t); | |
253 | if (onext == NULL) { | |
254 | r = GETDNS_RETURN_MEMORY_ERROR; | |
255 | goto fail; | |
256 | } | |
257 | onext->next = out; | |
258 | memcpy(onext->pin, data->data, SHA256_DIGEST_LENGTH); | |
259 | out = onext; | |
260 | } | |
261 | ||
262 | *pinset_out = out; | |
263 | return GETDNS_RETURN_GOOD; | |
264 | fail: | |
265 | while (out) { | |
266 | onext = out->next; | |
267 | GETDNS_FREE(*mf, out); | |
268 | out = onext; | |
269 | } | |
270 | return r; | |
271 | } | |
272 | ||
273 | getdns_return_t | |
274 | _getdns_get_pubkey_pinset_list(getdns_context *ctx, | |
275 | const sha256_pin_t *pinset_in, | |
276 | getdns_list **pinset_list) | |
277 | { | |
278 | getdns_list *out = getdns_list_create_with_context(ctx); | |
279 | getdns_return_t r; | |
280 | uint8_t buf[SHA256_DIGEST_LENGTH]; | |
281 | getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; | |
282 | getdns_dict *pin = NULL; | |
283 | size_t idx = 0; | |
284 | ||
285 | if (out == NULL) | |
286 | return GETDNS_RETURN_MEMORY_ERROR; | |
287 | while (pinset_in) { | |
288 | pin = getdns_dict_create_with_context(ctx); | |
289 | if (pin == NULL) { | |
290 | r = GETDNS_RETURN_MEMORY_ERROR; | |
291 | goto fail; | |
292 | } | |
293 | if (r = getdns_dict_set_bindata(pin, "digest", &sha256), r) | |
294 | goto fail; | |
295 | memcpy(buf, pinset_in->pin, sizeof(buf)); | |
296 | if (r = getdns_dict_set_bindata(pin, "value", &value), r) | |
297 | goto fail; | |
298 | if (r = getdns_list_set_dict(out, idx++, pin), r) | |
299 | goto fail; | |
300 | getdns_dict_destroy(pin); | |
301 | pin = NULL; | |
302 | pinset_in = pinset_in->next; | |
303 | } | |
304 | ||
305 | *pinset_list = out; | |
306 | return GETDNS_RETURN_GOOD; | |
307 | fail: | |
308 | getdns_dict_destroy(pin); | |
309 | getdns_list_destroy(out); | |
310 | return r; | |
311 | } | |
312 | ||
313 | /* this should only happen once ever in the life of the library. it's | |
314 | used to associate a getdns_context_t with an SSL_CTX, to be able to | |
315 | do custom verification. | |
316 | ||
317 | see doc/HOWTO/proxy_certificates.txt as an example | |
318 | */ | |
319 | static int | |
320 | _get_ssl_getdns_upstream_idx() | |
321 | { | |
322 | static volatile int idx = -1; | |
323 | if (idx < 0) { | |
324 | CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); | |
325 | if (idx < 0) | |
326 | idx = SSL_get_ex_new_index(0, "associated getdns upstream", | |
327 | NULL,NULL,NULL); | |
328 | CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); | |
329 | } | |
330 | return idx; | |
331 | } | |
332 | ||
333 | getdns_upstream* | |
334 | _getdns_upstream_from_x509_store(X509_STORE_CTX *store) | |
335 | { | |
336 | int uidx = _get_ssl_getdns_upstream_idx(); | |
337 | int sslidx = SSL_get_ex_data_X509_STORE_CTX_idx(); | |
338 | const SSL *ssl; | |
339 | ||
340 | /* all *_get_ex_data() should return NULL on failure anyway */ | |
341 | ssl = X509_STORE_CTX_get_ex_data(store, sslidx); | |
342 | if (ssl) | |
343 | return (getdns_upstream*) SSL_get_ex_data(ssl, uidx); | |
344 | else | |
345 | return NULL; | |
346 | /* TODO: if we want more details about errors somehow, we | |
347 | * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ | |
348 | } | |
349 | ||
350 | getdns_return_t | |
351 | _getdns_associate_upstream_with_SSL(SSL *ssl, | |
352 | getdns_upstream *upstream) | |
353 | { | |
354 | int uidx = _get_ssl_getdns_upstream_idx(); | |
355 | if (SSL_set_ex_data(ssl, uidx, upstream)) | |
356 | return GETDNS_RETURN_GOOD; | |
357 | else | |
358 | return GETDNS_RETURN_GENERIC_ERROR; | |
359 | /* TODO: if we want more details about errors somehow, we | |
360 | * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ | |
361 | } | |
362 | ||
363 | getdns_return_t | |
364 | _getdns_verify_pinset_match(const sha256_pin_t *pinset, | |
365 | X509_STORE_CTX *store) | |
366 | { | |
367 | getdns_return_t ret = GETDNS_RETURN_GENERIC_ERROR; | |
368 | X509 *x; | |
369 | int i, len; | |
370 | unsigned char raw[4096]; | |
371 | unsigned char *next = raw; | |
372 | unsigned char buf[sizeof(pinset->pin)]; | |
373 | const sha256_pin_t *p; | |
374 | ||
375 | if (pinset == NULL || store == NULL) | |
376 | return GETDNS_RETURN_GENERIC_ERROR; | |
377 | ||
378 | /* start at the base of the chain (the end-entity cert) and | |
379 | * make sure that some valid element of the chain does match | |
380 | * the pinset. */ | |
381 | ||
382 | /* Testing with OpenSSL 1.0.1e-1 on debian indicates that | |
383 | * store->untrusted holds the chain offered by the server in | |
384 | * the order that the server offers it. If the server offers | |
385 | * bogus certificates (that is, matching and valid certs that | |
386 | * belong to private keys that the server does not control), | |
387 | * the the verification will succeed (including this pinset | |
388 | * check), but the handshake will fail outside of this | |
389 | * verification. */ | |
390 | ||
391 | /* TODO: how do we handle raw public keys? */ | |
392 | ||
393 | for (i = 0; i < sk_X509_num(store->untrusted); i++) { | |
394 | if (i > 0) { | |
395 | /* TODO: how do we ensure that the certificates in | |
396 | * each stage appropriately sign the previous one? | |
397 | * for now, to be safe, we only examine the end-entity | |
398 | * cert: */ | |
399 | return GETDNS_RETURN_GENERIC_ERROR; | |
400 | } | |
401 | ||
402 | x = sk_X509_value(store->untrusted, i); | |
403 | if (x->cert_info == NULL) | |
404 | continue; | |
405 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
406 | DEBUG_STUB("--- %s: name of cert %d:\n", __FUNCTION__, i); | |
407 | if (x->cert_info->subject != NULL) | |
408 | X509_NAME_print_ex_fp(stderr, x->cert_info->subject, 4, XN_FLAG_ONELINE); | |
409 | fprintf(stderr, "\n"); | |
410 | #endif | |
411 | if (x->cert_info->key == NULL) | |
412 | continue; | |
413 | ||
414 | /* digest the cert with sha256 */ | |
415 | len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL); | |
416 | if (len > sizeof(raw)) { | |
417 | DEBUG_STUB("--- %s: pubkey %d is larger than %ld octets\n", | |
418 | __FUNCTION__, i, sizeof(raw)); | |
419 | continue; | |
420 | } | |
421 | i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &next); | |
422 | if (next - raw != len) { | |
423 | DEBUG_STUB("--- %s: pubkey %d claimed it needed %d octets, really needed %ld\n", | |
424 | __FUNCTION__, i, len, next - raw); | |
425 | continue; | |
426 | } | |
427 | SHA256(raw, len, buf); | |
428 | ||
429 | /* compare it */ | |
430 | for (p = pinset; p; p = p->next) | |
431 | if (0 == memcmp(buf, p->pin, sizeof(p->pin))) { | |
432 | DEBUG_STUB("--- %s: pubkey %d matched pin %p (%ld)!\n", | |
433 | __FUNCTION__, i, p, sizeof(p->pin)); | |
434 | return GETDNS_RETURN_GOOD; | |
435 | } else | |
436 | DEBUG_STUB("--- %s: pubkey %d did not match pin %p!\n", | |
437 | __FUNCTION__, i, p); | |
438 | } | |
439 | ||
440 | return ret; | |
441 | } | |
442 | ||
443 | /* pubkey-pinning.c */ |
0 | /** | |
1 | * | |
2 | * /brief internal functions for dealing with pubkey pinsets | |
3 | * | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2015 ACLU | |
8 | * All rights reserved. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions are met: | |
12 | * * Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * * Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * * Neither the names of the copyright holders nor the | |
18 | * names of its contributors may be used to endorse or promote products | |
19 | * derived from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY | |
25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | #ifndef PUBKEY_PINNING_H_ | |
34 | #define PUBKEY_PINNING_H_ | |
35 | ||
36 | ||
37 | /* create and populate a pinset linked list from a getdns_list pinset */ | |
38 | getdns_return_t | |
39 | _getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, | |
40 | struct mem_funcs *mf, | |
41 | sha256_pin_t **pinset_out); | |
42 | ||
43 | ||
44 | /* create a getdns_list version of the pinset */ | |
45 | getdns_return_t | |
46 | _getdns_get_pubkey_pinset_list(getdns_context *ctx, | |
47 | const sha256_pin_t *pinset_in, | |
48 | getdns_list **pinset_list); | |
49 | ||
50 | ||
51 | /* internal functions for associating X.509 verification processes in | |
52 | * OpenSSL with getdns_upstream objects. */ | |
53 | ||
54 | getdns_upstream* | |
55 | _getdns_upstream_from_x509_store(X509_STORE_CTX *store); | |
56 | ||
57 | ||
58 | getdns_return_t | |
59 | _getdns_associate_upstream_with_SSL(SSL *ssl, | |
60 | getdns_upstream *upstream); | |
61 | ||
62 | getdns_return_t | |
63 | _getdns_verify_pinset_match(const sha256_pin_t *pinset, | |
64 | X509_STORE_CTX *store); | |
65 | ||
66 | #endif | |
67 | /* pubkey-pinning.h */ |
40 | 40 | #include "gldns/gbuffer.h" |
41 | 41 | #include "gldns/pkthdr.h" |
42 | 42 | #include "dict.h" |
43 | #include "debug.h" | |
44 | ||
45 | /* MAXIMUM_TSIG_SPACE = TSIG name (dname) : 256 | |
46 | * TSIG type (uint16_t) : 2 | |
47 | * TSIG class (uint16_t) : 2 | |
48 | * TSIG TTL (uint32_t) : 4 | |
49 | * RdLen (uint16_t) : 2 | |
50 | * Algorithm name (dname) : 256 | |
51 | * Time Signed (uint48_t) : 6 | |
52 | * Fudge (uint16_t) : 2 | |
53 | * Mac Size (uint16_t) : 2 | |
54 | * Mac (variable) : EVP_MAX_MD_SIZE | |
55 | * Original Id (uint16_t) : 2 | |
56 | * Error (uint16_t) : 2 | |
57 | * Other Len (uint16_t) : 2 | |
58 | * Other Data (nothing) : 0 | |
59 | * ---- + | |
60 | * 538 + EVP_MAX_MD_SIZE | |
61 | */ | |
62 | #define MAXIMUM_TSIG_SPACE (538 + EVP_MAX_MD_SIZE) | |
43 | 63 | |
44 | 64 | getdns_dict dnssec_ok_checking_disabled_spc = { |
45 | 65 | { RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp }, |
89 | 109 | GETDNS_FREE(net_req->owner->my_mf, net_req->response); |
90 | 110 | } |
91 | 111 | |
112 | static uint8_t * | |
113 | netreq_reset(getdns_network_req *net_req) | |
114 | { | |
115 | uint8_t *buf; | |
116 | /* variables that need to be reset on reinit | |
117 | */ | |
118 | net_req->unbound_id = -1; | |
119 | net_req->state = NET_REQ_NOT_SENT; | |
120 | net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE; | |
121 | net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE; | |
122 | net_req->query_id = 0; | |
123 | net_req->response_len = 0; | |
124 | /* Some fields to record info for return_call_reporting */ | |
125 | net_req->debug_start_time = 0; | |
126 | net_req->debug_end_time = 0; | |
127 | if (!net_req->query) | |
128 | return NULL; | |
129 | ||
130 | buf = net_req->query + GLDNS_HEADER_SIZE; | |
131 | (void) memcpy(buf, net_req->owner->name, net_req->owner->name_len); | |
132 | buf += net_req->owner->name_len; | |
133 | ||
134 | gldns_write_uint16(buf, net_req->request_type); | |
135 | gldns_write_uint16(buf + 2, net_req->owner->request_class); | |
136 | return buf + 4; | |
137 | } | |
138 | ||
92 | 139 | static int |
93 | 140 | network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, |
94 | const char *name, uint16_t request_type, uint16_t request_class, | |
95 | int dnssec_extension_set, int with_opt, | |
141 | uint16_t request_type, int dnssec_extension_set, int with_opt, | |
96 | 142 | int edns_maximum_udp_payload_size, |
97 | 143 | uint8_t edns_extended_rcode, uint8_t edns_version, int edns_do_bit, |
98 | 144 | uint16_t opt_options_size, size_t noptions, getdns_list *options, |
99 | 145 | size_t wire_data_sz, size_t max_query_sz) |
100 | 146 | { |
101 | 147 | uint8_t *buf; |
102 | size_t dname_len; | |
103 | 148 | getdns_dict *option; |
104 | 149 | uint32_t option_code; |
105 | 150 | getdns_bindata *option_data; |
106 | 151 | size_t i; |
107 | 152 | int r = 0; |
108 | 153 | |
154 | /* variables that stay the same on reinit, don't touch | |
155 | */ | |
109 | 156 | net_req->request_type = request_type; |
110 | net_req->request_class = request_class; | |
111 | net_req->unbound_id = -1; | |
112 | net_req->state = NET_REQ_NOT_SENT; | |
113 | 157 | net_req->owner = owner; |
114 | ||
115 | net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE; | |
116 | ||
117 | net_req->upstream = NULL; | |
118 | net_req->fd = -1; | |
119 | net_req->transport_count = owner->context->dns_transport_count; | |
120 | net_req->transport_current = 0; | |
121 | memcpy(net_req->transports, owner->context->dns_transports, | |
122 | net_req->transport_count * sizeof(getdns_transport_list_t)); | |
123 | net_req->tls_auth_min = owner->context->tls_auth_min; | |
124 | memset(&net_req->event, 0, sizeof(net_req->event)); | |
125 | memset(&net_req->tcp, 0, sizeof(net_req->tcp)); | |
126 | net_req->query_id = 0; | |
127 | 158 | net_req->edns_maximum_udp_payload_size = edns_maximum_udp_payload_size; |
128 | 159 | net_req->max_udp_payload_size = edns_maximum_udp_payload_size != -1 |
129 | 160 | ? edns_maximum_udp_payload_size : 1432; |
161 | net_req->base_query_option_sz = opt_options_size; | |
162 | net_req->wire_data_sz = wire_data_sz; | |
163 | ||
164 | net_req->transport_count = owner->context->dns_transport_count; | |
165 | memcpy(net_req->transports, owner->context->dns_transports, | |
166 | net_req->transport_count * sizeof(getdns_transport_list_t)); | |
167 | net_req->tls_auth_min = owner->context->tls_auth_min; | |
168 | ||
169 | /* state variables from the resolver, don't touch | |
170 | */ | |
171 | net_req->upstream = NULL; | |
172 | net_req->fd = -1; | |
173 | net_req->transport_current = 0; | |
174 | memset(&net_req->event, 0, sizeof(net_req->event)); | |
175 | memset(&net_req->tcp, 0, sizeof(net_req->tcp)); | |
176 | net_req->keepalive_sent = 0; | |
130 | 177 | net_req->write_queue_tail = NULL; |
131 | net_req->response_len = 0; | |
132 | net_req->base_query_option_sz = opt_options_size; | |
133 | ||
134 | /* Some fields to record info for return_call_debugging */ | |
135 | net_req->debug_start_time = 0; | |
136 | net_req->debug_end_time = 0; | |
178 | /* Some fields to record info for return_call_reporting */ | |
137 | 179 | net_req->debug_tls_auth_status = 0; |
138 | 180 | net_req->debug_udp = 0; |
139 | 181 | |
140 | net_req->wire_data_sz = wire_data_sz; | |
141 | if (max_query_sz) { | |
142 | /* first two bytes will contain query length (for tcp) */ | |
143 | buf = net_req->query = net_req->wire_data + 2; | |
144 | ||
145 | gldns_write_uint16(buf + 2, 0); /* reset all flags */ | |
146 | GLDNS_RD_SET(buf); | |
147 | if (dnssec_extension_set) /* We will do validation ourselves */ | |
148 | GLDNS_CD_SET(buf); | |
149 | GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY); | |
150 | gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */ | |
151 | gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */ | |
152 | gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */ | |
153 | gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0); | |
154 | ||
155 | buf += GLDNS_HEADER_SIZE; | |
156 | dname_len = max_query_sz - GLDNS_HEADER_SIZE; | |
157 | if ((r = gldns_str2wire_dname_buf(name, buf, &dname_len))) { | |
158 | net_req->opt = NULL; | |
159 | return r; | |
160 | } | |
161 | ||
162 | buf += dname_len; | |
163 | ||
164 | gldns_write_uint16(buf, request_type); | |
165 | gldns_write_uint16(buf + 2, request_class); | |
166 | buf += 4; | |
167 | ||
168 | if (with_opt) { | |
169 | net_req->opt = buf; | |
170 | buf[0] = 0; /* dname for . */ | |
171 | gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT); | |
172 | gldns_write_uint16(net_req->opt + 3, | |
173 | net_req->max_udp_payload_size); | |
174 | buf[5] = edns_extended_rcode; | |
175 | buf[6] = edns_version; | |
176 | buf[7] = edns_do_bit ? 0x80 : 0; | |
177 | buf[8] = 0; | |
178 | gldns_write_uint16(buf + 9, opt_options_size); | |
179 | buf += 11; | |
180 | for (i = 0; i < noptions; i++) { | |
181 | if (getdns_list_get_dict(options, i, &option)) | |
182 | continue; | |
183 | if (getdns_dict_get_int( | |
184 | option, "option_code", &option_code)) | |
185 | continue; | |
186 | if (getdns_dict_get_bindata( | |
187 | option, "option_data", &option_data)) | |
188 | continue; | |
189 | ||
190 | gldns_write_uint16(buf, (uint16_t) option_code); | |
191 | gldns_write_uint16(buf + 2, | |
192 | (uint16_t) option_data->size); | |
193 | (void) memcpy(buf + 4, option_data->data, | |
194 | option_data->size); | |
195 | ||
196 | buf += option_data->size + 4; | |
197 | } | |
198 | } else | |
199 | net_req->opt = NULL; | |
200 | net_req->response = buf; | |
201 | gldns_write_uint16(net_req->wire_data, net_req->response - net_req->query); | |
202 | } else { | |
182 | if (max_query_sz == 0) { | |
203 | 183 | net_req->query = NULL; |
204 | 184 | net_req->opt = NULL; |
205 | 185 | net_req->response = net_req->wire_data; |
206 | } | |
186 | netreq_reset(net_req); | |
187 | return r; | |
188 | } | |
189 | /* first two bytes will contain query length (for tcp) */ | |
190 | net_req->query = net_req->wire_data + 2; | |
191 | ||
192 | buf = net_req->query; | |
193 | gldns_write_uint16(buf + 2, 0); /* reset all flags */ | |
194 | GLDNS_RD_SET(buf); | |
195 | if (dnssec_extension_set) /* We will do validation ourselves */ | |
196 | GLDNS_CD_SET(buf); | |
197 | GLDNS_OPCODE_SET(buf, GLDNS_PACKET_QUERY); | |
198 | gldns_write_uint16(buf + GLDNS_QDCOUNT_OFF, 1); /* 1 query */ | |
199 | gldns_write_uint16(buf + GLDNS_ANCOUNT_OFF, 0); /* 0 answers */ | |
200 | gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */ | |
201 | gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0); | |
202 | ||
203 | buf = netreq_reset(net_req); | |
204 | if (with_opt) { | |
205 | net_req->opt = buf; | |
206 | buf[0] = 0; /* dname for . */ | |
207 | gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT); | |
208 | gldns_write_uint16(net_req->opt + 3, | |
209 | net_req->max_udp_payload_size); | |
210 | buf[5] = edns_extended_rcode; | |
211 | buf[6] = edns_version; | |
212 | buf[7] = edns_do_bit ? 0x80 : 0; | |
213 | buf[8] = 0; | |
214 | gldns_write_uint16(buf + 9, opt_options_size); | |
215 | buf += 11; | |
216 | for (i = 0; i < noptions; i++) { | |
217 | if (getdns_list_get_dict(options, i, &option)) | |
218 | continue; | |
219 | if (getdns_dict_get_int( | |
220 | option, "option_code", &option_code)) | |
221 | continue; | |
222 | if (getdns_dict_get_bindata( | |
223 | option, "option_data", &option_data)) | |
224 | continue; | |
225 | ||
226 | gldns_write_uint16(buf, (uint16_t) option_code); | |
227 | gldns_write_uint16(buf + 2, | |
228 | (uint16_t) option_data->size); | |
229 | (void) memcpy(buf + 4, option_data->data, | |
230 | option_data->size); | |
231 | ||
232 | buf += option_data->size + 4; | |
233 | } | |
234 | } else | |
235 | net_req->opt = NULL; | |
236 | ||
237 | net_req->response = buf; | |
238 | gldns_write_uint16(net_req->wire_data, net_req->response - net_req->query); | |
239 | ||
207 | 240 | return r; |
208 | 241 | } |
209 | 242 | |
224 | 257 | gldns_write_uint16(req->query - 2, pktlen); |
225 | 258 | } |
226 | 259 | } |
260 | ||
261 | void | |
262 | _getdns_netreq_reinit(getdns_network_req *netreq) | |
263 | { | |
264 | uint8_t *base_opt_backup; | |
265 | size_t base_opt_rr_sz; | |
266 | ||
267 | if (!netreq->query) { | |
268 | (void) netreq_reset(netreq); | |
269 | return; | |
270 | ||
271 | } else if (!netreq->opt) { | |
272 | /* Remove TSIG (if any) */ | |
273 | gldns_write_uint16(netreq->query + GLDNS_ARCOUNT_OFF, 0); | |
274 | netreq->response = netreq_reset(netreq); | |
275 | gldns_write_uint16(netreq->wire_data, | |
276 | netreq->response - netreq->query); | |
277 | return; | |
278 | } | |
279 | _getdns_network_req_clear_upstream_options(netreq); | |
280 | base_opt_rr_sz = netreq->base_query_option_sz + 11; | |
281 | base_opt_backup = netreq->wire_data + netreq->wire_data_sz | |
282 | - base_opt_rr_sz; | |
283 | (void) memcpy(base_opt_backup, netreq->opt, base_opt_rr_sz); | |
284 | netreq->opt = netreq_reset(netreq); | |
285 | (void) memcpy(netreq->opt, base_opt_backup, base_opt_rr_sz); | |
286 | netreq->response = netreq->opt + base_opt_rr_sz; | |
287 | /* Remove TSIG (if any), but leave the opt RR */ | |
288 | gldns_write_uint16(netreq->query + GLDNS_ARCOUNT_OFF, 1); | |
289 | gldns_write_uint16(netreq->wire_data, | |
290 | netreq->response - netreq->query); | |
291 | } | |
292 | ||
227 | 293 | |
228 | 294 | /* add_upstream_option appends an option that is derived at send time. |
229 | 295 | (you can send data as NULL and it will fill with all zeros) */ |
248 | 314 | |
249 | 315 | /* no overflow allowed for OPT size either (maybe this is overkill |
250 | 316 | given the above check?) */ |
251 | oldlen = gldns_read_uint16(req->opt + 9); | |
317 | oldlen = gldns_read_uint16(req->opt + 9); | |
252 | 318 | newlen = oldlen + 4 + sz; |
253 | 319 | if (newlen > UINT16_MAX) |
254 | 320 | return GETDNS_RETURN_GENERIC_ERROR; |
276 | 342 | return GETDNS_RETURN_GOOD; |
277 | 343 | } |
278 | 344 | |
345 | size_t | |
346 | _getdns_network_req_add_tsig(getdns_network_req *req) | |
347 | { | |
348 | getdns_upstream *upstream = req->upstream; | |
349 | gldns_buffer gbuf; | |
350 | uint16_t arcount; | |
351 | const getdns_tsig_info *tsig_info; | |
352 | uint8_t md_buf[EVP_MAX_MD_SIZE]; | |
353 | unsigned int md_len = EVP_MAX_MD_SIZE; | |
354 | const EVP_MD *digester; | |
355 | ||
356 | /* Should only be called when in stub mode */ | |
357 | assert(req->query); | |
358 | ||
359 | if (upstream->tsig_alg == GETDNS_NO_TSIG || !upstream->tsig_dname_len) | |
360 | return req->response - req->query; | |
361 | ||
362 | arcount = gldns_read_uint16(req->query + 10); | |
363 | ||
364 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
365 | /* TSIG should not have been written yet. */ | |
366 | if (req->opt) { | |
367 | assert(arcount == 1); | |
368 | assert(req->opt + 11 + gldns_read_uint16(req->opt + 9) | |
369 | == req->response); | |
370 | } else | |
371 | assert(arcount == 0); | |
372 | #endif | |
373 | tsig_info = _getdns_get_tsig_info(upstream->tsig_alg); | |
374 | ||
375 | gldns_buffer_init_frm_data(&gbuf, req->response, MAXIMUM_TSIG_SPACE); | |
376 | gldns_buffer_write(&gbuf, | |
377 | upstream->tsig_dname, upstream->tsig_dname_len); /* Name */ | |
378 | gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */ | |
379 | gldns_buffer_write_u32(&gbuf, 0); /* TTL */ | |
380 | gldns_buffer_write(&gbuf, | |
381 | tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */ | |
382 | gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */ | |
383 | gldns_buffer_write_u16(&gbuf, 300); /* Fudge */ | |
384 | gldns_buffer_write_u16(&gbuf, 0); /* Error */ | |
385 | gldns_buffer_write_u16(&gbuf, 0); /* Other len */ | |
386 | ||
387 | switch (upstream->tsig_alg) { | |
388 | #ifdef HAVE_EVP_MD5 | |
389 | case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break; | |
390 | #endif | |
391 | #ifdef HAVE_EVP_SHA1 | |
392 | case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break; | |
393 | #endif | |
394 | #ifdef HAVE_EVP_SHA224 | |
395 | case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break; | |
396 | #endif | |
397 | #ifdef HAVE_EVP_SHA256 | |
398 | case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break; | |
399 | #endif | |
400 | #ifdef HAVE_EVP_SHA384 | |
401 | case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break; | |
402 | #endif | |
403 | #ifdef HAVE_EVP_SHA512 | |
404 | case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break; | |
405 | #endif | |
406 | default : return req->response - req->query; | |
407 | } | |
408 | ||
409 | (void) HMAC(digester, upstream->tsig_key, upstream->tsig_size, | |
410 | (void *)req->query, gldns_buffer_current(&gbuf) - req->query, | |
411 | md_buf, &md_len); | |
412 | ||
413 | gldns_buffer_rewind(&gbuf); | |
414 | gldns_buffer_write(&gbuf, | |
415 | upstream->tsig_dname, upstream->tsig_dname_len); /* Name */ | |
416 | gldns_buffer_write_u16(&gbuf, GETDNS_RRTYPE_TSIG); /* Type*/ | |
417 | gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */ | |
418 | gldns_buffer_write_u32(&gbuf, 0); /* TTL */ | |
419 | gldns_buffer_write_u16(&gbuf, | |
420 | tsig_info->dname_len + 10 + md_len + 6); /* RdLen */ | |
421 | gldns_buffer_write(&gbuf, | |
422 | tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */ | |
423 | gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */ | |
424 | gldns_buffer_write_u16(&gbuf, 300); /* Fudge */ | |
425 | gldns_buffer_write_u16(&gbuf, md_len); /* MAC Size */ | |
426 | gldns_buffer_write(&gbuf, md_buf, md_len); /* MAC*/ | |
427 | gldns_buffer_write(&gbuf, req->query, 2); /* Original ID */ | |
428 | gldns_buffer_write_u16(&gbuf, 0); /* Error */ | |
429 | gldns_buffer_write_u16(&gbuf, 0); /* Other len */ | |
430 | ||
431 | if (gldns_buffer_position(&gbuf) > gldns_buffer_limit(&gbuf)) | |
432 | return req->response - req->query; | |
433 | ||
434 | DEBUG_STUB("Sending with TSIG, mac length: %d\n", (int)md_len); | |
435 | req->tsig_status = GETDNS_DNSSEC_INSECURE; | |
436 | gldns_write_uint16(req->query + 10, arcount + 1); | |
437 | req->response = gldns_buffer_current(&gbuf); | |
438 | return req->response - req->query; | |
439 | } | |
440 | ||
441 | ||
442 | ||
443 | void | |
444 | _getdns_network_validate_tsig(getdns_network_req *req) | |
445 | { | |
446 | _getdns_rr_iter rr_spc, *rr; | |
447 | _getdns_rdf_iter rdf_spc, *rdf; | |
448 | const uint8_t *request_mac; | |
449 | uint16_t request_mac_len; | |
450 | uint8_t tsig_vars[MAXIMUM_TSIG_SPACE]; | |
451 | gldns_buffer gbuf; | |
452 | const uint8_t *dname; | |
453 | size_t dname_len; | |
454 | const uint8_t *response_mac; | |
455 | uint16_t response_mac_len; | |
456 | uint8_t other_len; | |
457 | uint8_t result_mac[EVP_MAX_MD_SIZE]; | |
458 | unsigned int result_mac_len = EVP_MAX_MD_SIZE; | |
459 | uint16_t original_id; | |
460 | const EVP_MD *digester; | |
461 | HMAC_CTX ctx; | |
462 | ||
463 | DEBUG_STUB("Validate TSIG\n"); | |
464 | for ( rr = _getdns_rr_iter_init(&rr_spc, req->query, | |
465 | (req->response - req->query)) | |
466 | ; rr | |
467 | ; rr = _getdns_rr_iter_next(rr)) { | |
468 | ||
469 | if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL && | |
470 | gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG) | |
471 | break; | |
472 | } | |
473 | if (!rr || !(rdf = _getdns_rdf_iter_init_at(&rdf_spc, rr, 3))) | |
474 | return; /* No good TSIG sent, so nothing expected on reply */ | |
475 | ||
476 | request_mac_len = gldns_read_uint16(rdf->pos); | |
477 | if (request_mac_len != rdf->nxt - rdf->pos - 2) | |
478 | return; | |
479 | DEBUG_STUB("Request MAC found length: %d\n", (int)(request_mac_len)); | |
480 | request_mac = rdf->pos + 2; | |
481 | ||
482 | /* Now we expect a TSIG on the response! */ | |
483 | req->tsig_status = GETDNS_DNSSEC_BOGUS; | |
484 | ||
485 | for ( rr = _getdns_rr_iter_init( | |
486 | &rr_spc, req->response, req->response_len) | |
487 | ; rr | |
488 | ; rr = _getdns_rr_iter_next(rr)) { | |
489 | ||
490 | if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL && | |
491 | gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG) | |
492 | break; | |
493 | } | |
494 | if (!rr || !(rdf = _getdns_rdf_iter_init(&rdf_spc, rr))) | |
495 | return; | |
496 | gldns_buffer_init_frm_data(&gbuf, tsig_vars, MAXIMUM_TSIG_SPACE); | |
497 | ||
498 | dname_len = gldns_buffer_remaining(&gbuf); | |
499 | if (!(dname = _getdns_owner_if_or_as_decompressed( | |
500 | rr, gldns_buffer_current(&gbuf), &dname_len))) | |
501 | return; | |
502 | if (dname == gldns_buffer_current(&gbuf)) | |
503 | gldns_buffer_skip(&gbuf, dname_len); | |
504 | else | |
505 | gldns_buffer_write(&gbuf, dname, dname_len); | |
506 | ||
507 | gldns_buffer_write(&gbuf, rr->rr_type + 2, 2); /* Class */ | |
508 | gldns_buffer_write(&gbuf, rr->rr_type + 4, 4); /* TTL */ | |
509 | ||
510 | dname_len = gldns_buffer_remaining(&gbuf); | |
511 | if (!(dname = _getdns_rdf_if_or_as_decompressed( | |
512 | rdf, gldns_buffer_current(&gbuf), &dname_len))) | |
513 | return; | |
514 | if (dname == gldns_buffer_current(&gbuf)) | |
515 | gldns_buffer_skip(&gbuf, dname_len); | |
516 | else | |
517 | gldns_buffer_write(&gbuf, dname, dname_len); | |
518 | ||
519 | if (!(rdf = _getdns_rdf_iter_next(rdf)) || | |
520 | rdf->nxt - rdf->pos != 6) | |
521 | return; | |
522 | gldns_buffer_write(&gbuf, rdf->pos, 6); /* Time Signed */ | |
523 | ||
524 | if (!(rdf = _getdns_rdf_iter_next(rdf)) || | |
525 | rdf->nxt - rdf->pos != 2) | |
526 | return; | |
527 | gldns_buffer_write(&gbuf, rdf->pos, 2); /* Fudge */ | |
528 | ||
529 | if (!(rdf = _getdns_rdf_iter_next(rdf))) /* mac */ | |
530 | return; | |
531 | response_mac_len = gldns_read_uint16(rdf->pos); | |
532 | if (response_mac_len != rdf->nxt - rdf->pos - 2) | |
533 | return; | |
534 | DEBUG_STUB("Response MAC found length: %d\n", (int)(response_mac_len)); | |
535 | response_mac = rdf->pos + 2; | |
536 | ||
537 | if (!(rdf = _getdns_rdf_iter_next(rdf)) || | |
538 | rdf->nxt -rdf->pos != 2) /* Original ID */ | |
539 | return; | |
540 | original_id = gldns_read_uint16(rdf->pos); | |
541 | ||
542 | if (!(rdf = _getdns_rdf_iter_next(rdf)) || | |
543 | rdf->nxt - rdf->pos != 2) | |
544 | return; | |
545 | gldns_buffer_write(&gbuf, rdf->pos, 2); /* Error */ | |
546 | ||
547 | if (!(rdf = _getdns_rdf_iter_next(rdf))) /* Other */ | |
548 | return; | |
549 | ||
550 | gldns_buffer_write_u16(&gbuf, 0); /* Other len */ | |
551 | other_len = gldns_read_uint16(rdf->pos); | |
552 | if (other_len != rdf->nxt - rdf->pos - 2) | |
553 | return; | |
554 | if (other_len) | |
555 | gldns_buffer_write(&gbuf, rdf->pos, other_len); | |
556 | ||
557 | /* TSIG found */ | |
558 | DEBUG_STUB("TSIG found, original ID: %d\n", (int)original_id); | |
559 | ||
560 | gldns_write_uint16(req->response + 10, | |
561 | gldns_read_uint16(req->response + 10) - 1); | |
562 | gldns_write_uint16(req->response, original_id); | |
563 | ||
564 | switch (req->upstream->tsig_alg) { | |
565 | #ifdef HAVE_EVP_MD5 | |
566 | case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break; | |
567 | #endif | |
568 | #ifdef HAVE_EVP_SHA1 | |
569 | case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break; | |
570 | #endif | |
571 | #ifdef HAVE_EVP_SHA224 | |
572 | case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break; | |
573 | #endif | |
574 | #ifdef HAVE_EVP_SHA256 | |
575 | case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break; | |
576 | #endif | |
577 | #ifdef HAVE_EVP_SHA384 | |
578 | case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break; | |
579 | #endif | |
580 | #ifdef HAVE_EVP_SHA512 | |
581 | case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break; | |
582 | #endif | |
583 | default : return; | |
584 | } | |
585 | ||
586 | HMAC_CTX_init(&ctx); | |
587 | (void) HMAC_Init_ex(&ctx, req->upstream->tsig_key, | |
588 | req->upstream->tsig_size, digester, NULL); | |
589 | (void) HMAC_Update(&ctx, request_mac - 2, request_mac_len + 2); | |
590 | (void) HMAC_Update(&ctx, req->response, rr->pos - req->response); | |
591 | (void) HMAC_Update(&ctx, tsig_vars, gldns_buffer_position(&gbuf)); | |
592 | HMAC_Final(&ctx, result_mac, &result_mac_len); | |
593 | ||
594 | DEBUG_STUB("Result MAC length: %d\n", (int)(result_mac_len)); | |
595 | if (result_mac_len == response_mac_len && | |
596 | memcmp(result_mac, response_mac, result_mac_len) == 0) | |
597 | req->tsig_status = GETDNS_DNSSEC_SECURE; | |
598 | ||
599 | HMAC_CTX_cleanup(&ctx); | |
600 | ||
601 | gldns_write_uint16(req->response, gldns_read_uint16(req->query)); | |
602 | gldns_write_uint16(req->response + 10, | |
603 | gldns_read_uint16(req->response + 10) + 1); | |
604 | } | |
605 | ||
279 | 606 | void |
280 | 607 | _getdns_dns_req_free(getdns_dns_req * req) |
281 | 608 | { |
298 | 625 | |
299 | 626 | GETDNS_FREE(req->my_mf, req); |
300 | 627 | } |
628 | ||
629 | static const uint8_t no_suffixes[] = { 1, 0 }; | |
301 | 630 | |
302 | 631 | /* create a new dns req to be submitted */ |
303 | 632 | getdns_dns_req * |
363 | 692 | * And align on the 8 byte boundry (hence the (x + 7) / 8 * 8) |
364 | 693 | */ |
365 | 694 | size_t max_query_sz, max_response_sz, netreq_sz, dnsreq_base_sz; |
366 | uint8_t *region; | |
695 | uint8_t *region, *suffixes; | |
367 | 696 | |
368 | 697 | if (extensions == dnssec_ok_checking_disabled || |
369 | 698 | extensions == dnssec_ok_checking_disabled_roadblock_avoidance || |
435 | 764 | ; |
436 | 765 | } |
437 | 766 | max_query_sz = ( GLDNS_HEADER_SIZE |
438 | + strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */ | |
767 | + 256 + 4 /* dname maximum 255 bytes (256 with mdns)*/ | |
439 | 768 | + 12 + opt_options_size /* space needed for OPT (if needed) */ |
440 | 769 | + MAXIMUM_UPSTREAM_OPTION_SPACE |
441 | /* TODO: TSIG */ | |
770 | + MAXIMUM_TSIG_SPACE | |
442 | 771 | + 7) / 8 * 8; |
443 | 772 | } |
444 | 773 | max_response_sz = (( edns_maximum_udp_payload_size != -1 |
450 | 779 | + max_query_sz + max_response_sz + 7 ) / 8 * 8; |
451 | 780 | dnsreq_base_sz = (( sizeof(getdns_dns_req) |
452 | 781 | + (a_aaaa_query ? 3 : 2) * sizeof(getdns_network_req*) |
782 | + context->suffixes_len | |
453 | 783 | ) + 7) / 8 * 8; |
454 | 784 | |
455 | 785 | if (! (region = GETDNS_XMALLOC(context->mf, uint8_t, |
466 | 796 | result->netreqs[1] = NULL; |
467 | 797 | |
468 | 798 | result->my_mf = context->mf; |
469 | ||
799 | ||
800 | suffixes = region + dnsreq_base_sz - context->suffixes_len; | |
801 | assert(context->suffixes); | |
802 | assert(context->suffixes_len); | |
803 | memcpy(suffixes, context->suffixes, context->suffixes_len); | |
804 | ||
805 | result->append_name = context->append_name; | |
806 | if (!strlen(name) || name[strlen(name)-1] == '.' || | |
807 | result->append_name == GETDNS_APPEND_NAME_NEVER) { | |
808 | /* Absolute query string, no appending */ | |
809 | result->suffix_len = no_suffixes[0]; | |
810 | result->suffix = no_suffixes + 1; | |
811 | result->suffix_appended = 1; | |
812 | } else { | |
813 | result->suffix_len = suffixes[0]; | |
814 | result->suffix = suffixes + 1; | |
815 | result->suffix_appended = 0; | |
816 | } | |
470 | 817 | result->name_len = sizeof(result->name); |
471 | 818 | if (gldns_str2wire_dname_buf(name, result->name, &result->name_len)) { |
472 | 819 | GETDNS_FREE(result->my_mf, result); |
473 | 820 | return NULL; |
821 | } | |
822 | if (result->append_name == GETDNS_APPEND_NAME_ALWAYS) { | |
823 | for ( | |
824 | ; result->suffix_len > 1 && *result->suffix | |
825 | ; result->suffix += result->suffix_len | |
826 | , result->suffix_len = *result->suffix++) { | |
827 | ||
828 | if (result->suffix_len + result->name_len - 1 < | |
829 | sizeof(result->name)) { | |
830 | memcpy(result->name + result->name_len - 1, | |
831 | result->suffix, result->suffix_len); | |
832 | result->name_len += result->suffix_len - 1; | |
833 | result->suffix_appended = 1; | |
834 | break; | |
835 | } | |
836 | } | |
837 | } else if (result->append_name == | |
838 | GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE && | |
839 | result->name[result->name[0]+1] != 0) { | |
840 | /* We have multiple labels, no appending */ | |
841 | result->suffix_len = no_suffixes[0]; | |
842 | result->suffix = no_suffixes + 1; | |
843 | result->suffix_appended = 1; | |
474 | 844 | } |
475 | 845 | result->context = context; |
476 | 846 | result->loop = loop; |
487 | 857 | #endif |
488 | 858 | result->edns_client_subnet_private = context->edns_client_subnet_private; |
489 | 859 | result->tls_query_padding_blocksize = context->tls_query_padding_blocksize; |
490 | result->return_call_debugging | |
491 | = is_extension_set(extensions, "return_call_debugging"); | |
860 | result->return_call_reporting = | |
861 | is_extension_set(extensions, "return_call_reporting"); | |
862 | result->add_warning_for_bad_dns = | |
863 | is_extension_set(extensions, "add_warning_for_bad_dns"); | |
492 | 864 | |
493 | 865 | /* will be set by caller */ |
494 | 866 | result->user_pointer = NULL; |
497 | 869 | |
498 | 870 | /* check the specify_class extension */ |
499 | 871 | (void) getdns_dict_get_int(extensions, "specify_class", &klass); |
872 | result->request_class = klass; | |
500 | 873 | |
501 | 874 | result->upstreams = context->upstreams; |
502 | 875 | if (result->upstreams) |
503 | 876 | result->upstreams->referenced++; |
504 | 877 | |
505 | 878 | network_req_init(result->netreqs[0], result, |
506 | name, request_type, klass, | |
507 | dnssec_extension_set, with_opt, | |
879 | request_type, dnssec_extension_set, with_opt, | |
508 | 880 | edns_maximum_udp_payload_size, |
509 | 881 | edns_extended_rcode, edns_version, edns_do_bit, |
510 | 882 | opt_options_size, noptions, options, |
511 | 883 | netreq_sz - sizeof(getdns_network_req), max_query_sz); |
512 | 884 | |
513 | 885 | if (a_aaaa_query) |
514 | network_req_init(result->netreqs[1], result, name, | |
886 | network_req_init(result->netreqs[1], result, | |
515 | 887 | ( request_type == GETDNS_RRTYPE_A |
516 | ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ), klass, | |
888 | ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ), | |
517 | 889 | dnssec_extension_set, with_opt, |
518 | 890 | edns_maximum_udp_payload_size, |
519 | 891 | edns_extended_rcode, edns_version, edns_do_bit, |
43 | 43 | #define ALEN(a) (sizeof(a)/sizeof(a[0])) |
44 | 44 | #define UNKNOWN_RDATA NULL |
45 | 45 | |
46 | static uint8_t * | |
47 | apl_n_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
46 | static const uint8_t * | |
47 | apl_n_rdf_end(const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
48 | 48 | { |
49 | 49 | return rdf < pkt_end ? rdf + 1 : NULL; |
50 | 50 | } |
51 | 51 | static getdns_return_t |
52 | apl_n_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
52 | apl_n_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
53 | 53 | { |
54 | 54 | return getdns_dict_set_int(dict, "n", (*rdf >> 7)); |
55 | 55 | } |
56 | 56 | static getdns_return_t |
57 | apl_n_list_append_value(getdns_list *list, uint8_t *rdf) | |
57 | apl_n_wire2list(getdns_list *list, const uint8_t *rdf) | |
58 | 58 | { |
59 | 59 | return _getdns_list_append_int(list, (*rdf >> 7)); |
60 | 60 | } |
61 | static getdns_return_t | |
62 | apl_n_2wire(uint32_t value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
63 | { | |
64 | (void)rdata; /* unused parameter */ | |
65 | ||
66 | if (*rdf_len < 1) { | |
67 | *rdf_len = 1; | |
68 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
69 | } | |
70 | *rdf_len = 1; | |
71 | *rdf = value ? 0x80 : 0x00; | |
72 | return GETDNS_RETURN_GOOD; | |
73 | } | |
74 | static getdns_return_t | |
75 | apl_n_dict2wire(const getdns_dict *dict, | |
76 | uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
77 | { | |
78 | getdns_return_t r; | |
79 | uint32_t value; | |
80 | ||
81 | if ((r = getdns_dict_get_int(dict, "n", &value))) | |
82 | return r; | |
83 | else | |
84 | return apl_n_2wire(value, rdata, rdf, rdf_len); | |
85 | } | |
86 | static getdns_return_t | |
87 | apl_n_list2wire(const getdns_list *list, size_t i, | |
88 | uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
89 | { | |
90 | getdns_return_t r; | |
91 | uint32_t value; | |
92 | ||
93 | if ((r = getdns_list_get_int(list, i, &value))) | |
94 | return r; | |
95 | else | |
96 | return apl_n_2wire(value, rdata, rdf, rdf_len); | |
97 | } | |
61 | 98 | static _getdns_rdf_special apl_n = { |
62 | apl_n_rdf_end, apl_n_dict_set_value, apl_n_list_append_value | |
99 | apl_n_rdf_end, | |
100 | apl_n_wire2dict, apl_n_wire2list, | |
101 | apl_n_dict2wire, apl_n_list2wire | |
63 | 102 | }; |
64 | 103 | |
65 | static uint8_t * | |
66 | apl_afdpart_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
67 | { | |
68 | uint8_t *end = rdf + (rdf[-1] & 0x7F); | |
104 | static const uint8_t * | |
105 | apl_afdpart_rdf_end( | |
106 | const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
107 | { | |
108 | const uint8_t *end = rdf + (rdf[-1] & 0x7F); | |
69 | 109 | return end <= pkt_end ? end : NULL; |
70 | 110 | } |
71 | 111 | static getdns_return_t |
72 | apl_afdpart_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
73 | { | |
74 | getdns_bindata bindata = { (rdf[-1] & 0x7F), rdf }; | |
75 | return getdns_dict_set_bindata(dict, "afdpart", &bindata); | |
76 | } | |
77 | static getdns_return_t | |
78 | apl_afdpart_list_append_value(getdns_list *list, uint8_t *rdf) | |
79 | { | |
80 | getdns_bindata bindata = { (rdf[-1] & 0x7F), rdf }; | |
81 | return _getdns_list_append_bindata(list, &bindata); | |
112 | apl_afdpart_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
113 | { | |
114 | return _getdns_dict_set_const_bindata( | |
115 | dict, "afdpart", (rdf[-1] & 0x7F), rdf); | |
116 | } | |
117 | static getdns_return_t | |
118 | apl_afdpart_wire2list(getdns_list *list, const uint8_t *rdf) | |
119 | { | |
120 | return _getdns_list_append_const_bindata(list, (rdf[-1] & 0x7F), rdf); | |
121 | } | |
122 | static getdns_return_t | |
123 | apl_afdpart_2wire( | |
124 | const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
125 | { | |
126 | if (value->size > 0x7F) | |
127 | return GETDNS_RETURN_INVALID_PARAMETER; | |
128 | ||
129 | if (rdf - 1 < rdata) | |
130 | return GETDNS_RETURN_GENERIC_ERROR; | |
131 | ||
132 | if (*rdf_len < value->size) { | |
133 | *rdf_len = value->size; | |
134 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
135 | } | |
136 | *rdf_len = value->size; | |
137 | ||
138 | /* Keeping first bit is safe because value->size <= 0x7F */ | |
139 | rdf[-1] |= value->size; | |
140 | ||
141 | (void) memcpy(rdf, value->data, value->size); | |
142 | return GETDNS_RETURN_GOOD; | |
143 | } | |
144 | static getdns_return_t | |
145 | apl_afdpart_dict2wire( | |
146 | const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
147 | { | |
148 | getdns_return_t r; | |
149 | getdns_bindata *value; | |
150 | ||
151 | if ((r = getdns_dict_get_bindata(dict, "afdpart", &value))) | |
152 | return r; | |
153 | else | |
154 | return apl_afdpart_2wire(value, rdata, rdf, rdf_len); | |
155 | } | |
156 | static getdns_return_t | |
157 | apl_afdpart_list2wire(const getdns_list *list, | |
158 | size_t i, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
159 | { | |
160 | getdns_return_t r; | |
161 | getdns_bindata *value; | |
162 | ||
163 | if ((r = getdns_list_get_bindata(list, i, &value))) | |
164 | return r; | |
165 | else | |
166 | return apl_afdpart_2wire(value, rdata, rdf, rdf_len); | |
82 | 167 | } |
83 | 168 | static _getdns_rdf_special apl_afdpart = { |
84 | 169 | apl_afdpart_rdf_end, |
85 | apl_afdpart_dict_set_value, apl_afdpart_list_append_value | |
170 | apl_afdpart_wire2dict, apl_afdpart_wire2list, | |
171 | apl_afdpart_dict2wire, apl_afdpart_list2wire | |
86 | 172 | }; |
87 | 173 | |
88 | static uint8_t * | |
89 | ipseckey_gateway_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
90 | { | |
91 | uint8_t *end; | |
174 | static const uint8_t * | |
175 | ipseckey_gateway_rdf_end( | |
176 | const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
177 | { | |
178 | const uint8_t *end; | |
92 | 179 | |
93 | 180 | if (rdf - 5 < pkt) |
94 | 181 | return NULL; |
115 | 202 | return end <= pkt_end ? end : NULL; |
116 | 203 | } |
117 | 204 | static getdns_return_t |
118 | ipseckey_gateway_equip_bindata(uint8_t *rdf, getdns_bindata *bindata) | |
119 | { | |
120 | bindata->data = rdf; | |
205 | ipseckey_gateway_equip_const_bindata( | |
206 | const uint8_t *rdf, size_t *size, const uint8_t **data) | |
207 | { | |
208 | *data = rdf; | |
121 | 209 | switch (rdf[-2]) { |
122 | case 0: bindata->size = 0; | |
210 | case 0: *size = 0; | |
123 | 211 | break; |
124 | case 1: bindata->size = 4; | |
212 | case 1: *size = 4; | |
125 | 213 | break; |
126 | case 2: bindata->size = 16; | |
214 | case 2: *size = 16; | |
127 | 215 | break; |
128 | 216 | case 3: while (*rdf) |
129 | 217 | if ((*rdf & 0xC0) == 0xC0) |
132 | 220 | return GETDNS_RETURN_GENERIC_ERROR; |
133 | 221 | else |
134 | 222 | rdf += *rdf + 1; |
135 | bindata->size = rdf + 1 - bindata->data; | |
223 | *size = rdf + 1 - *data; | |
136 | 224 | break; |
137 | 225 | default: |
138 | 226 | return GETDNS_RETURN_GENERIC_ERROR; |
139 | 227 | } |
140 | 228 | return GETDNS_RETURN_GOOD; |
141 | ||
142 | } | |
143 | static getdns_return_t | |
144 | ipseckey_gateway_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
145 | { | |
146 | getdns_bindata bindata; | |
147 | ||
148 | if (ipseckey_gateway_equip_bindata(rdf, &bindata)) | |
229 | } | |
230 | ||
231 | static getdns_return_t | |
232 | ipseckey_gateway_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
233 | { | |
234 | size_t size; | |
235 | const uint8_t *data; | |
236 | ||
237 | if (ipseckey_gateway_equip_const_bindata(rdf, &size, &data)) | |
149 | 238 | return GETDNS_RETURN_GENERIC_ERROR; |
150 | 239 | |
151 | else if (! bindata.size) | |
240 | else if (! size) | |
152 | 241 | return GETDNS_RETURN_GOOD; |
153 | 242 | else |
154 | return getdns_dict_set_bindata(dict, "gateway", &bindata); | |
155 | } | |
156 | static getdns_return_t | |
157 | ipseckey_gateway_list_append_value(getdns_list *list, uint8_t *rdf) | |
158 | { | |
159 | getdns_bindata bindata; | |
160 | ||
161 | if (ipseckey_gateway_equip_bindata(rdf, &bindata)) | |
243 | return _getdns_dict_set_const_bindata(dict, "gateway", size, data); | |
244 | } | |
245 | static getdns_return_t | |
246 | ipseckey_gateway_wire2list(getdns_list *list, const uint8_t *rdf) | |
247 | { | |
248 | size_t size; | |
249 | const uint8_t *data; | |
250 | ||
251 | if (ipseckey_gateway_equip_const_bindata(rdf, &size, &data)) | |
162 | 252 | return GETDNS_RETURN_GENERIC_ERROR; |
163 | 253 | |
164 | else if (! bindata.size) | |
254 | else if (!size) | |
165 | 255 | return GETDNS_RETURN_GOOD; |
166 | 256 | else |
167 | return _getdns_list_append_bindata(list, &bindata); | |
257 | return _getdns_list_append_const_bindata(list, size, data); | |
258 | } | |
259 | static getdns_return_t | |
260 | ipseckey_gateway_2wire( | |
261 | const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
262 | { | |
263 | if (rdf - 2 < rdata) | |
264 | return GETDNS_RETURN_GENERIC_ERROR; | |
265 | ||
266 | switch (rdf[-2]) { | |
267 | case 0: if (value && value->size > 0) | |
268 | return GETDNS_RETURN_INVALID_PARAMETER; | |
269 | break; | |
270 | case 1: if (!value || value->size != 4) | |
271 | return GETDNS_RETURN_INVALID_PARAMETER; | |
272 | if (*rdf_len < 4) { | |
273 | *rdf_len = 4; | |
274 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
275 | } | |
276 | *rdf_len = 4; | |
277 | (void)memcpy(rdf, value->data, 4); | |
278 | return GETDNS_RETURN_GOOD; | |
279 | case 2: if (!value || value->size != 16) | |
280 | return GETDNS_RETURN_INVALID_PARAMETER; | |
281 | if (*rdf_len < 16) { | |
282 | *rdf_len = 16; | |
283 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
284 | } | |
285 | *rdf_len = 16; | |
286 | (void)memcpy(rdf, value->data, 16); | |
287 | return GETDNS_RETURN_GOOD; | |
288 | case 3: if (!value || value->size == 0) | |
289 | return GETDNS_RETURN_INVALID_PARAMETER; | |
290 | /* Assume bindata is a valid dname; garbage in, garbage out */ | |
291 | if (*rdf_len < value->size) { | |
292 | *rdf_len = value->size; | |
293 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
294 | } | |
295 | *rdf_len = value->size; | |
296 | (void)memcpy(rdf, value->data, value->size); | |
297 | return GETDNS_RETURN_GOOD; | |
298 | default: | |
299 | return GETDNS_RETURN_GENERIC_ERROR; | |
300 | } | |
301 | return GETDNS_RETURN_GOOD; | |
302 | } | |
303 | static getdns_return_t | |
304 | ipseckey_gateway_dict2wire( | |
305 | const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
306 | { | |
307 | getdns_return_t r; | |
308 | getdns_bindata *value; | |
309 | ||
310 | if ((r = getdns_dict_get_bindata(dict, "gateway", &value))) | |
311 | return r; | |
312 | else | |
313 | return ipseckey_gateway_2wire(value, rdata, rdf, rdf_len); | |
314 | } | |
315 | static getdns_return_t | |
316 | ipseckey_gateway_list2wire(const getdns_list *list, | |
317 | size_t i, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
318 | { | |
319 | getdns_return_t r; | |
320 | getdns_bindata *value; | |
321 | ||
322 | if ((r = getdns_list_get_bindata(list, i, &value))) | |
323 | return r; | |
324 | else | |
325 | return ipseckey_gateway_2wire(value, rdata, rdf, rdf_len); | |
168 | 326 | } |
169 | 327 | static _getdns_rdf_special ipseckey_gateway = { |
170 | 328 | ipseckey_gateway_rdf_end, |
171 | ipseckey_gateway_dict_set_value, ipseckey_gateway_list_append_value | |
329 | ipseckey_gateway_wire2dict, ipseckey_gateway_wire2list, | |
330 | ipseckey_gateway_dict2wire, ipseckey_gateway_list2wire | |
172 | 331 | }; |
173 | 332 | |
174 | static uint8_t * | |
175 | hip_pk_algorithm_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
333 | static const uint8_t * | |
334 | hip_pk_algorithm_rdf_end( | |
335 | const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
176 | 336 | { |
177 | 337 | return rdf + 4 > pkt_end ? NULL |
178 | 338 | : rdf + 4 + *rdf + gldns_read_uint16(rdf + 2) > pkt_end ? NULL |
179 | 339 | : rdf + 1; |
180 | 340 | } |
181 | 341 | static getdns_return_t |
182 | hip_pk_algorithm_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
342 | hip_pk_algorithm_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
183 | 343 | { |
184 | 344 | return getdns_dict_set_int(dict, "pk_algorithm", rdf[1]); |
185 | 345 | } |
186 | 346 | static getdns_return_t |
187 | hip_pk_algorithm_list_append_value(getdns_list *list, uint8_t *rdf) | |
347 | hip_pk_algorithm_wire2list(getdns_list *list, const uint8_t *rdf) | |
188 | 348 | { |
189 | 349 | return _getdns_list_append_int(list, rdf[1]); |
350 | } | |
351 | static getdns_return_t | |
352 | hip_pk_algorithm_2wire(uint32_t value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
353 | { | |
354 | if (rdata != rdf) | |
355 | return GETDNS_RETURN_GENERIC_ERROR; | |
356 | if (value > 0xFF) | |
357 | return GETDNS_RETURN_INVALID_PARAMETER; | |
358 | if (*rdf_len < 4) { | |
359 | *rdf_len = 4; | |
360 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
361 | } | |
362 | *rdf_len = 4; | |
363 | rdata[1] = value; | |
364 | return GETDNS_RETURN_GOOD; | |
365 | } | |
366 | static getdns_return_t | |
367 | hip_pk_algorithm_dict2wire( | |
368 | const getdns_dict *dict,uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
369 | { | |
370 | getdns_return_t r; | |
371 | uint32_t value; | |
372 | ||
373 | if ((r = getdns_dict_get_int(dict, "pk_algorithm", &value))) | |
374 | return r; | |
375 | else | |
376 | return hip_pk_algorithm_2wire(value, rdata, rdf, rdf_len); | |
377 | } | |
378 | static getdns_return_t | |
379 | hip_pk_algorithm_list2wire(const getdns_list *list, | |
380 | size_t i, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
381 | { | |
382 | getdns_return_t r; | |
383 | uint32_t value; | |
384 | ||
385 | if ((r = getdns_list_get_int(list, i, &value))) | |
386 | return r; | |
387 | else | |
388 | return hip_pk_algorithm_2wire(value, rdata, rdf, rdf_len); | |
190 | 389 | } |
191 | 390 | static _getdns_rdf_special hip_pk_algorithm = { |
192 | 391 | hip_pk_algorithm_rdf_end, |
193 | hip_pk_algorithm_dict_set_value, hip_pk_algorithm_list_append_value | |
392 | hip_pk_algorithm_wire2dict, hip_pk_algorithm_wire2list, | |
393 | hip_pk_algorithm_dict2wire, hip_pk_algorithm_list2wire | |
194 | 394 | }; |
195 | 395 | |
196 | static uint8_t * | |
197 | hip_hit_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
396 | static const uint8_t * | |
397 | hip_hit_rdf_end(const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
198 | 398 | { |
199 | 399 | return rdf + 3 > pkt_end ? NULL |
200 | 400 | : rdf + 3 + rdf[-1] + gldns_read_uint16(rdf + 1) > pkt_end ? NULL |
201 | 401 | : rdf + 1; |
202 | 402 | } |
203 | 403 | static getdns_return_t |
204 | hip_hit_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
205 | { | |
206 | getdns_bindata bindata = { rdf[-1], rdf + 3 }; | |
207 | return getdns_dict_set_bindata(dict, "hit", &bindata); | |
208 | } | |
209 | static getdns_return_t | |
210 | hip_hit_list_append_value(getdns_list *list, uint8_t *rdf) | |
211 | { | |
212 | getdns_bindata bindata = { rdf[-1], rdf + 3 }; | |
213 | return _getdns_list_append_bindata(list, &bindata); | |
404 | hip_hit_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
405 | { | |
406 | return _getdns_dict_set_const_bindata(dict, "hit", rdf[-1], rdf + 3); | |
407 | } | |
408 | static getdns_return_t | |
409 | hip_hit_wire2list(getdns_list *list, const uint8_t *rdf) | |
410 | { | |
411 | return _getdns_list_append_const_bindata(list, rdf[-1], rdf + 3); | |
412 | } | |
413 | static getdns_return_t | |
414 | hip_hit_2wire( | |
415 | const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
416 | { | |
417 | if (rdata != rdf - 4) | |
418 | return GETDNS_RETURN_GENERIC_ERROR; | |
419 | if (value && value->size > 0xFF) | |
420 | return GETDNS_RETURN_INVALID_PARAMETER; | |
421 | if (!value || value->size == 0) { | |
422 | rdata[0] = 0; | |
423 | *rdf_len = 0; | |
424 | return GETDNS_RETURN_GOOD; | |
425 | } | |
426 | if (value->size > *rdf_len) { | |
427 | *rdf_len = value->size; | |
428 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
429 | } | |
430 | *rdf_len = value->size; | |
431 | rdata[0] = value->size; | |
432 | (void)memcpy(rdf, value->data, value->size); | |
433 | return GETDNS_RETURN_GOOD; | |
434 | } | |
435 | static getdns_return_t | |
436 | hip_hit_dict2wire( | |
437 | const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
438 | { | |
439 | getdns_return_t r; | |
440 | getdns_bindata *value; | |
441 | ||
442 | if ((r = getdns_dict_get_bindata(dict, "hit", &value))) | |
443 | return r; | |
444 | else | |
445 | return hip_hit_2wire(value, rdata, rdf, rdf_len); | |
446 | } | |
447 | static getdns_return_t | |
448 | hip_hit_list2wire(const getdns_list *list, | |
449 | size_t i, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
450 | { | |
451 | getdns_return_t r; | |
452 | getdns_bindata *value; | |
453 | ||
454 | if ((r = getdns_list_get_bindata(list, i, &value))) | |
455 | return r; | |
456 | else | |
457 | return hip_hit_2wire(value, rdata, rdf, rdf_len); | |
214 | 458 | } |
215 | 459 | static _getdns_rdf_special hip_hit = { |
216 | hip_hit_rdf_end, hip_hit_dict_set_value, hip_hit_list_append_value | |
460 | hip_hit_rdf_end, | |
461 | hip_hit_wire2dict, hip_hit_wire2list, | |
462 | hip_hit_dict2wire, hip_hit_list2wire | |
217 | 463 | }; |
218 | 464 | |
219 | static uint8_t * | |
220 | hip_public_key_rdf_end(uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf) | |
465 | static const uint8_t * | |
466 | hip_public_key_rdf_end( | |
467 | const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf) | |
221 | 468 | { |
222 | 469 | return rdf + 2 > pkt_end ? NULL |
223 | 470 | : rdf + 2 + rdf[-2] + gldns_read_uint16(rdf) > pkt_end ? NULL |
224 | 471 | : rdf + 2 + rdf[-2] + gldns_read_uint16(rdf); |
225 | 472 | } |
226 | 473 | static getdns_return_t |
227 | hip_public_key_dict_set_value(getdns_dict *dict, uint8_t *rdf) | |
228 | { | |
229 | getdns_bindata bindata = { gldns_read_uint16(rdf), rdf + 2 + rdf[-2] }; | |
230 | return getdns_dict_set_bindata(dict, "public_key", &bindata); | |
231 | } | |
232 | static getdns_return_t | |
233 | hip_public_key_list_append_value(getdns_list *list, uint8_t *rdf) | |
234 | { | |
235 | getdns_bindata bindata = { gldns_read_uint16(rdf), rdf + 2 + rdf[-2] }; | |
236 | return _getdns_list_append_bindata(list, &bindata); | |
474 | hip_public_key_wire2dict(getdns_dict *dict, const uint8_t *rdf) | |
475 | { | |
476 | return _getdns_dict_set_const_bindata( | |
477 | dict, "public_key", gldns_read_uint16(rdf), rdf + 2 + rdf[-2]); | |
478 | } | |
479 | static getdns_return_t | |
480 | hip_public_key_wire2list(getdns_list *list, const uint8_t *rdf) | |
481 | { | |
482 | return _getdns_list_append_const_bindata( | |
483 | list, gldns_read_uint16(rdf), rdf + 2 + rdf[-2]); | |
484 | } | |
485 | static getdns_return_t | |
486 | hip_public_key_2wire( | |
487 | const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
488 | { | |
489 | if (rdata > rdf - 4 || rdata + 4 + rdata[0] != rdf) | |
490 | return GETDNS_RETURN_GENERIC_ERROR; | |
491 | if (value && value->size > 0xFFFF) | |
492 | return GETDNS_RETURN_INVALID_PARAMETER; | |
493 | if (!value || value->size == 0) { | |
494 | rdata[2] = rdata[3] = 0; | |
495 | *rdf_len = 0; | |
496 | return GETDNS_RETURN_GOOD; | |
497 | } | |
498 | if (value->size > *rdf_len) { | |
499 | *rdf_len = value->size; | |
500 | return GETDNS_RETURN_NEED_MORE_SPACE; | |
501 | } | |
502 | *rdf_len = value->size; | |
503 | gldns_write_uint16(rdata + 2, value->size); | |
504 | (void)memcpy(rdf, value->data, value->size); | |
505 | return GETDNS_RETURN_GOOD; | |
506 | } | |
507 | static getdns_return_t | |
508 | hip_public_key_dict2wire( | |
509 | const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
510 | { | |
511 | getdns_return_t r; | |
512 | getdns_bindata *value; | |
513 | ||
514 | if ((r = getdns_dict_get_bindata(dict, "public_key", &value))) | |
515 | return r; | |
516 | else | |
517 | return hip_public_key_2wire(value, rdata, rdf, rdf_len); | |
518 | } | |
519 | static getdns_return_t | |
520 | hip_public_key_list2wire( | |
521 | const getdns_list *list, size_t i, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) | |
522 | { | |
523 | getdns_return_t r; | |
524 | getdns_bindata *value; | |
525 | ||
526 | if ((r = getdns_list_get_bindata(list, i, &value))) | |
527 | return r; | |
528 | else | |
529 | return hip_public_key_2wire(value, rdata, rdf, rdf_len); | |
237 | 530 | } |
238 | 531 | static _getdns_rdf_special hip_public_key = { |
239 | 532 | hip_public_key_rdf_end, |
240 | hip_public_key_dict_set_value, hip_public_key_list_append_value | |
533 | hip_public_key_wire2dict, hip_public_key_wire2list, | |
534 | hip_public_key_dict2wire, hip_public_key_list2wire | |
241 | 535 | }; |
242 | 536 | |
243 | 537 | |
740 | 1034 | return _getdns_rr_def_lookup(rr_type)->name; |
741 | 1035 | } |
742 | 1036 | |
1037 | static void | |
1038 | write_int_rdata(gldns_buffer *buf, _getdns_rdf_type type, uint32_t value) | |
1039 | { | |
1040 | size_t j; | |
1041 | ||
1042 | for (j = type & GETDNS_RDF_FIXEDSZ; j; j--) | |
1043 | gldns_buffer_write_u8(buf, | |
1044 | (uint8_t)(value >> (8 * (j - 1))) & 0xff); | |
1045 | } | |
1046 | ||
1047 | static void | |
1048 | write_bindata_rdata(gldns_buffer *buf, | |
1049 | _getdns_rdf_type type, getdns_bindata *bindata) | |
1050 | { | |
1051 | if (type & GETDNS_RDF_LEN_VAL) | |
1052 | write_int_rdata(buf, type >> 8, bindata->size); | |
1053 | ||
1054 | gldns_buffer_write(buf, bindata->data, bindata->size); | |
1055 | } | |
1056 | ||
1057 | ||
1058 | static getdns_return_t | |
1059 | write_rdata_field(gldns_buffer *buf, uint8_t *rdata_start, | |
1060 | const _getdns_rdata_def *rd_def, getdns_dict *rdata) | |
1061 | { | |
1062 | getdns_return_t r; | |
1063 | getdns_list *list; | |
1064 | uint32_t value; | |
1065 | getdns_bindata *bindata; | |
1066 | size_t i, rdf_len; | |
1067 | ||
1068 | if (rd_def->type & GETDNS_RDF_INTEGER) { | |
1069 | if (!(rd_def->type & GETDNS_RDF_REPEAT)) { | |
1070 | if ((r = getdns_dict_get_int( | |
1071 | rdata, rd_def->name, &value))) | |
1072 | return r; | |
1073 | else | |
1074 | write_int_rdata(buf, rd_def->type, value); | |
1075 | ||
1076 | } else if ((r = getdns_dict_get_list( | |
1077 | rdata, rd_def->name, &list))) | |
1078 | ||
1079 | return r == GETDNS_RETURN_NO_SUCH_DICT_NAME | |
1080 | ? GETDNS_RETURN_GOOD : r; | |
1081 | ||
1082 | else for ( i = 0 | |
1083 | ; GETDNS_RETURN_GOOD == | |
1084 | (r = getdns_list_get_int(list, i, &value)) | |
1085 | ; i++) | |
1086 | write_int_rdata(buf, rd_def->type, value); | |
1087 | ||
1088 | ||
1089 | } else if (rd_def->type & GETDNS_RDF_BINDATA) { | |
1090 | ||
1091 | ||
1092 | if (!(rd_def->type & GETDNS_RDF_REPEAT)) { | |
1093 | if ((r = getdns_dict_get_bindata( | |
1094 | rdata, rd_def->name, &bindata))) | |
1095 | return r; | |
1096 | else | |
1097 | write_bindata_rdata(buf, rd_def->type, bindata); | |
1098 | ||
1099 | } else if ((r = getdns_dict_get_list( | |
1100 | rdata, rd_def->name, &list))) | |
1101 | ||
1102 | return r == GETDNS_RETURN_NO_SUCH_DICT_NAME | |
1103 | ? GETDNS_RETURN_GOOD : r; | |
1104 | ||
1105 | else for ( i = 0 | |
1106 | ; GETDNS_RETURN_GOOD == | |
1107 | (r = getdns_list_get_bindata(list, i, &bindata)) | |
1108 | ; i++) | |
1109 | write_bindata_rdata(buf, rd_def->type, bindata); | |
1110 | ||
1111 | ||
1112 | } else if (!(rd_def->type & GETDNS_RDF_SPECIAL)) { | |
1113 | /* Unknown rdata type */ | |
1114 | return GETDNS_RETURN_GENERIC_ERROR; | |
1115 | ||
1116 | } else if (!(rd_def->type & GETDNS_RDF_REPEAT)) { | |
1117 | ||
1118 | rdf_len = gldns_buffer_remaining(buf); | |
1119 | r = rd_def->special->dict2wire(rdata, rdata_start, | |
1120 | gldns_buffer_current(buf), &rdf_len); | |
1121 | if (r == GETDNS_RETURN_GOOD || | |
1122 | r == GETDNS_RETURN_NEED_MORE_SPACE) | |
1123 | gldns_buffer_skip(buf, rdf_len); | |
1124 | if (r) | |
1125 | return r; | |
1126 | ||
1127 | } else if ((r = getdns_dict_get_list(rdata, rd_def->name, &list))) { | |
1128 | ||
1129 | return r == GETDNS_RETURN_NO_SUCH_DICT_NAME | |
1130 | ? GETDNS_RETURN_GOOD : r; | |
1131 | ||
1132 | } else for ( i = 0; r == GETDNS_RETURN_GOOD; i++ ) { | |
1133 | ||
1134 | rdf_len = gldns_buffer_remaining(buf); | |
1135 | r = rd_def->special->list2wire(list, i, rdata_start, | |
1136 | gldns_buffer_current(buf), &rdf_len); | |
1137 | if (r == GETDNS_RETURN_GOOD || | |
1138 | r == GETDNS_RETURN_NEED_MORE_SPACE) | |
1139 | gldns_buffer_skip(buf, rdf_len); | |
1140 | } | |
1141 | ||
1142 | return r != GETDNS_RETURN_NO_SUCH_LIST_ITEM ? r : GETDNS_RETURN_GOOD; | |
1143 | } | |
1144 | ||
743 | 1145 | getdns_return_t |
744 | _getdns_rr_dict2wire(getdns_dict *rr_dict, gldns_buffer *buf) | |
1146 | _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf) | |
745 | 1147 | { |
746 | 1148 | getdns_return_t r = GETDNS_RETURN_GOOD; |
747 | struct getdns_bindata *name; | |
748 | struct getdns_bindata *rdata_raw; | |
749 | struct getdns_bindata *bindata; | |
750 | struct getdns_dict *rdata; | |
1149 | getdns_bindata *name; | |
1150 | getdns_bindata *rdata_raw; | |
1151 | getdns_dict *rdata; | |
751 | 1152 | uint32_t rr_type; |
752 | 1153 | uint32_t rr_class = GETDNS_RRCLASS_IN; |
753 | 1154 | uint32_t rr_ttl = 0; |
754 | uint32_t value; | |
755 | 1155 | const _getdns_rr_def *rr_def; |
756 | const _getdns_rdata_def *rd_def; | |
757 | int n_rdata_fields; | |
758 | size_t j, rdata_size_mark; | |
1156 | const _getdns_rdata_def *rd_def, *rep_rd_def; | |
1157 | int n_rdata_fields, rep_n_rdata_fields; | |
1158 | size_t rdata_size_mark; | |
1159 | uint8_t *rdata_start; | |
1160 | getdns_list *list; | |
1161 | size_t i; | |
759 | 1162 | |
760 | 1163 | assert(rr_dict); |
761 | 1164 | assert(buf); |
762 | 1165 | |
763 | 1166 | if ((r = getdns_dict_get_bindata(rr_dict, "name", &name))) |
764 | goto error; | |
1167 | return r; | |
765 | 1168 | gldns_buffer_write(buf, name->data, name->size); |
766 | 1169 | |
767 | 1170 | if ((r = getdns_dict_get_int(rr_dict, "type", &rr_type))) |
768 | goto error; | |
1171 | return r; | |
769 | 1172 | gldns_buffer_write_u16(buf, (uint16_t)rr_type); |
770 | 1173 | |
771 | 1174 | (void) getdns_dict_get_int(rr_dict, "class", &rr_class); |
786 | 1189 | break; |
787 | 1190 | } |
788 | 1191 | |
789 | if ((r = getdns_dict_get_dict(rr_dict, "rdata", &rdata))) | |
790 | goto error; | |
791 | ||
792 | if (n_rdata_fields == 0 && GETDNS_RETURN_GOOD == | |
1192 | if ((r = getdns_dict_get_dict(rr_dict, "rdata", &rdata))) { | |
1193 | if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME) { | |
1194 | gldns_buffer_write_u16(buf, 0); | |
1195 | r = GETDNS_RETURN_GOOD; | |
1196 | } | |
1197 | ||
1198 | } else if (n_rdata_fields == 0 && GETDNS_RETURN_GOOD == | |
793 | 1199 | (r = getdns_dict_get_bindata(rdata, "rdata_raw", &rdata_raw))) { |
794 | 1200 | |
795 | 1201 | gldns_buffer_write_u16(buf, (uint16_t)rdata_raw->size); |
797 | 1203 | |
798 | 1204 | } else if (n_rdata_fields || r == GETDNS_RETURN_NO_SUCH_DICT_NAME) { |
799 | 1205 | |
1206 | r = GETDNS_RETURN_GOOD; | |
800 | 1207 | rdata_size_mark = gldns_buffer_position(buf); |
801 | 1208 | gldns_buffer_skip(buf, 2); |
1209 | rdata_start = gldns_buffer_current(buf); | |
802 | 1210 | |
803 | 1211 | for ( rd_def = rr_def->rdata |
804 | 1212 | , n_rdata_fields = rr_def->n_rdata_fields |
805 | 1213 | ; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) { |
806 | 1214 | |
807 | if (rd_def->type & GETDNS_RDF_BINDATA) { | |
808 | if ((r = getdns_dict_get_bindata(rdata, | |
809 | rd_def->name, &bindata))) | |
810 | break; | |
811 | ||
812 | gldns_buffer_write(buf, bindata->data | |
813 | , bindata->size ); | |
814 | continue; | |
815 | } | |
816 | if (!(rd_def->type & GETDNS_RDF_INTEGER)) { | |
817 | r = GETDNS_RETURN_GENERIC_ERROR; | |
1215 | if (rd_def->type == GETDNS_RDF_REPEAT) | |
1216 | break; | |
1217 | ||
1218 | if ((r = write_rdata_field(buf, | |
1219 | rdata_start, rd_def, rdata))) | |
1220 | break; | |
1221 | } | |
1222 | if (n_rdata_fields == 0 || r) { | |
1223 | /* pass */; | |
1224 | ||
1225 | } else if ((r = getdns_dict_get_list( | |
1226 | rdata, rd_def->name, &list))) { | |
1227 | /* pass */; | |
1228 | ||
1229 | } else for ( i = 0 | |
1230 | ; r == GETDNS_RETURN_GOOD | |
1231 | ; i++) { | |
1232 | ||
1233 | if ((r = getdns_list_get_dict(list, i, &rdata))) { | |
1234 | if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) | |
1235 | r = GETDNS_RETURN_GOOD; | |
818 | 1236 | break; |
819 | 1237 | } |
820 | if ((r = getdns_dict_get_int( | |
821 | rdata, rd_def->name, &value))) | |
822 | break; | |
823 | ||
824 | for (j = rd_def->type & GETDNS_RDF_FIXEDSZ; j; j--) | |
825 | gldns_buffer_write_u8(buf, | |
826 | (uint8_t)(value >> (8 * (j - 1))) & 0xff); | |
1238 | for ( rep_rd_def = rd_def + 1 | |
1239 | , rep_n_rdata_fields = n_rdata_fields - 1 | |
1240 | ; rep_n_rdata_fields | |
1241 | ; rep_n_rdata_fields--, rep_rd_def++ ) { | |
1242 | ||
1243 | if ((r = write_rdata_field(buf, | |
1244 | rdata_start, rep_rd_def, rdata))) | |
1245 | break; | |
1246 | } | |
827 | 1247 | } |
828 | 1248 | gldns_buffer_write_u16_at(buf, rdata_size_mark, |
829 | 1249 | (uint16_t)(gldns_buffer_position(buf)-rdata_size_mark-2)); |
830 | 1250 | } |
831 | error: | |
832 | 1251 | return r; |
833 | 1252 | } |
834 | 1253 |
35 | 35 | #include "getdns/getdns.h" |
36 | 36 | #include "gldns/gbuffer.h" |
37 | 37 | |
38 | typedef uint8_t *(*_getdns_rdf_end_t)( | |
39 | uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf); | |
38 | /* rdf_end returns a pointer to the end of this rdf's data, | |
39 | * i.e. where the next rdata field will start. | |
40 | */ | |
41 | typedef const uint8_t *(*_getdns_rdf_end_t)( | |
42 | const uint8_t *pkt, const uint8_t *pkt_end, const uint8_t *rdf); | |
40 | 43 | /* Limit checks are already done with _getdns_rdf_end_t */ |
41 | typedef getdns_return_t (*_getdns_rdf_dict_set_value_t)( | |
42 | getdns_dict *dict, uint8_t *rdf); | |
43 | typedef getdns_return_t (*_getdns_rdf_list_append_value_t)( | |
44 | getdns_list *list, uint8_t *rdf); | |
44 | typedef getdns_return_t (*_getdns_rdf_wire2dict_t)( | |
45 | getdns_dict *dict, const uint8_t *rdf); | |
46 | typedef getdns_return_t (*_getdns_rdf_wire2list_t)( | |
47 | getdns_list *list, const uint8_t *rdf); | |
48 | typedef getdns_return_t (*_getdns_rdf_dict2wire_t)( | |
49 | const getdns_dict *dict, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len); | |
50 | typedef getdns_return_t (*_getdns_rdf_list2wire_t)( | |
51 | const getdns_list *list, size_t index, | |
52 | uint8_t *rdata, uint8_t *rdf, size_t *rdf_len); | |
45 | 53 | |
46 | 54 | typedef struct _getdns_rdf_special { |
47 | _getdns_rdf_end_t rdf_end; | |
48 | _getdns_rdf_dict_set_value_t dict_set_value; | |
49 | _getdns_rdf_list_append_value_t list_append_value; | |
55 | _getdns_rdf_end_t rdf_end; | |
56 | _getdns_rdf_wire2dict_t wire2dict; | |
57 | _getdns_rdf_wire2list_t wire2list; | |
58 | _getdns_rdf_dict2wire_t dict2wire; | |
59 | _getdns_rdf_list2wire_t list2wire; | |
50 | 60 | } _getdns_rdf_special; |
51 | 61 | |
52 | 62 | /* draft-levine-dnsextlang'ish type rr and rdata definitions */ |
119 | 129 | } _getdns_rdf_type; |
120 | 130 | |
121 | 131 | typedef struct _getdns_rdata_def { |
122 | const char *name; | |
132 | const char *name; | |
123 | 133 | _getdns_rdf_type type; |
124 | 134 | _getdns_rdf_special *special; |
125 | 135 | } _getdns_rdata_def; |
126 | 136 | |
127 | 137 | typedef struct _getdns_rr_def { |
128 | const char *name; | |
138 | const char *name; | |
129 | 139 | const _getdns_rdata_def *rdata; |
130 | int n_rdata_fields; | |
140 | int n_rdata_fields; | |
131 | 141 | } _getdns_rr_def; |
132 | 142 | |
133 | 143 | const _getdns_rr_def *_getdns_rr_def_lookup(uint16_t rr_type); |
134 | 144 | |
135 | 145 | getdns_return_t _getdns_rr_dict2wire( |
136 | getdns_dict *rr_dict, gldns_buffer *buf); | |
146 | const getdns_dict *rr_dict, gldns_buffer *buf); | |
137 | 147 | |
138 | 148 | const char *_getdns_rr_type_name(int rr_type); |
139 | 149 |
38 | 38 | assert(i); |
39 | 39 | assert(i->rr_type); |
40 | 40 | |
41 | i->nxt = i->n < GLDNS_QDCOUNT(i->pkt) | |
41 | i->nxt = i->pkt && i->n < GLDNS_QDCOUNT(i->pkt) | |
42 | 42 | ? i->rr_type + 4 |
43 | 43 | : i->rr_type + 10 > i->pkt_end |
44 | 44 | ? i->pkt_end |
50 | 50 | static _getdns_rr_iter * |
51 | 51 | find_rrtype(_getdns_rr_iter *i) |
52 | 52 | { |
53 | uint8_t *pos; | |
53 | const uint8_t *pos; | |
54 | 54 | |
55 | 55 | assert(i); |
56 | 56 | assert(i->pos); |
57 | 57 | |
58 | 58 | /* Past the last RR in the pkt */ |
59 | if (GLDNS_QDCOUNT(i->pkt) + GLDNS_ANCOUNT(i->pkt) + | |
59 | if (i->pkt && | |
60 | GLDNS_QDCOUNT(i->pkt) + GLDNS_ANCOUNT(i->pkt) + | |
60 | 61 | GLDNS_NSCOUNT(i->pkt) + GLDNS_ARCOUNT(i->pkt) <= i->n) |
61 | 62 | goto done; |
62 | 63 | |
82 | 83 | } |
83 | 84 | |
84 | 85 | _getdns_rr_iter * |
85 | _getdns_rr_iter_init(_getdns_rr_iter *i, uint8_t *pkt, size_t pkt_len) | |
86 | _getdns_rr_iter_init(_getdns_rr_iter *i, const uint8_t *pkt, size_t pkt_len) | |
86 | 87 | { |
87 | 88 | assert(i); |
88 | 89 | |
99 | 100 | } |
100 | 101 | |
101 | 102 | _getdns_rr_iter * |
103 | _getdns_single_rr_iter_init( | |
104 | _getdns_rr_iter *i, const uint8_t *wire, size_t wire_len) | |
105 | { | |
106 | assert(i); | |
107 | ||
108 | if (!wire || wire_len < 5 /* name + type + class */) { | |
109 | i->pos = NULL; | |
110 | return NULL; | |
111 | } | |
112 | i->pkt = NULL; | |
113 | i->pos = wire; | |
114 | i->pkt_end = wire + wire_len; | |
115 | i->n = 0; | |
116 | ||
117 | return find_rrtype(i); | |
118 | } | |
119 | ||
120 | ||
121 | _getdns_rr_iter * | |
102 | 122 | _getdns_rr_iter_rewind(_getdns_rr_iter *i) |
103 | 123 | { |
104 | 124 | assert(i); |
120 | 140 | return find_rrtype(i); |
121 | 141 | } |
122 | 142 | |
123 | static uint8_t * | |
124 | dname_if_or_as_decompressed(uint8_t *pkt, uint8_t *pkt_end, uint8_t *pos, | |
125 | uint8_t *buf, size_t *len, size_t refs) | |
143 | static const uint8_t * | |
144 | dname_if_or_as_decompressed(const uint8_t *pkt, const uint8_t *pkt_end, | |
145 | const uint8_t *pos, uint8_t *buf, size_t *len, size_t refs) | |
126 | 146 | { |
127 | 147 | uint16_t offset; |
128 | uint8_t *start, *dst; | |
129 | ||
130 | assert(pkt); | |
148 | const uint8_t *start; | |
149 | uint8_t *dst; | |
150 | ||
131 | 151 | assert(pkt_end); |
132 | 152 | assert(pos); |
133 | 153 | assert(buf); |
137 | 157 | goto error; |
138 | 158 | |
139 | 159 | if ((*pos & 0xC0) == 0xC0) { |
140 | if (pos + 1 >= pkt_end) | |
160 | if (!pkt || pos + 1 >= pkt_end) | |
141 | 161 | goto error; |
142 | 162 | offset = gldns_read_uint16(pos) & 0x3FFF; |
143 | 163 | if (pkt + offset >= pkt_end) |
174 | 194 | start = pos; |
175 | 195 | } |
176 | 196 | if ((*pos & 0xC0) == 0xC0) { |
177 | if (pos + 1 >= pkt_end) | |
197 | if (!pkt || pos + 1 >= pkt_end) | |
178 | 198 | goto error; |
179 | 199 | offset = gldns_read_uint16(pos) & 0x3FFF; |
180 | 200 | if (pkt + offset >= pkt_end) |
203 | 223 | return NULL; |
204 | 224 | } |
205 | 225 | |
206 | uint8_t * | |
226 | const uint8_t * | |
207 | 227 | _getdns_owner_if_or_as_decompressed(_getdns_rr_iter *i, |
208 | 228 | uint8_t *ff_bytes, size_t *len) |
209 | 229 | { |
214 | 234 | static _getdns_rdf_iter * |
215 | 235 | rdf_iter_find_nxt(_getdns_rdf_iter *i) |
216 | 236 | { |
217 | uint8_t *pos; | |
237 | const uint8_t *pos; | |
218 | 238 | |
219 | 239 | assert(i); |
220 | 240 | assert(i->pos); |
278 | 298 | |
279 | 299 | i->end = NULL; |
280 | 300 | /* rr_iter already done or in question section */ |
281 | if (!rr->pos || rr->n < GLDNS_QDCOUNT(rr->pkt)) | |
301 | if (!rr->pos || _getdns_rr_iter_section(rr) == GLDNS_SECTION_QUESTION) | |
282 | 302 | goto done; |
283 | 303 | |
284 | 304 | i->pkt = rr->pkt; |
333 | 353 | return i; |
334 | 354 | } |
335 | 355 | |
336 | uint8_t * | |
356 | const uint8_t * | |
337 | 357 | _getdns_rdf_if_or_as_decompressed( |
338 | 358 | _getdns_rdf_iter *i, uint8_t *ff_bytes, size_t *len) |
339 | 359 | { |
37 | 37 | #include "gldns/gbuffer.h" |
38 | 38 | |
39 | 39 | typedef struct _getdns_rr_iter { |
40 | uint8_t *pkt; | |
41 | uint8_t *pkt_end; | |
40 | const uint8_t *pkt; | |
41 | const uint8_t *pkt_end; | |
42 | 42 | |
43 | 43 | /* Which RR are we currently at */ |
44 | 44 | size_t n; |
46 | 46 | /* pos points to start of the owner name the RR. |
47 | 47 | * Or is NULL when there are no RR's left. |
48 | 48 | */ |
49 | uint8_t *pos; | |
49 | const uint8_t *pos; | |
50 | 50 | |
51 | 51 | /* rr_type will point to the rr_type right after the RR's owner name. |
52 | 52 | * rr_type is guaranteed to have a value when pos has a value |
53 | 53 | */ |
54 | uint8_t *rr_type; | |
54 | const uint8_t *rr_type; | |
55 | 55 | |
56 | 56 | /* nxt point to the owner name of the next RR or to pkt_end */ |
57 | uint8_t *nxt; | |
57 | const uint8_t *nxt; | |
58 | 58 | |
59 | 59 | } _getdns_rr_iter; |
60 | 60 | |
61 | 61 | _getdns_rr_iter *_getdns_rr_iter_init(_getdns_rr_iter *i, |
62 | uint8_t *pkt, size_t pkt_len); | |
62 | const uint8_t *pkt, const size_t pkt_len); | |
63 | ||
64 | _getdns_rr_iter *_getdns_single_rr_iter_init(_getdns_rr_iter *i, | |
65 | const uint8_t *wire, const size_t wire_len); | |
63 | 66 | |
64 | 67 | _getdns_rr_iter *_getdns_rr_iter_rewind(_getdns_rr_iter *i); |
65 | 68 | |
66 | 69 | _getdns_rr_iter *_getdns_rr_iter_next(_getdns_rr_iter *i); |
67 | 70 | |
68 | uint8_t *_getdns_owner_if_or_as_decompressed( | |
71 | const uint8_t *_getdns_owner_if_or_as_decompressed( | |
69 | 72 | _getdns_rr_iter *i, uint8_t *ff_bytes, size_t *len); |
70 | 73 | |
71 | 74 | static inline gldns_pkt_section |
72 | 75 | _getdns_rr_iter_section(_getdns_rr_iter *i) |
73 | 76 | { |
74 | return i->n < GLDNS_QDCOUNT(i->pkt) ? GLDNS_SECTION_QUESTION | |
77 | return !i->pkt ? (i->nxt - i->rr_type == 4 ? GLDNS_SECTION_QUESTION | |
78 | : GLDNS_SECTION_ANSWER ) | |
79 | : i->n < GLDNS_QDCOUNT(i->pkt) ? GLDNS_SECTION_QUESTION | |
75 | 80 | : i->n < GLDNS_QDCOUNT(i->pkt) |
76 | 81 | + GLDNS_ANCOUNT(i->pkt) ? GLDNS_SECTION_ANSWER |
77 | 82 | : i->n < GLDNS_QDCOUNT(i->pkt) |
85 | 90 | } |
86 | 91 | |
87 | 92 | typedef struct piv_getdns_rdf_iter { |
88 | uint8_t *pkt; | |
89 | uint8_t *pkt_end; | |
93 | const uint8_t *pkt; | |
94 | const uint8_t *pkt_end; | |
90 | 95 | const _getdns_rdata_def *rdd_pos; |
91 | 96 | const _getdns_rdata_def *rdd_end; |
92 | 97 | const _getdns_rdata_def *rdd_repeat; |
93 | uint8_t *pos; | |
94 | uint8_t *end; | |
95 | uint8_t *nxt; | |
98 | const uint8_t *pos; | |
99 | const uint8_t *end; | |
100 | const uint8_t *nxt; | |
96 | 101 | } _getdns_rdf_iter; |
97 | 102 | |
98 | 103 | _getdns_rdf_iter *_getdns_rdf_iter_init(_getdns_rdf_iter *i, |
103 | 108 | _getdns_rdf_iter *_getdns_rdf_iter_init_at(_getdns_rdf_iter *i, |
104 | 109 | _getdns_rr_iter *rr, size_t pos); |
105 | 110 | |
106 | uint8_t *_getdns_rdf_if_or_as_decompressed( | |
111 | const uint8_t *_getdns_rdf_if_or_as_decompressed( | |
107 | 112 | _getdns_rdf_iter *i, uint8_t *ff_bytes, size_t *len); |
108 | 113 | |
109 | 114 | #endif |
30 | 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | 31 | */ |
32 | 32 | |
33 | #include "config.h" | |
34 | #include "debug.h" | |
33 | 35 | #include <openssl/err.h> |
34 | 36 | #include <openssl/conf.h> |
35 | 37 | #include <openssl/x509v3.h> |
36 | #include "config.h" | |
37 | 38 | #include <fcntl.h> |
38 | 39 | #include "stub.h" |
39 | 40 | #include "gldns/gbuffer.h" |
40 | 41 | #include "gldns/pkthdr.h" |
41 | 42 | #include "gldns/rrdef.h" |
42 | 43 | #include "gldns/str2wire.h" |
44 | #include "gldns/wire2str.h" | |
43 | 45 | #include "rr-iter.h" |
44 | 46 | #include "context.h" |
45 | 47 | #include "util-internal.h" |
46 | 48 | #include "general.h" |
49 | #include "pubkey-pinning.h" | |
50 | ||
51 | #ifdef USE_WINSOCK | |
52 | #define EINPROGRESS 112 | |
53 | #define EWOULDBLOCK 140 | |
54 | typedef u_short sa_family_t; | |
55 | #include "util/winsock_event.h" | |
56 | #endif | |
47 | 57 | |
48 | 58 | #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ |
49 | 59 | #define STUB_TLS_SETUP_ERROR -4 |
52 | 62 | |
53 | 63 | /* Don't currently have access to the context whilst doing handshake */ |
54 | 64 | #define TIMEOUT_TLS 2500 |
65 | /* Arbritray number of message for EDNS keepalive resend*/ | |
66 | #define EDNS_KEEPALIVE_RESEND 5 | |
55 | 67 | |
56 | 68 | static time_t secret_rollover_time = 0; |
57 | 69 | static uint32_t secret = 0; |
73 | 85 | static void netreq_upstream_write_cb(void *userarg); |
74 | 86 | static int fallback_on_write(getdns_network_req *netreq); |
75 | 87 | |
76 | static void stub_tcp_write_cb(void *userarg); | |
77 | 88 | static void stub_timeout_cb(void *userarg); |
78 | 89 | /*****************************/ |
79 | 90 | /* General utility functions */ |
144 | 155 | } |
145 | 156 | |
146 | 157 | static getdns_return_t |
158 | attach_edns_keepalive(getdns_network_req *req) | |
159 | { | |
160 | /* Client always sends length 0, omits the timeout */ | |
161 | return _getdns_network_req_add_upstream_option(req, | |
162 | GLDNS_EDNS_KEEPALIVE, | |
163 | 0, NULL); | |
164 | } | |
165 | ||
166 | static getdns_return_t | |
147 | 167 | attach_edns_cookie(getdns_network_req *req) |
148 | 168 | { |
149 | 169 | getdns_upstream *upstream = req->upstream; |
181 | 201 | |
182 | 202 | } |
183 | 203 | |
204 | /* Will find a matching OPT RR, but leaves the caller to validate it*/ | |
184 | 205 | static int |
185 | match_and_process_server_cookie( | |
186 | getdns_upstream *upstream, uint8_t *response, size_t response_len) | |
206 | match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len, | |
207 | const uint8_t **position, uint16_t *option_len) | |
187 | 208 | { |
188 | 209 | _getdns_rr_iter rr_iter_storage, *rr_iter; |
189 | uint8_t *pos; | |
210 | const uint8_t *pos; | |
190 | 211 | uint16_t rdata_len, opt_code = 0, opt_len = 0; |
191 | 212 | |
192 | 213 | /* Search for the OPT RR (if any) */ |
209 | 230 | |
210 | 231 | pos = rr_iter->rr_type + 8; |
211 | 232 | |
212 | /* OPT found, now search for the cookie option */ | |
233 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
234 | char str_spc[8192], *str = str_spc; | |
235 | size_t str_len = sizeof(str_spc); | |
236 | uint8_t *data = (uint8_t *)rr_iter->pos; | |
237 | size_t data_len = rr_iter->nxt - rr_iter->pos; | |
238 | (void) gldns_wire2str_rr_scan( | |
239 | &data, &data_len, &str, &str_len, (uint8_t *)rr_iter->pkt, rr_iter->pkt_end - rr_iter->pkt); | |
240 | DEBUG_STUB("OPT RR: %s", str_spc); | |
241 | #endif | |
242 | ||
243 | /* OPT found, now search for the specified option */ | |
213 | 244 | if (pos + 2 > rr_iter->nxt) |
214 | 245 | return 1; /* FORMERR */ |
215 | 246 | |
222 | 253 | opt_len = gldns_read_uint16(pos); pos += 2; |
223 | 254 | if (pos + opt_len > rr_iter->nxt) |
224 | 255 | return 1; /* FORMERR */ |
225 | if (opt_code == EDNS_COOKIE_OPCODE) | |
256 | if (opt_code == code) | |
226 | 257 | break; |
227 | 258 | pos += opt_len; /* Skip unknown options */ |
228 | 259 | } |
229 | if (pos >= rr_iter->nxt || opt_code != EDNS_COOKIE_OPCODE) | |
260 | if (pos >= rr_iter->nxt || opt_code != code) | |
230 | 261 | return 0; /* Everything OK, just no cookie found. */ |
231 | ||
232 | if (opt_len < 16 || opt_len > 40) | |
262 | *position = pos; | |
263 | *option_len = opt_len; | |
264 | return 2; | |
265 | } | |
266 | ||
267 | /* TODO: Test combinations of EDNS0 options*/ | |
268 | static int | |
269 | match_and_process_server_cookie( | |
270 | getdns_upstream *upstream, uint8_t *response, size_t response_len) | |
271 | { | |
272 | const uint8_t *position = NULL; | |
273 | uint16_t option_len = 0; | |
274 | int found = match_edns_opt_rr(EDNS_COOKIE_OPCODE, response, | |
275 | response_len, &position, &option_len); | |
276 | if (found != 2) | |
277 | return found; | |
278 | ||
279 | if (option_len < 16 || option_len > 40) | |
233 | 280 | return 1; /* FORMERR */ |
234 | 281 | |
235 | 282 | if (!upstream->has_client_cookie) |
236 | 283 | return 1; /* Cookie reply, but we didn't sent one */ |
237 | 284 | |
238 | if (memcmp(upstream->client_cookie, pos, 8) != 0) { | |
285 | if (memcmp(upstream->client_cookie, position, 8) != 0) { | |
239 | 286 | if (!upstream->has_prev_client_cookie) |
240 | 287 | return 1; /* Cookie didn't match */ |
241 | if (memcmp(upstream->prev_client_cookie, pos, 8) != 0) | |
288 | if (memcmp(upstream->prev_client_cookie, position, 8) != 0) | |
242 | 289 | return 1; /* Previous cookie didn't match either */ |
243 | 290 | |
244 | 291 | upstream->has_server_cookie = 0; |
246 | 293 | * is for our previous client cookie |
247 | 294 | */ |
248 | 295 | } |
249 | pos += 8; | |
250 | opt_len -= 8; | |
296 | position += 8; | |
297 | option_len -= 8; | |
251 | 298 | upstream->has_server_cookie = 1; |
252 | upstream->server_cookie_len = opt_len; | |
253 | (void) memcpy(upstream->server_cookie, pos, opt_len); | |
299 | upstream->server_cookie_len = option_len; | |
300 | (void) memcpy(upstream->server_cookie, position, option_len); | |
254 | 301 | return 0; |
255 | 302 | } |
256 | 303 | |
257 | 304 | static int |
258 | create_starttls_request(getdns_dns_req *dnsreq, getdns_upstream *upstream, | |
259 | getdns_eventloop *loop) | |
260 | { | |
261 | getdns_return_t r = GETDNS_RETURN_GOOD; | |
262 | getdns_dict* extensions = getdns_dict_create_with_context(dnsreq->context); | |
263 | if (!extensions) { | |
264 | return 0; | |
265 | } | |
266 | r = getdns_dict_set_int(extensions, "specify_class", GLDNS_RR_CLASS_CH); | |
267 | if (r != GETDNS_RETURN_GOOD) { | |
268 | getdns_dict_destroy(extensions); | |
269 | return 0; | |
270 | } | |
271 | upstream->starttls_req = _getdns_dns_req_new(dnsreq->context, loop, | |
272 | "STARTTLS", GETDNS_RRTYPE_TXT, extensions); | |
273 | /*TODO[TLS]: TO BIT*/ | |
274 | if (upstream->starttls_req == NULL) | |
275 | return 0; | |
276 | getdns_dict_destroy(extensions); | |
277 | ||
278 | upstream->starttls_req->netreqs[0]->upstream = upstream; | |
279 | return 1; | |
280 | } | |
281 | ||
282 | static int | |
283 | is_starttls_response(getdns_network_req *netreq) | |
284 | { | |
285 | _getdns_rr_iter rr_iter_storage, *rr_iter; | |
286 | _getdns_rdf_iter rdf_iter_storage, *rdf_iter; | |
287 | uint16_t rr_type; | |
288 | gldns_pkt_section section; | |
289 | uint8_t starttls_name_space[256], *starttls_name; | |
290 | uint8_t owner_name_space[256], *owner_name; | |
291 | size_t starttls_name_len = sizeof(starttls_name_space); | |
292 | size_t owner_name_len = sizeof(owner_name_space);; | |
293 | ||
294 | /* Servers that are not STARTTLS aware will refuse the CH query*/ | |
295 | if (GLDNS_RCODE_NOERROR != GLDNS_RCODE_WIRE(netreq->response)) | |
296 | return 0; | |
297 | ||
298 | if (GLDNS_ANCOUNT(netreq->response) != 1) | |
299 | return 0; | |
300 | ||
301 | for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage | |
302 | , netreq->response | |
303 | , netreq->response_len) | |
304 | ; rr_iter | |
305 | ; rr_iter = _getdns_rr_iter_next(rr_iter)) { | |
306 | ||
307 | section = _getdns_rr_iter_section(rr_iter); | |
308 | rr_type = gldns_read_uint16(rr_iter->rr_type); | |
309 | if (section != GLDNS_SECTION_ANSWER | |
310 | || rr_type != GETDNS_RRTYPE_TXT) | |
311 | continue; | |
312 | ||
313 | owner_name = _getdns_owner_if_or_as_decompressed( | |
314 | rr_iter, owner_name_space, &owner_name_len); | |
315 | if (!_getdns_dname_equal(netreq->owner->name, owner_name)) | |
316 | continue; | |
317 | ||
318 | if (!(rdf_iter = _getdns_rdf_iter_init( | |
319 | &rdf_iter_storage, rr_iter))) | |
320 | continue; | |
321 | ||
322 | if ((starttls_name = _getdns_rdf_if_or_as_decompressed( | |
323 | rdf_iter, starttls_name_space, &starttls_name_len)) && | |
324 | _getdns_dname_equal(starttls_name, owner_name)) | |
325 | return 1; | |
326 | ||
327 | return 0; | |
305 | process_keepalive( | |
306 | getdns_upstream *upstream, getdns_network_req *netreq, | |
307 | uint8_t *response, size_t response_len) | |
308 | { | |
309 | const uint8_t *position = NULL; | |
310 | uint16_t option_len = 0; | |
311 | int found = match_edns_opt_rr(GLDNS_EDNS_KEEPALIVE, response, | |
312 | response_len, &position, &option_len); | |
313 | if (found != 2) { | |
314 | if (netreq->keepalive_sent == 1) | |
315 | /* If no keepalive sent back, then we must use 0 idle timeout | |
316 | as server does not support it.*/ | |
317 | upstream->keepalive_timeout = 0; | |
318 | return found; | |
319 | } | |
320 | if (option_len != 2) | |
321 | return 1; /* FORMERR */ | |
322 | /* Use server sent value unless the client specified a shorter one. | |
323 | Convert to ms first (wire value has units of 100ms) */ | |
324 | uint64_t server_keepalive = ((uint64_t)gldns_read_uint16(position))*100; | |
325 | if (netreq->owner->context->idle_timeout < server_keepalive) | |
326 | upstream->keepalive_timeout = netreq->owner->context->idle_timeout; | |
327 | else { | |
328 | upstream->keepalive_timeout = server_keepalive; | |
329 | DEBUG_STUB("*** %s: SERVER KEEPALIVE USED : %d ms\n", | |
330 | __FUNCTION__, (int)server_keepalive); | |
328 | 331 | } |
329 | 332 | return 0; |
330 | 333 | } |
359 | 362 | getdns_sock_nonblock(fd); |
360 | 363 | #ifdef USE_TCP_FASTOPEN |
361 | 364 | /* Leave the connect to the later call to sendto() if using TCP*/ |
362 | if (transport == GETDNS_TRANSPORT_TCP || | |
363 | transport == GETDNS_TRANSPORT_STARTTLS) | |
365 | if (transport == GETDNS_TRANSPORT_TCP) | |
364 | 366 | return fd; |
367 | #elif USE_OSX_TCP_FASTOPEN | |
368 | sa_endpoints_t endpoints; | |
369 | endpoints.sae_srcif = 0; | |
370 | endpoints.sae_srcaddr = NULL; | |
371 | endpoints.sae_srcaddrlen = 0; | |
372 | endpoints.sae_dstaddr = (struct sockaddr *)&upstream->addr; | |
373 | endpoints.sae_dstaddrlen = upstream->addr_len; | |
374 | if (connectx(fd, &endpoints, SAE_ASSOCID_ANY, | |
375 | CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE, | |
376 | NULL, 0, NULL, NULL) == -1) { | |
377 | if (errno != EINPROGRESS) { | |
378 | close(fd); | |
379 | return -1; | |
380 | } | |
381 | } | |
382 | return fd; | |
365 | 383 | #endif |
366 | 384 | if (connect(fd, (struct sockaddr *)&upstream->addr, |
367 | 385 | upstream->addr_len) == -1) { |
448 | 466 | netreq->write_queue_tail = NULL; |
449 | 467 | break; |
450 | 468 | } |
451 | upstream_reschedule_events(upstream, netreq->owner->context->idle_timeout); | |
469 | upstream_reschedule_events(upstream, upstream->keepalive_timeout); | |
452 | 470 | } |
453 | 471 | |
454 | 472 | static int |
504 | 522 | if (netreq->fd >= 0) close(netreq->fd); |
505 | 523 | } |
506 | 524 | |
507 | static void | |
525 | /* May be needed in future for better UDP error handling?*/ | |
526 | /*static void | |
508 | 527 | stub_erred(getdns_network_req *netreq) |
509 | 528 | { |
510 | 529 | DEBUG_STUB("*** %s\n", __FUNCTION__); |
511 | 530 | stub_next_upstream(netreq); |
512 | 531 | stub_cleanup(netreq); |
513 | /* TODO[TLS]: When we get an error (which is probably a timeout) and are | |
514 | * using to keep connections open should we leave the connection up here? */ | |
515 | 532 | if (netreq->fd >= 0) close(netreq->fd); |
516 | 533 | netreq->state = NET_REQ_FINISHED; |
517 | 534 | _getdns_check_dns_req_complete(netreq->owner); |
518 | } | |
535 | }*/ | |
519 | 536 | |
520 | 537 | static void |
521 | 538 | stub_timeout_cb(void *userarg) |
522 | 539 | { |
523 | 540 | DEBUG_STUB("*** %s(%p)\n", __FUNCTION__, userarg); |
524 | 541 | getdns_network_req *netreq = (getdns_network_req *)userarg; |
525 | ||
526 | /* For now, mark a STARTTLS timeout as a failured negotiation and allow | |
527 | * fallback but don't close the connection. */ | |
528 | if (netreq->owner == netreq->upstream->starttls_req) { | |
529 | netreq->upstream->tls_hs_state = GETDNS_HS_FAILED; | |
530 | stub_next_upstream(netreq); | |
531 | stub_cleanup(netreq); | |
532 | return; | |
533 | } | |
534 | 542 | |
535 | 543 | stub_next_upstream(netreq); |
536 | 544 | stub_cleanup(netreq); |
616 | 624 | /****************************/ |
617 | 625 | |
618 | 626 | static int |
619 | stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) | |
627 | stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event) | |
620 | 628 | { |
621 | 629 | ssize_t read; |
622 | 630 | uint8_t *buf; |
631 | 639 | tcp->read_pos = tcp->read_buf; |
632 | 640 | tcp->to_read = 2; /* Packet size */ |
633 | 641 | } |
634 | read = recv(fd, tcp->read_pos, tcp->to_read, 0); | |
642 | read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); | |
635 | 643 | if (read == -1) { |
644 | #ifdef USE_WINSOCK | |
645 | printf("read (in tcp ) %s\n", | |
646 | wsa_strerror(WSAGetLastError())); | |
647 | if (WSAGetLastError() == WSAECONNRESET) | |
648 | return STUB_TCP_AGAIN; | |
649 | if (WSAGetLastError() == WSAEINPROGRESS) | |
650 | return STUB_TCP_AGAIN; | |
651 | if (WSAGetLastError() == WSAEWOULDBLOCK) { | |
652 | winsock_tcp_wouldblock(event->ev, EV_READ); | |
653 | return STUB_TCP_AGAIN; | |
654 | } | |
655 | ||
656 | #else | |
636 | 657 | if (errno == EAGAIN || errno == EWOULDBLOCK) |
637 | 658 | return STUB_TCP_AGAIN; |
638 | 659 | else |
639 | 660 | return STUB_TCP_ERROR; |
661 | #endif | |
640 | 662 | } else if (read == 0) { |
641 | 663 | /* Remote end closed the socket */ |
642 | 664 | /* TODO: Try to reconnect */ |
718 | 740 | if (netreq->owner->edns_client_subnet_private) |
719 | 741 | if (attach_edns_client_subnet_private(netreq)) |
720 | 742 | return STUB_OUT_OF_OPTIONS; |
743 | if (netreq->upstream->writes_done == 0 && | |
744 | netreq->owner->context->idle_timeout != 0) { | |
745 | /* Add the keepalive option to the first query on this connection*/ | |
746 | DEBUG_STUB("# %s: Requesting keepalive\n", __FUNCTION__); | |
747 | if (attach_edns_keepalive(netreq)) | |
748 | return STUB_OUT_OF_OPTIONS; | |
749 | netreq->keepalive_sent = 1; | |
750 | } | |
721 | 751 | } |
722 | pkt_len = netreq->response - netreq->query; | |
752 | pkt_len = _getdns_network_req_add_tsig(netreq); | |
723 | 753 | /* We have an initialized packet buffer. |
724 | 754 | * Lets see how much of it we can write |
725 | 755 | */ |
741 | 771 | errno == EINPROGRESS)) || |
742 | 772 | written < pkt_len + 2) { |
743 | 773 | #else |
774 | ||
775 | #ifdef USE_WINSOCK | |
776 | written = sendto(fd, (const char *)(netreq->query - 2), | |
777 | pkt_len + 2, 0, | |
778 | (struct sockaddr *)&(netreq->upstream->addr), | |
779 | netreq->upstream->addr_len); | |
780 | ||
781 | #else | |
744 | 782 | written = write(fd, netreq->query - 2, pkt_len + 2); |
783 | #endif | |
745 | 784 | if ((written == -1 && (errno == EAGAIN || |
746 | 785 | errno == EWOULDBLOCK)) || |
747 | 786 | written < pkt_len + 2) { |
795 | 834 | tls_requested(getdns_network_req *netreq) |
796 | 835 | { |
797 | 836 | return (netreq->transports[netreq->transport_current] == |
798 | GETDNS_TRANSPORT_TLS || | |
799 | netreq->transports[netreq->transport_current] == | |
800 | GETDNS_TRANSPORT_STARTTLS) ? | |
837 | GETDNS_TRANSPORT_TLS) ? | |
801 | 838 | 1 : 0; |
802 | 839 | } |
803 | 840 | |
804 | 841 | static int |
805 | 842 | tls_should_write(getdns_upstream *upstream) |
806 | 843 | { |
807 | /* Should messages be written on TLS upstream. Remember that for STARTTLS | |
808 | * the first message should got over TCP as the handshake isn't started yet.*/ | |
809 | return ((upstream->transport == GETDNS_TRANSPORT_TLS || | |
810 | upstream->transport == GETDNS_TRANSPORT_STARTTLS) && | |
844 | /* Should messages be written on TLS upstream. */ | |
845 | return ((upstream->transport == GETDNS_TRANSPORT_TLS) && | |
811 | 846 | upstream->tls_hs_state != GETDNS_HS_NONE) ? 1 : 0; |
812 | 847 | } |
813 | 848 | |
814 | 849 | static int |
815 | 850 | tls_should_read(getdns_upstream *upstream) |
816 | 851 | { |
817 | return ((upstream->transport == GETDNS_TRANSPORT_TLS || | |
818 | upstream->transport == GETDNS_TRANSPORT_STARTTLS) && | |
852 | return ((upstream->transport == GETDNS_TRANSPORT_TLS) && | |
819 | 853 | !(upstream->tls_hs_state == GETDNS_HS_FAILED || |
820 | 854 | upstream->tls_hs_state == GETDNS_HS_NONE)) ? 1 : 0; |
821 | 855 | } |
824 | 858 | tls_failed(getdns_upstream *upstream) |
825 | 859 | { |
826 | 860 | /* No messages should be scheduled onto an upstream in this state */ |
827 | return ((upstream->transport == GETDNS_TRANSPORT_TLS || | |
828 | upstream->transport == GETDNS_TRANSPORT_STARTTLS) && | |
861 | return ((upstream->transport == GETDNS_TRANSPORT_TLS) && | |
829 | 862 | upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1 : 0; |
830 | 863 | } |
831 | 864 | |
832 | 865 | static int |
833 | 866 | tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { |
834 | return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME && | |
867 | return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED && | |
835 | 868 | upstream->tls_auth_failed) ? 0 : 1; |
836 | 869 | } |
837 | 870 | |
838 | 871 | int |
839 | 872 | tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) |
840 | 873 | { |
841 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
842 | int err; | |
843 | const char * err_str; | |
844 | ||
845 | err = X509_STORE_CTX_get_error(ctx); | |
846 | err_str = X509_verify_cert_error_string(err); | |
847 | DEBUG_STUB("--- %s, VERIFY RESULT: %s\n", __FUNCTION__, err_str); | |
874 | getdns_upstream *upstream; | |
875 | getdns_return_t pinset_ret = GETDNS_RETURN_GOOD; | |
876 | ||
877 | #if defined(STUB_DEBUG) && STUB_DEBUG || defined(X509_V_ERR_HOSTNAME_MISMATCH) | |
878 | int err = X509_STORE_CTX_get_error(ctx); | |
879 | ||
880 | DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, | |
881 | err, X509_verify_cert_error_string(err)); | |
848 | 882 | #endif |
849 | /*Always proceed without changing result*/ | |
850 | return preverify_ok; | |
851 | } | |
852 | ||
853 | int | |
854 | tls_verify_callback_with_fallback(int preverify_ok, X509_STORE_CTX *ctx) | |
855 | { | |
883 | upstream = _getdns_upstream_from_x509_store(ctx); | |
884 | ||
856 | 885 | #ifdef X509_V_ERR_HOSTNAME_MISMATCH |
857 | int err; | |
858 | # if defined(STUB_DEBUG) && STUB_DEBUG | |
859 | const char * err_str; | |
860 | # endif | |
861 | ||
862 | err = X509_STORE_CTX_get_error(ctx); | |
863 | # if defined(STUB_DEBUG) && STUB_DEBUG | |
864 | err_str = X509_verify_cert_error_string(err); | |
865 | DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, err, err_str); | |
866 | # endif | |
867 | /*Proceed if error is hostname mismatch*/ | |
868 | if (err == X509_V_ERR_HOSTNAME_MISMATCH) { | |
869 | DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); | |
870 | return 1; | |
871 | } | |
872 | else | |
886 | /*Report if error is hostname mismatch*/ | |
887 | if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) | |
888 | DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH HOSTNAME VALIDATION FAILED!!\n", __FUNCTION__); | |
873 | 889 | #endif |
874 | return preverify_ok; | |
890 | if (upstream && upstream->tls_pubkey_pinset) | |
891 | pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); | |
892 | ||
893 | if (pinset_ret != GETDNS_RETURN_GOOD) { | |
894 | DEBUG_STUB("--- %s, PINSET VALIDATION FAILURE!!\n", __FUNCTION__); | |
895 | preverify_ok = 0; | |
896 | upstream->tls_auth_failed = 1; | |
897 | if (upstream->tls_fallback_ok) | |
898 | DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH PINSET VALIDATION FAILED!!\n", __FUNCTION__); | |
899 | } | |
900 | /* If fallback is allowed, proceed regardless of what the auth error is | |
901 | (might not be hostname or pinset related) */ | |
902 | return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; | |
875 | 903 | } |
876 | 904 | |
877 | 905 | static SSL* |
889 | 917 | SSL_free(ssl); |
890 | 918 | return NULL; |
891 | 919 | } |
920 | /* make sure we'll be able to find the context again when we need it */ | |
921 | if (_getdns_associate_upstream_with_SSL(ssl, upstream) != GETDNS_RETURN_GOOD) { | |
922 | SSL_free(ssl); | |
923 | return NULL; | |
924 | } | |
892 | 925 | |
893 | 926 | /* NOTE: this code will fallback on a given upstream, without trying |
894 | 927 | authentication on other upstreams first. This is non-optimal and but avoids |
895 | 928 | multiple TLS handshakes before getting a usable connection. */ |
896 | 929 | |
930 | upstream->tls_fallback_ok = 0; | |
897 | 931 | /* If we have a hostname, always use it */ |
898 | 932 | if (upstream->tls_auth_name[0] != '\0') { |
899 | 933 | /*Request certificate for the auth_name*/ |
906 | 940 | param = SSL_get0_param(ssl); |
907 | 941 | X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); |
908 | 942 | X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); |
909 | DEBUG_STUB("--- %s, HOSTNAME VERIFICATION REQUESTED \n", __FUNCTION__); | |
910 | 943 | #else |
911 | if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { | |
944 | if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { | |
912 | 945 | /* TODO: Trigger post-handshake custom validation*/ |
913 | DEBUG_STUB("--- %s, ERROR: Authentication functionality not available\n", __FUNCTION__); | |
946 | DEBUG_STUB("--- %s, ERROR: TLS Authentication functionality not available\n", __FUNCTION__); | |
914 | 947 | upstream->tls_hs_state = GETDNS_HS_FAILED; |
915 | 948 | upstream->tls_auth_failed = 1; |
916 | 949 | return NULL; |
917 | 950 | } |
918 | 951 | #endif |
919 | 952 | /* Allow fallback to opportunistic if settings permit it*/ |
920 | if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) | |
921 | SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); | |
922 | else { | |
923 | SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback); | |
924 | SSL_set_cipher_list(ssl, "DEFAULT"); | |
953 | if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) | |
954 | upstream->tls_fallback_ok = 1; | |
955 | } else { | |
956 | /* Lack of host name is OK unless only authenticated | |
957 | * TLS is specified and we have no pubkey_pinset */ | |
958 | if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { | |
959 | if (upstream->tls_pubkey_pinset) { | |
960 | DEBUG_STUB("--- %s, PROCEEDING WITH ONLY PUBKEY PINNING AUTHENTICATION\n", __FUNCTION__); | |
961 | } else { | |
962 | DEBUG_STUB("--- %s, ERROR: No host name or pubkey pinset provided for TLS authentication\n", __FUNCTION__); | |
963 | upstream->tls_hs_state = GETDNS_HS_FAILED; | |
964 | upstream->tls_auth_failed = 1; | |
965 | return NULL; | |
966 | } | |
967 | } else { | |
968 | /* no hostname verification, so we will make opportunistic connections */ | |
969 | DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH NO HOSTNAME PROVIDED!!\n", __FUNCTION__); | |
970 | upstream->tls_auth_failed = 1; | |
971 | upstream->tls_fallback_ok = 1; | |
925 | 972 | } |
926 | } else { | |
927 | /* Lack of host name is OK unless only authenticated TLS is specified*/ | |
928 | if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { | |
929 | DEBUG_STUB("--- %s, ERROR: No host name provided for authentication\n", __FUNCTION__); | |
930 | upstream->tls_hs_state = GETDNS_HS_FAILED; | |
931 | upstream->tls_auth_failed = 1; | |
932 | return NULL; | |
933 | } else { | |
934 | /* no hostname verification, so we will make opportunistic connections */ | |
935 | DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); | |
936 | upstream->tls_auth_failed = 1; | |
937 | SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback); | |
938 | SSL_set_cipher_list(ssl, "DEFAULT"); | |
939 | } | |
940 | } | |
941 | ||
973 | } | |
974 | if (upstream->tls_fallback_ok) { | |
975 | SSL_set_cipher_list(ssl, "DEFAULT"); | |
976 | DEBUG_STUB("--- %s, PROCEEDING WITH OPPOTUNISTIC TLS CONNECTION (FALLBACK ALLOWED)!!\n", __FUNCTION__); | |
977 | } else | |
978 | DEBUG_STUB("--- %s, PROCEEDING WITH STRICT TLS CONNECTION!!\n", __FUNCTION__); | |
979 | SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); | |
980 | ||
942 | 981 | SSL_set_connect_state(ssl); |
943 | 982 | (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); |
944 | 983 | return ssl; |
999 | 1038 | } |
1000 | 1039 | upstream->tls_hs_state = GETDNS_HS_DONE; |
1001 | 1040 | r = SSL_get_verify_result(upstream->tls_obj); |
1041 | if (upstream->tls_auth_name[0]) | |
1002 | 1042 | #ifdef X509_V_ERR_HOSTNAME_MISMATCH |
1003 | if (r == X509_V_ERR_HOSTNAME_MISMATCH) | |
1043 | if (r == X509_V_ERR_HOSTNAME_MISMATCH) | |
1044 | #else | |
1045 | /* if we weren't built against OpenSSL with hostname matching we | |
1046 | * could not have matched the hostname, so this would be an automatic | |
1047 | * tls_auth_fail. */ | |
1004 | 1048 | #endif |
1005 | upstream->tls_auth_failed = 1; | |
1049 | upstream->tls_auth_failed = 1; | |
1006 | 1050 | /* Reset timeout on success*/ |
1007 | 1051 | GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); |
1008 | 1052 | upstream->event.read_cb = NULL; |
1171 | 1215 | &netreq->upstream->netreq_by_query_id, &netreq->node)); |
1172 | 1216 | |
1173 | 1217 | GLDNS_ID_SET(netreq->query, query_id); |
1218 | /* TODO: Review if more EDNS0 handling can be centralised.*/ | |
1174 | 1219 | if (netreq->opt) { |
1175 | 1220 | _getdns_network_req_clear_upstream_options(netreq); |
1176 | 1221 | /* no limits on the max udp payload size with tcp */ |
1181 | 1226 | if (netreq->owner->edns_client_subnet_private) |
1182 | 1227 | if (attach_edns_client_subnet_private(netreq)) |
1183 | 1228 | return STUB_OUT_OF_OPTIONS; |
1229 | if (netreq->upstream->writes_done % EDNS_KEEPALIVE_RESEND == 0 && | |
1230 | netreq->owner->context->idle_timeout != 0) { | |
1231 | /* Add the keepalive option to every nth query on this | |
1232 | connection */ | |
1233 | DEBUG_STUB("# %s: Requesting keepalive\n", __FUNCTION__); | |
1234 | if (attach_edns_keepalive(netreq)) | |
1235 | return STUB_OUT_OF_OPTIONS; | |
1236 | netreq->keepalive_sent = 1; | |
1237 | } | |
1184 | 1238 | if (netreq->owner->tls_query_padding_blocksize > 1) { |
1185 | 1239 | pkt_len = netreq->response - netreq->query; |
1186 | 1240 | pkt_len += 4; /* this accounts for the OPTION-CODE and OPTION-LENGTH of the padding */ |
1194 | 1248 | } |
1195 | 1249 | } |
1196 | 1250 | |
1197 | pkt_len = netreq->response - netreq->query; | |
1251 | pkt_len = _getdns_network_req_add_tsig(netreq); | |
1198 | 1252 | /* We have an initialized packet buffer. |
1199 | 1253 | * Lets see how much of it we can write */ |
1200 | 1254 | |
1241 | 1295 | |
1242 | 1296 | GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); |
1243 | 1297 | |
1244 | read = recvfrom(netreq->fd, netreq->response, | |
1298 | read = recvfrom(netreq->fd, (void *)netreq->response, | |
1245 | 1299 | netreq->max_udp_payload_size + 1, /* If read == max_udp_payload_size |
1246 | 1300 | * then all is good. If read == |
1247 | 1301 | * max_udp_payload_size + 1, then |
1263 | 1317 | return; /* Client cookie didn't match? */ |
1264 | 1318 | |
1265 | 1319 | close(netreq->fd); |
1266 | if (GLDNS_TC_WIRE(netreq->response)) { | |
1320 | while (GLDNS_TC_WIRE(netreq->response)) { | |
1321 | DEBUG_STUB("TC bit set\n"); | |
1267 | 1322 | if (!(netreq->transport_current < netreq->transport_count)) |
1268 | goto done; | |
1323 | break; | |
1269 | 1324 | getdns_transport_list_t next_transport = |
1270 | 1325 | netreq->transports[++netreq->transport_current]; |
1271 | if (next_transport != GETDNS_TRANSPORT_TCP) | |
1272 | goto done; | |
1326 | if (next_transport != GETDNS_TRANSPORT_TCP && | |
1327 | next_transport != GETDNS_TRANSPORT_TLS) | |
1328 | break; | |
1273 | 1329 | /* For now, special case where fallback should be on the same upstream*/ |
1274 | 1330 | if ((netreq->fd = upstream_connect(upstream, next_transport, |
1275 | 1331 | dnsreq)) == -1) |
1276 | goto done; | |
1332 | break; | |
1277 | 1333 | upstream_schedule_netreq(netreq->upstream, netreq); |
1278 | 1334 | GETDNS_SCHEDULE_EVENT( |
1279 | 1335 | dnsreq->loop, netreq->upstream->fd, dnsreq->context->timeout, |
1285 | 1341 | } |
1286 | 1342 | netreq->response_len = read; |
1287 | 1343 | dnsreq->upstreams->current = 0; |
1288 | done: | |
1289 | 1344 | netreq->debug_end_time = _getdns_get_time_as_uintt64(); |
1290 | 1345 | netreq->state = NET_REQ_FINISHED; |
1291 | 1346 | _getdns_check_dns_req_complete(dnsreq); |
1319 | 1374 | if (attach_edns_client_subnet_private(netreq)) |
1320 | 1375 | return; /* too many upstream options */ |
1321 | 1376 | } |
1322 | pkt_len = netreq->response - netreq->query; | |
1323 | if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0, | |
1377 | pkt_len = _getdns_network_req_add_tsig(netreq); | |
1378 | if ((ssize_t)pkt_len != sendto( | |
1379 | netreq->fd, (const void *)netreq->query, pkt_len, 0, | |
1324 | 1380 | (struct sockaddr *)&netreq->upstream->addr, |
1325 | 1381 | netreq->upstream->addr_len)) { |
1326 | 1382 | close(netreq->fd); |
1333 | 1389 | } |
1334 | 1390 | |
1335 | 1391 | /**************************/ |
1336 | /* TCP callback functions*/ | |
1337 | /**************************/ | |
1338 | ||
1339 | static void | |
1340 | stub_tcp_read_cb(void *userarg) | |
1341 | { | |
1342 | getdns_network_req *netreq = (getdns_network_req *)userarg; | |
1343 | getdns_dns_req *dnsreq = netreq->owner; | |
1344 | int q; | |
1345 | ||
1346 | switch ((q = stub_tcp_read(netreq->fd, &netreq->tcp, | |
1347 | &dnsreq->context->mf))) { | |
1348 | ||
1349 | case STUB_TCP_AGAIN: | |
1350 | return; | |
1351 | ||
1352 | case STUB_TCP_ERROR: | |
1353 | stub_erred(netreq); | |
1354 | return; | |
1355 | ||
1356 | default: | |
1357 | GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); | |
1358 | if (q != netreq->query_id) | |
1359 | return; | |
1360 | if (netreq->owner->edns_cookies && | |
1361 | match_and_process_server_cookie( | |
1362 | netreq->upstream, netreq->tcp.read_buf, | |
1363 | netreq->tcp.read_pos - netreq->tcp.read_buf)) | |
1364 | return; /* Client cookie didn't match? */ | |
1365 | netreq->state = NET_REQ_FINISHED; | |
1366 | netreq->response = netreq->tcp.read_buf; | |
1367 | netreq->response_len = | |
1368 | netreq->tcp.read_pos - netreq->tcp.read_buf; | |
1369 | netreq->tcp.read_buf = NULL; | |
1370 | dnsreq->upstreams->current = 0; | |
1371 | netreq->debug_end_time = _getdns_get_time_as_uintt64(); | |
1372 | stub_cleanup(netreq); | |
1373 | close(netreq->fd); | |
1374 | _getdns_check_dns_req_complete(dnsreq); | |
1375 | } | |
1376 | } | |
1377 | ||
1378 | static void | |
1379 | stub_tcp_write_cb(void *userarg) | |
1380 | { | |
1381 | getdns_network_req *netreq = (getdns_network_req *)userarg; | |
1382 | getdns_dns_req *dnsreq = netreq->owner; | |
1383 | int q; | |
1384 | netreq->debug_start_time = _getdns_get_time_as_uintt64(); | |
1385 | switch ((q = stub_tcp_write(netreq->fd, &netreq->tcp, netreq))) { | |
1386 | case STUB_TCP_AGAIN: | |
1387 | return; | |
1388 | ||
1389 | case STUB_TCP_ERROR: | |
1390 | stub_erred(netreq); | |
1391 | return; | |
1392 | ||
1393 | default: | |
1394 | netreq->debug_udp = 0; | |
1395 | netreq->query_id = (uint16_t) q; | |
1396 | GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); | |
1397 | GETDNS_SCHEDULE_EVENT( | |
1398 | dnsreq->loop, netreq->fd, dnsreq->context->timeout, | |
1399 | getdns_eventloop_event_init(&netreq->event, netreq, | |
1400 | stub_tcp_read_cb, NULL, stub_timeout_cb)); | |
1401 | return; | |
1402 | } | |
1403 | } | |
1404 | ||
1405 | /**************************/ | |
1406 | 1392 | /* Upstream callback functions*/ |
1407 | 1393 | /**************************/ |
1408 | 1394 | |
1412 | 1398 | DEBUG_STUB("--- READ: %s\n", __FUNCTION__); |
1413 | 1399 | getdns_upstream *upstream = (getdns_upstream *)userarg; |
1414 | 1400 | getdns_network_req *netreq; |
1415 | getdns_dns_req *dnsreq; | |
1416 | 1401 | int q; |
1417 | 1402 | uint16_t query_id; |
1418 | 1403 | intptr_t query_id_intptr; |
1422 | 1407 | &upstream->upstreams->mf); |
1423 | 1408 | else |
1424 | 1409 | q = stub_tcp_read(upstream->fd, &upstream->tcp, |
1425 | &upstream->upstreams->mf); | |
1410 | &upstream->upstreams->mf, &upstream->event); | |
1426 | 1411 | |
1427 | 1412 | switch (q) { |
1428 | 1413 | case STUB_TCP_AGAIN: |
1455 | 1440 | /* TODO[TLS]: I don't think we should do this for TCP. We should stay |
1456 | 1441 | * on a working connection until we hit a problem.*/ |
1457 | 1442 | upstream->upstreams->current = 0; |
1458 | ||
1459 | if (netreq->owner == upstream->starttls_req) { | |
1460 | dnsreq = netreq->owner; | |
1461 | if (is_starttls_response(netreq)) { | |
1462 | upstream->tls_obj = tls_create_object(dnsreq, | |
1463 | upstream->fd, | |
1464 | upstream); | |
1465 | if (upstream->tls_obj == NULL) | |
1466 | upstream->tls_hs_state = GETDNS_HS_FAILED; | |
1467 | upstream->tls_hs_state = GETDNS_HS_WRITE; | |
1468 | } else | |
1469 | upstream->tls_hs_state = GETDNS_HS_FAILED; | |
1470 | ||
1471 | /* Now reschedule the writes on this connection */ | |
1472 | GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); | |
1473 | GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, | |
1474 | netreq->owner->context->timeout, | |
1475 | getdns_eventloop_event_init(&upstream->event, upstream, | |
1476 | NULL, upstream_write_cb, NULL)); | |
1477 | } | |
1443 | ||
1444 | /* !THIS CODE NEEDS TESTING!*/ | |
1445 | if (netreq->owner->edns_cookies && | |
1446 | match_and_process_server_cookie( | |
1447 | netreq->upstream, netreq->tcp.read_buf, | |
1448 | netreq->tcp.read_pos - netreq->tcp.read_buf)) | |
1449 | return; /* Client cookie didn't match? */ | |
1450 | ||
1451 | if ((netreq->owner->context->idle_timeout != 0) && | |
1452 | process_keepalive(netreq->upstream, netreq, netreq->response, | |
1453 | netreq->response_len)) | |
1454 | return; | |
1455 | ||
1478 | 1456 | netreq->debug_end_time = _getdns_get_time_as_uintt64(); |
1479 | 1457 | /* This also reschedules events for the upstream*/ |
1480 | 1458 | stub_cleanup(netreq); |
1483 | 1461 | if (netreq->event.read_cb) |
1484 | 1462 | upstream_reschedule_netreq_events(upstream, netreq); |
1485 | 1463 | |
1486 | if (netreq->owner != upstream->starttls_req) | |
1487 | _getdns_check_dns_req_complete(netreq->owner); | |
1464 | _getdns_check_dns_req_complete(netreq->owner); | |
1488 | 1465 | } |
1489 | 1466 | } |
1490 | 1467 | |
1564 | 1541 | GETDNS_SCHEDULE_EVENT(upstream->loop, |
1565 | 1542 | upstream->fd, TIMEOUT_FOREVER, &upstream->event); |
1566 | 1543 | } |
1567 | if (upstream->starttls_req && netreq->owner == upstream->starttls_req) { | |
1568 | /* Now deschedule any further writes on this connection until we get | |
1569 | * the STARTTLS answer*/ | |
1570 | GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); | |
1571 | upstream->event.write_cb = NULL; | |
1572 | GETDNS_SCHEDULE_EVENT(upstream->loop, | |
1573 | upstream->fd, TIMEOUT_FOREVER, &upstream->event); | |
1574 | } else if (upstream->starttls_req) { | |
1575 | /* Delay the cleanup of the STARTTLS req until the write of the next | |
1576 | * req in the queue since for sync req, the event on a request is | |
1577 | * used for the callback that writes the next req. */ | |
1578 | _getdns_dns_req_free(upstream->starttls_req); | |
1579 | upstream->starttls_req = NULL; | |
1580 | } | |
1581 | 1544 | /* With synchonous lookups, schedule the read locally too */ |
1582 | 1545 | if (netreq->event.write_cb) { |
1583 | 1546 | GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); |
1585 | 1548 | dnsreq->loop, upstream->fd, dnsreq->context->timeout, |
1586 | 1549 | getdns_eventloop_event_init(&netreq->event, netreq, |
1587 | 1550 | netreq_upstream_read_cb, |
1588 | (upstream->write_queue && !upstream->starttls_req ? | |
1551 | (upstream->write_queue ? | |
1589 | 1552 | netreq_upstream_write_cb : NULL), |
1590 | 1553 | stub_timeout_cb)); |
1591 | 1554 | } |
1621 | 1584 | upstream->tcp.write_error != 0) { |
1622 | 1585 | return 0; |
1623 | 1586 | } |
1624 | /* Allow TCP messages to be sent on a STARTTLS upstream that hasn't | |
1625 | * upgraded to avoid opening a new connection if one is aleady open. */ | |
1626 | if (transport == GETDNS_TRANSPORT_TCP && | |
1627 | upstream->transport == GETDNS_TRANSPORT_STARTTLS && | |
1628 | upstream->tls_hs_state == GETDNS_HS_FAILED) | |
1629 | return 1; | |
1630 | 1587 | /* Otherwise, transport must match, and not have failed */ |
1631 | 1588 | if (upstream->transport != transport) |
1632 | 1589 | return 0; |
1722 | 1679 | upstream->loop = dnsreq->context->extension; |
1723 | 1680 | upstream->fd = fd; |
1724 | 1681 | break; |
1725 | case GETDNS_TRANSPORT_STARTTLS: | |
1726 | /* Use existing if available. Let the fallback code handle it if | |
1727 | * STARTTLS isn't availble. */ | |
1728 | if (upstream->fd != -1) | |
1729 | return upstream->fd; | |
1730 | fd = tcp_connect(upstream, transport); | |
1731 | if (fd == -1) return -1; | |
1732 | if (!create_starttls_request(dnsreq, upstream, dnsreq->loop)) | |
1733 | return GETDNS_RETURN_GENERIC_ERROR; | |
1734 | getdns_network_req *starttls_netreq = upstream->starttls_req->netreqs[0]; | |
1735 | upstream->loop = dnsreq->context->extension; | |
1736 | upstream->fd = fd; | |
1737 | upstream_schedule_netreq(upstream, starttls_netreq); | |
1738 | /* Schedule at least the timeout locally, but use less than half the | |
1739 | * context value so by default this timeouts before the TIMEOUT_TLS. | |
1740 | * And also the write if we perform a synchronous lookup */ | |
1741 | GETDNS_SCHEDULE_EVENT( | |
1742 | dnsreq->loop, upstream->fd, dnsreq->context->timeout / 3, | |
1743 | getdns_eventloop_event_init(&starttls_netreq->event, | |
1744 | starttls_netreq, NULL, (dnsreq->loop != upstream->loop | |
1745 | ? netreq_upstream_write_cb : NULL), stub_timeout_cb)); | |
1746 | break; | |
1747 | 1682 | default: |
1748 | 1683 | return -1; |
1749 | 1684 | /* Nothing to do*/ |
1780 | 1715 | continue; |
1781 | 1716 | netreq->transport_current = i; |
1782 | 1717 | netreq->upstream = upstream; |
1718 | netreq->keepalive_sent = 0; | |
1783 | 1719 | return fd; |
1784 | 1720 | } |
1785 | 1721 | return -1; |
1891 | 1827 | GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); |
1892 | 1828 | upstream->event.timeout_cb = NULL; |
1893 | 1829 | upstream->event.write_cb = upstream_write_cb; |
1894 | if (upstream->tls_hs_state == GETDNS_HS_WRITE || | |
1895 | (upstream->starttls_req && | |
1896 | upstream->starttls_req->netreqs[0] == netreq)) { | |
1830 | if (upstream->tls_hs_state == GETDNS_HS_WRITE) { | |
1897 | 1831 | /* Set a timeout on the upstream so we can catch failed setup*/ |
1898 | 1832 | /* TODO[TLS]: When generic fallback supported, we should decide how |
1899 | 1833 | * to split the timeout between transports. */ |
1933 | 1867 | GETDNS_SCHEDULE_EVENT( |
1934 | 1868 | dnsreq->loop, netreq->fd, dnsreq->context->timeout, |
1935 | 1869 | getdns_eventloop_event_init(&netreq->event, netreq, |
1936 | NULL, (transport == GETDNS_TRANSPORT_UDP ? | |
1937 | stub_udp_write_cb: stub_tcp_write_cb), stub_timeout_cb)); | |
1870 | NULL, stub_udp_write_cb, stub_timeout_cb)); | |
1938 | 1871 | return GETDNS_RETURN_GOOD; |
1939 | ||
1940 | case GETDNS_TRANSPORT_STARTTLS: | |
1872 | ||
1941 | 1873 | case GETDNS_TRANSPORT_TLS: |
1942 | 1874 | case GETDNS_TRANSPORT_TCP: |
1943 | 1875 | upstream_schedule_netreq(netreq->upstream, netreq); |
57 | 57 | CHECK_EV_PROG=@CHECK_EV_PROG@ |
58 | 58 | |
59 | 59 | CC=@CC@ |
60 | CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ | |
60 | CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ @CPPFLAGS@ | |
61 | 61 | LDFLAGS=-L.. @LDFLAGS@ |
62 | 62 | LDLIBS=../libgetdns.la @LIBS@ |
63 | 63 | CHECK_LIBS=@CHECK_LIBS@ |
72 | 72 | ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ |
73 | 73 | check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ |
74 | 74 | testmessages.lo tests_dict.lo tests_list.lo tests_namespaces.lo \ |
75 | tests_stub_async.lo tests_stub_sync.lo tests_json-pointers.lo | |
75 | tests_stub_async.lo tests_stub_sync.lo | |
76 | 76 | |
77 | 77 | NON_C99_OBJS=check_getdns_libuv.lo |
78 | 78 | |
79 | PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync tests_json-pointers getdns_query $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) | |
79 | PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync getdns_query $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) | |
80 | 80 | |
81 | 81 | |
82 | 82 | .SUFFIXES: .c .o .a .lo .h |
111 | 111 | |
112 | 112 | tests_stub_sync: tests_stub_sync.lo |
113 | 113 | $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_stub_sync.lo |
114 | ||
115 | tests_json-pointers: tests_json-pointers.lo | |
116 | $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_json-pointers.lo | |
117 | 114 | |
118 | 115 | check_getdns_common: check_getdns_common.lo |
119 | 116 | $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns_common.lo |
182 | 179 | distclean : clean |
183 | 180 | rm -f scratchpad.c |
184 | 181 | rm -f Makefile config.status config.log |
182 | rm -f check_getdns_uv.core check_getdns.core check_getdns_event.core | |
185 | 183 | rm -Rf autom4te.cache |
186 | 184 | |
187 | 185 | $(distdir): FORCE |
215 | 213 | |
216 | 214 | depend: |
217 | 215 | (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) |
218 | (cd $(srcdir) ; gcc -MM -I. -I.. *.c | \ | |
219 | sed -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ | |
216 | (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I.. -I"$$blddir"/.. *.c | \ | |
217 | sed -e "s? $$blddir/? ?g" \ | |
218 | -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ | |
220 | 219 | -e 's? \$$(srcdir)/config\.h? ../config.h?g' \ |
221 | 220 | -e 's? $$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ |
222 | 221 | -e 's? \.\./getdns/getdns_ext_libevent\.h? $$(srcdir)/../getdns/getdns_ext_libevent.h?g' \ |
223 | 222 | -e 's? \.\./getdns/getdns_ext_libev\.h? $$(srcdir)/../getdns/getdns_ext_libev.h?g' \ |
224 | 223 | -e 's? \.\./getdns/getdns_ext_libuv\.h? $$(srcdir)/../getdns/getdns_ext_libuv.h?g' \ |
224 | -e 's? \.\./debug\.h? $$(srcdir)/../debug.h?g' \ | |
225 | 225 | -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) |
226 | 226 | (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ |
227 | 227 | || mv Makefile.in.new Makefile.in ) |
274 | 274 | check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ |
275 | 275 | $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ |
276 | 276 | ../getdns/getdns_extra.h |
277 | getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h ../getdns/getdns.h \ | |
278 | ../getdns/getdns_extra.h | |
277 | getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ | |
278 | ../getdns/getdns.h ../getdns/getdns_extra.h | |
279 | 279 | scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ |
280 | 280 | ../getdns/getdns_extra.h |
281 | 281 | testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h |
282 | 282 | tests_dict.lo tests_dict.o: $(srcdir)/tests_dict.c $(srcdir)/testmessages.h ../getdns/getdns.h |
283 | tests_json-pointers.lo tests_json-pointers.o: $(srcdir)/tests_json-pointers.c ../getdns/getdns.h \ | |
284 | ../getdns/getdns_extra.h | |
285 | 283 | tests_list.lo tests_list.o: $(srcdir)/tests_list.c $(srcdir)/testmessages.h ../getdns/getdns.h |
286 | 284 | tests_namespaces.lo tests_namespaces.o: $(srcdir)/tests_namespaces.c $(srcdir)/testmessages.h ../getdns/getdns.h |
287 | 285 | tests_stub_async.lo tests_stub_async.o: $(srcdir)/tests_stub_async.c ../config.h $(srcdir)/testmessages.h \ |
213 | 213 | |
214 | 214 | expected_changed_item = GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS; |
215 | 215 | |
216 | ASSERT_RC(getdns_context_set_follow_redirects(context, GETDNS_REDIRECTS_DO_NOT_FOLLOW), | |
217 | GETDNS_RETURN_GOOD, "Return code from getdns_context_set_follow_redirects()"); | |
216 | (void) getdns_context_set_follow_redirects(context, GETDNS_REDIRECTS_DO_NOT_FOLLOW); | |
218 | 217 | |
219 | 218 | CONTEXT_DESTROY; |
220 | 219 |
95 | 95 | { |
96 | 96 | /* |
97 | 97 | * timeout is 0 |
98 | * expect: GETDNS_RETURN_INVALID_PARAMETER | |
98 | * expect: GETDNS_RETURN_GOOD | |
99 | 99 | */ |
100 | 100 | |
101 | 101 | struct getdns_context *context = NULL; |
102 | 102 | CONTEXT_CREATE(TRUE); |
103 | 103 | |
104 | 104 | ASSERT_RC(getdns_context_set_idle_timeout(context, 0), |
105 | GETDNS_RETURN_INVALID_PARAMETER, "Return code from getdns_context_set_timeout()"); | |
105 | GETDNS_RETURN_GOOD, "Return code from getdns_context_set_timeout()"); | |
106 | 106 | |
107 | 107 | CONTEXT_DESTROY; |
108 | 108 |
330 | 330 | } |
331 | 331 | END_TEST |
332 | 332 | |
333 | /* This test disabled because travis does not support IPv6 in their | |
334 | * container based infrastructure! | |
335 | */ | |
336 | #if 0 | |
333 | 337 | START_TEST (getdns_context_set_upstream_recursive_servers_10) |
334 | 338 | { |
335 | 339 | /* |
344 | 348 | struct getdns_dict *dict = NULL; |
345 | 349 | struct getdns_dict *response = NULL; |
346 | 350 | struct getdns_bindata address_type = { 5, (void *)"IPv6" }; |
347 | struct getdns_bindata address_data = { 16, (void *)"\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x44" }; | |
351 | struct getdns_bindata address_data = { 16, (void *)"\x26\x20\x00\x74\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01" }; | |
348 | 352 | size_t index = 0; |
349 | 353 | |
350 | 354 | CONTEXT_CREATE(TRUE); |
378 | 382 | DICT_DESTROY(response); |
379 | 383 | } |
380 | 384 | END_TEST |
381 | ||
385 | #endif | |
382 | 386 | START_TEST (getdns_context_set_upstream_recursive_servers_11) |
383 | 387 | { |
384 | 388 | /* |
459 | 463 | /* Positive test cases */ |
460 | 464 | TCase *tc_pos = tcase_create("Positive"); |
461 | 465 | tcase_add_test(tc_pos, getdns_context_set_upstream_recursive_servers_9); |
462 | tcase_add_test(tc_pos, getdns_context_set_upstream_recursive_servers_10); | |
466 | /***** tcase_add_test(tc_pos, getdns_context_set_upstream_recursive_servers_10); *****/ | |
463 | 467 | tcase_add_test(tc_pos, getdns_context_set_upstream_recursive_servers_11); |
464 | 468 | |
465 | 469 | suite_add_tcase(s, tc_pos); |
25 | 25 | */ |
26 | 26 | |
27 | 27 | #include "config.h" |
28 | #include "debug.h" | |
28 | 29 | #include <stdio.h> |
29 | 30 | #include <stdlib.h> |
30 | 31 | #include <string.h> |
31 | 32 | #include <inttypes.h> |
32 | 33 | #include <getdns/getdns.h> |
33 | 34 | #include <getdns/getdns_extra.h> |
34 | #include "util-internal.h" | |
35 | 35 | |
36 | 36 | #define MAX_TIMEOUTS FD_SETSIZE |
37 | ||
38 | #define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" | |
37 | 39 | |
38 | 40 | /* Eventloop based on select */ |
39 | 41 | typedef struct my_eventloop { |
259 | 261 | static char *name; |
260 | 262 | static getdns_context *context; |
261 | 263 | static getdns_dict *extensions; |
264 | static getdns_list *pubkey_pinset = NULL; | |
265 | static size_t pincount = 0; | |
262 | 266 | static uint16_t request_type = GETDNS_RRTYPE_NS; |
263 | 267 | static int timeout, edns0_size, padding_blocksize; |
264 | 268 | static int async = 0, interactive = 0; |
265 | 269 | static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; |
266 | 270 | |
267 | 271 | int get_rrtype(const char *t); |
272 | ||
273 | int gqldns_b64_pton(char const *src, uint8_t *target, size_t targsize) | |
274 | { | |
275 | const uint8_t pad64 = 64; /* is 64th in the b64 array */ | |
276 | const char* s = src; | |
277 | uint8_t in[4]; | |
278 | size_t o = 0, incount = 0; | |
279 | ||
280 | while(*s) { | |
281 | /* skip any character that is not base64 */ | |
282 | /* conceptually we do: | |
283 | const char* b64 = pad'=' is appended to array | |
284 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
285 | const char* d = strchr(b64, *s++); | |
286 | and use d-b64; | |
287 | */ | |
288 | char d = *s++; | |
289 | if(d <= 'Z' && d >= 'A') | |
290 | d -= 'A'; | |
291 | else if(d <= 'z' && d >= 'a') | |
292 | d = d - 'a' + 26; | |
293 | else if(d <= '9' && d >= '0') | |
294 | d = d - '0' + 52; | |
295 | else if(d == '+') | |
296 | d = 62; | |
297 | else if(d == '/') | |
298 | d = 63; | |
299 | else if(d == '=') | |
300 | d = 64; | |
301 | else continue; | |
302 | in[incount++] = (uint8_t)d; | |
303 | if(incount != 4) | |
304 | continue; | |
305 | /* process whole block of 4 characters into 3 output bytes */ | |
306 | if(in[3] == pad64 && in[2] == pad64) { /* A B = = */ | |
307 | if(o+1 > targsize) | |
308 | return -1; | |
309 | target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); | |
310 | o += 1; | |
311 | break; /* we are done */ | |
312 | } else if(in[3] == pad64) { /* A B C = */ | |
313 | if(o+2 > targsize) | |
314 | return -1; | |
315 | target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); | |
316 | target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); | |
317 | o += 2; | |
318 | break; /* we are done */ | |
319 | } else { | |
320 | if(o+3 > targsize) | |
321 | return -1; | |
322 | /* write xxxxxxyy yyyyzzzz zzwwwwww */ | |
323 | target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); | |
324 | target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); | |
325 | target[o+2]= ((in[2]&0x03)<<6) | in[3]; | |
326 | o += 3; | |
327 | } | |
328 | incount = 0; | |
329 | } | |
330 | return (int)o; | |
331 | } | |
268 | 332 | |
269 | 333 | getdns_dict * |
270 | 334 | ipaddr_dict(getdns_context *context, char *ipstr) |
274 | 338 | char *p = strchr(ipstr, '@'), *portstr = ""; |
275 | 339 | char *t = strchr(ipstr, '#'), *tls_portstr = ""; |
276 | 340 | char *n = strchr(ipstr, '~'), *tls_namestr = ""; |
341 | /* ^[alg:]name:key */ | |
342 | char *T = strchr(ipstr, '^'), *tsig_name_str = "" | |
343 | , *tsig_secret_str = "" | |
344 | , *tsig_algorithm_str = ""; | |
345 | int tsig_secret_size; | |
346 | uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */ | |
347 | getdns_bindata tsig_secret; | |
277 | 348 | uint8_t buf[sizeof(struct in6_addr)]; |
278 | 349 | getdns_bindata addr; |
279 | 350 | |
295 | 366 | if (n) { |
296 | 367 | *n = 0; |
297 | 368 | tls_namestr = n + 1; |
369 | } | |
370 | if (T) { | |
371 | *T = 0; | |
372 | tsig_name_str = T + 1; | |
373 | if ((T = strchr(tsig_name_str, ':'))) { | |
374 | *T = 0; | |
375 | tsig_secret_str = T + 1; | |
376 | if ((T = strchr(tsig_secret_str, ':'))) { | |
377 | *T = 0; | |
378 | tsig_algorithm_str = tsig_name_str; | |
379 | tsig_name_str = tsig_secret_str; | |
380 | tsig_secret_str = T + 1; | |
381 | } | |
382 | } else { | |
383 | tsig_name_str = ""; | |
384 | } | |
298 | 385 | } |
299 | 386 | if (strchr(ipstr, ':')) { |
300 | 387 | getdns_dict_util_set_string(r, "address_type", "IPv6"); |
321 | 408 | } |
322 | 409 | if (*scope_id_str) |
323 | 410 | getdns_dict_util_set_string(r, "scope_id", scope_id_str); |
324 | ||
411 | if (*tsig_name_str) | |
412 | getdns_dict_util_set_string(r, "tsig_name", tsig_name_str); | |
413 | if (*tsig_algorithm_str) | |
414 | getdns_dict_util_set_string(r, "tsig_algorithm", tsig_algorithm_str); | |
415 | if (*tsig_secret_str) { | |
416 | tsig_secret_size = gqldns_b64_pton( | |
417 | tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf)); | |
418 | if (tsig_secret_size > 0) { | |
419 | tsig_secret.size = tsig_secret_size; | |
420 | tsig_secret.data = tsig_secret_buf; | |
421 | getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret); | |
422 | } | |
423 | } | |
325 | 424 | return r; |
326 | 425 | } |
327 | 426 | |
344 | 443 | case 'L': |
345 | 444 | transports[i] = GETDNS_TRANSPORT_TLS; |
346 | 445 | break; |
347 | case 'S': | |
348 | transports[i] = GETDNS_TRANSPORT_STARTTLS; | |
349 | break; | |
350 | 446 | default: |
351 | 447 | fprintf(stderr, "Unrecognised transport '%c' in string %s\n", |
352 | 448 | *(transport_list_str + i), transport_list_str); |
359 | 455 | void |
360 | 456 | print_usage(FILE *out, const char *progname) |
361 | 457 | { |
362 | fprintf(out, "usage: %s [@<server>] [+extension] [<name>] [<type>]\n", | |
363 | progname); | |
364 | fprintf(out, "options:\n"); | |
458 | fprintf(out, "usage: %s [<option> ...] \\\n" | |
459 | "\t\t[@<upstream> ...] [+<extension> ...] [<name>] [<type>]\n", progname); | |
460 | fprintf(out, "\nupstreams: @<ip>[%%<scope_id>][@<port>][#<tls port>][~<tls name>][^<tsig spec>]\n"); | |
461 | fprintf(out, "\ntsig spec: [<algorithm>:]<name>:<secret in Base64>\n"); | |
462 | fprintf(out, "\nextensions:\n"); | |
463 | fprintf(out, "\t+add_warning_for_bad_dns\n"); | |
464 | fprintf(out, "\t+dnssec_return_status\n"); | |
465 | fprintf(out, "\t+dnssec_return_only_secure\n"); | |
466 | fprintf(out, "\t+dnssec_return_validation_chain\n"); | |
467 | #ifdef DNSSEC_ROADBLOCK_AVOIDANCE | |
468 | fprintf(out, "\t+dnssec_roadblock_avoidance\n"); | |
469 | #endif | |
470 | #ifdef EDNS_COOKIES | |
471 | fprintf(out, "\t+edns_cookies\n"); | |
472 | #endif | |
473 | fprintf(out, "\t+return_both_v4_and_v6\n"); | |
474 | fprintf(out, "\t+return_call_reporting\n"); | |
475 | fprintf(out, "\t+sit=<cookie>\t\tSend along cookie OPT with value <cookie>\n"); | |
476 | fprintf(out, "\t+specify_class=<class>\n"); | |
477 | fprintf(out, "\t+0\t\t\tClear all extensions\n"); | |
478 | fprintf(out, "\noptions:\n"); | |
365 | 479 | fprintf(out, "\t-a\tPerform asynchronous resolution " |
366 | 480 | "(default = synchronous)\n"); |
367 | 481 | fprintf(out, "\t-A\taddress lookup (<type> is ignored)\n"); |
372 | 486 | fprintf(out, "\t-d\tclear edns0 do bit\n"); |
373 | 487 | fprintf(out, "\t-e <idle_timeout>\tSet idle timeout in miliseconds\n"); |
374 | 488 | fprintf(out, "\t-F <filename>\tread the queries from the specified file\n"); |
489 | fprintf(out, "\t-f <filename>\tRead DNSSEC trust anchors from <filename>\n"); | |
375 | 490 | fprintf(out, "\t-G\tgeneral lookup\n"); |
376 | 491 | fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> is ignored)\n"); |
377 | 492 | fprintf(out, "\t-h\tPrint this help\n"); |
380 | 495 | fprintf(out, "\t-j\tOutput json response dict\n"); |
381 | 496 | fprintf(out, "\t-J\tPretty print json response dict\n"); |
382 | 497 | fprintf(out, "\t-k\tPrint root trust anchors\n"); |
498 | fprintf(out, "\t-K <pin>\tPin a public key for TLS connections (can repeat)\n"); | |
499 | fprintf(out, "\t\t(should look like '" EXAMPLE_PIN "')\n"); | |
383 | 500 | fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n"); |
384 | fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n"); | |
501 | fprintf(out, "\t-m\tSet TLS authentication mode to REQUIRED\n"); | |
385 | 502 | fprintf(out, "\t-p\tPretty print response dict\n"); |
386 | 503 | fprintf(out, "\t-P <blocksize>\tPad TLS queries to a multiple of blocksize\n"); |
387 | 504 | fprintf(out, "\t-r\tSet recursing resolution type\n"); |
505 | fprintf(out, "\t-R <filename>\tRead root hints from <filename>\n"); | |
388 | 506 | fprintf(out, "\t-q\tQuiet mode - don't print response\n"); |
389 | 507 | fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); |
390 | 508 | fprintf(out, "\t-S\tservice lookup (<type> is ignored)\n"); |
391 | 509 | fprintf(out, "\t-t <timeout>\tSet timeout in miliseconds\n"); |
510 | ||
511 | fprintf(out, "\t-W\tAppend suffix always (default)\n"); | |
512 | fprintf(out, "\t-1\tAppend suffix only to single label after failure\n"); | |
513 | fprintf(out, "\t-M\tAppend suffix only to multi label name after failure\n"); | |
514 | fprintf(out, "\t-N\tNever append a suffix\n"); | |
515 | fprintf(out, "\t-Z <suffixes>\tSet suffixes with the given comma separed list\n"); | |
516 | ||
392 | 517 | fprintf(out, "\t-T\tSet transport to TCP only\n"); |
393 | 518 | fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n"); |
394 | 519 | fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n"); |
395 | 520 | fprintf(out, "\t-E\tSet transport to TLS with TCP fallback only keep connections open\n"); |
396 | fprintf(out, "\t-R\tSet transport to STARTTLS with TCP fallback only keep connections open\n"); | |
397 | 521 | fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n"); |
398 | 522 | fprintf(out, "\t-U\tSet transport to UDP only\n"); |
399 | 523 | fprintf(out, "\t-l <transports>\tSet transport list. List can contain 1 of each of the characters\n"); |
400 | fprintf(out, "\t\t\t U T L S for UDP, TCP, TLS or STARTTLS e.g 'UT' or 'LST' \n"); | |
524 | fprintf(out, "\t\t\t U T L S for UDP, TCP or TLS e.g 'UT' or 'LTU' \n"); | |
401 | 525 | |
402 | 526 | } |
403 | 527 | |
415 | 539 | if (!(to_validate = getdns_list_create())) |
416 | 540 | return GETDNS_RETURN_MEMORY_ERROR; |
417 | 541 | |
418 | trust_anchor = getdns_root_trust_anchor(NULL); | |
542 | if (getdns_context_get_dnssec_trust_anchors(context, &trust_anchor)) | |
543 | trust_anchor = getdns_root_trust_anchor(NULL); | |
419 | 544 | |
420 | 545 | if ((r = getdns_dict_get_list( |
421 | 546 | response, "validation_chain", &validation_chain))) |
454 | 579 | if ((r = getdns_list_set_dict(to_validate, 0, reply))) |
455 | 580 | goto error; |
456 | 581 | |
457 | fprintf( stdout | |
458 | , "reply %zu, dnssec_status: ", i); | |
582 | printf("reply %u, dnssec_status: ", (unsigned)i); | |
459 | 583 | switch ((s = getdns_validate_dnssec( |
460 | 584 | to_validate, validation_chain, trust_anchor))) { |
461 | 585 | |
503 | 627 | } |
504 | 628 | |
505 | 629 | if (callback_type == GETDNS_CALLBACK_COMPLETE) { |
506 | fprintf(stdout, | |
507 | "Response code was: GOOD. Status was: Callback with ID %llu was successfull.\n", | |
508 | (unsigned long long)trans_id); | |
630 | printf("Response code was: GOOD. Status was: Callback with ID %"PRIu64" was successfull.\n", | |
631 | trans_id); | |
509 | 632 | |
510 | 633 | } else if (callback_type == GETDNS_CALLBACK_CANCEL) |
511 | 634 | fprintf(stderr, |
512 | "An error occurred: The callback with ID %llu was cancelled. Exiting.\n", | |
513 | (unsigned long long)trans_id); | |
635 | "An error occurred: The callback with ID %"PRIu64" was cancelled. Exiting.\n", | |
636 | trans_id); | |
514 | 637 | else { |
515 | 638 | fprintf(stderr, |
516 | 639 | "An error occurred: The callback got a callback_type of %d. Exiting.\n", |
581 | 704 | getdns_return_t parse_args(int argc, char **argv) |
582 | 705 | { |
583 | 706 | getdns_return_t r = GETDNS_RETURN_GOOD; |
584 | size_t i; | |
707 | size_t i, j; | |
585 | 708 | char *arg, *c, *endptr; |
586 | 709 | int t, print_api_info = 0, print_trust_anchors = 0; |
587 | 710 | getdns_list *upstream_list = NULL; |
588 | getdns_list *tas = NULL; | |
711 | getdns_list *tas = NULL, *hints = NULL; | |
712 | getdns_dict *pubkey_pin = NULL; | |
713 | getdns_list *suffixes; | |
714 | char *suffix; | |
715 | getdns_bindata bindata; | |
589 | 716 | size_t upstream_count = 0; |
717 | FILE *fh; | |
718 | uint32_t klass; | |
590 | 719 | |
591 | 720 | for (i = 1; i < argc; i++) { |
592 | 721 | arg = argv[i]; |
602 | 731 | " %d", r); |
603 | 732 | break; |
604 | 733 | } |
734 | } else if (strncmp(arg+1, "specify_class=", 14) == 0) { | |
735 | if (strncasecmp(arg+15, "IN", 3) == 0) | |
736 | r = getdns_dict_set_int(extensions, | |
737 | "specify_class", GETDNS_RRCLASS_IN); | |
738 | else if (strncasecmp(arg+15, "CH", 3) == 0) | |
739 | r = getdns_dict_set_int(extensions, | |
740 | "specify_class", GETDNS_RRCLASS_CH); | |
741 | else if (strncasecmp(arg+15, "HS", 3) == 0) | |
742 | r = getdns_dict_set_int(extensions, | |
743 | "specify_class", GETDNS_RRCLASS_HS); | |
744 | else if (strncasecmp(arg+15, "NONE", 5) == 0) | |
745 | r = getdns_dict_set_int(extensions, | |
746 | "specify_class", GETDNS_RRCLASS_NONE); | |
747 | else if (strncasecmp(arg+15, "ANY", 4) == 0) | |
748 | r = getdns_dict_set_int(extensions, | |
749 | "specify_class", GETDNS_RRCLASS_ANY); | |
750 | else if (strncasecmp(arg+15, "CLASS", 5) == 0) { | |
751 | klass = strtol(arg + 20, &endptr, 10); | |
752 | if (*endptr || klass > 255) | |
753 | fprintf(stderr, | |
754 | "Unknown class: %s\n", | |
755 | arg+15); | |
756 | else | |
757 | r = getdns_dict_set_int(extensions, | |
758 | "specify_class", klass); | |
759 | ||
760 | } else | |
761 | fprintf(stderr, | |
762 | "Unknown class: %s\n", arg+15); | |
605 | 763 | } else if (arg[1] == '0') { |
606 | 764 | /* Unset all existing extensions*/ |
607 | 765 | getdns_dict_destroy(extensions); |
666 | 824 | case 'd': |
667 | 825 | (void) getdns_context_set_edns_do_bit(context, 0); |
668 | 826 | break; |
827 | case 'f': | |
828 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { | |
829 | fprintf(stderr, "file name expected " | |
830 | "after -f\n"); | |
831 | return GETDNS_RETURN_GENERIC_ERROR; | |
832 | } | |
833 | if (!(fh = fopen(argv[i], "r"))) { | |
834 | fprintf(stderr, "Could not open \"%s\"" | |
835 | ": %s\n",argv[i], strerror(errno)); | |
836 | return GETDNS_RETURN_GENERIC_ERROR; | |
837 | } | |
838 | if (getdns_fp2rr_list(fh, &tas, NULL, 3600)) { | |
839 | fprintf(stderr,"Could not parse " | |
840 | "\"%s\"\n", argv[i]); | |
841 | return GETDNS_RETURN_GENERIC_ERROR; | |
842 | } | |
843 | fclose(fh); | |
844 | if (getdns_context_set_dnssec_trust_anchors( | |
845 | context, tas)) { | |
846 | fprintf(stderr,"Could not set " | |
847 | "trust anchors from \"%s\"\n", | |
848 | argv[i]); | |
849 | return GETDNS_RETURN_GENERIC_ERROR; | |
850 | } | |
851 | getdns_list_destroy(tas); | |
852 | tas = NULL; | |
853 | break; | |
669 | 854 | case 'F': |
670 | 855 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { |
671 | 856 | fprintf(stderr, "file name expected " |
696 | 881 | case 'J': |
697 | 882 | json = 1; |
698 | 883 | break; |
884 | case 'K': | |
885 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { | |
886 | fprintf(stderr, "pin string of the form " | |
887 | EXAMPLE_PIN | |
888 | "expected after -K\n"); | |
889 | return GETDNS_RETURN_GENERIC_ERROR; | |
890 | } | |
891 | pubkey_pin = getdns_pubkey_pin_create_from_string(context, | |
892 | argv[i]); | |
893 | if (pubkey_pin == NULL) { | |
894 | fprintf(stderr, "could not convert '%s' into a " | |
895 | "public key pin.\n" | |
896 | "Good pins look like: " EXAMPLE_PIN "\n" | |
897 | "Please see RFC 7469 for details about " | |
898 | "the format\n", argv[i]); | |
899 | return GETDNS_RETURN_GENERIC_ERROR; | |
900 | } | |
901 | if (pubkey_pinset == NULL) | |
902 | pubkey_pinset = getdns_list_create_with_context(context); | |
903 | if (r = getdns_list_set_dict(pubkey_pinset, pincount++, | |
904 | pubkey_pin), r) { | |
905 | fprintf(stderr, "Failed to add pin to pinset (error %d: %s)\n", | |
906 | r, getdns_get_errorstr_by_id(r)); | |
907 | getdns_dict_destroy(pubkey_pin); | |
908 | pubkey_pin = NULL; | |
909 | return GETDNS_RETURN_GENERIC_ERROR; | |
910 | } | |
911 | getdns_dict_destroy(pubkey_pin); | |
912 | pubkey_pin = NULL; | |
913 | break; | |
699 | 914 | case 'k': |
700 | 915 | print_trust_anchors = 1; |
701 | 916 | break; |
705 | 920 | break; |
706 | 921 | case 'm': |
707 | 922 | getdns_context_set_tls_authentication(context, |
708 | GETDNS_AUTHENTICATION_HOSTNAME); | |
923 | GETDNS_AUTHENTICATION_REQUIRED); | |
709 | 924 | break; |
710 | 925 | case 'P': |
711 | 926 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { |
733 | 948 | getdns_context_set_resolution_type( |
734 | 949 | context, |
735 | 950 | GETDNS_RESOLUTION_RECURSING); |
951 | break; | |
952 | case 'R': | |
953 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { | |
954 | fprintf(stderr, "file name expected " | |
955 | "after -f\n"); | |
956 | return GETDNS_RETURN_GENERIC_ERROR; | |
957 | } | |
958 | if (!(fh = fopen(argv[i], "r"))) { | |
959 | fprintf(stderr, "Could not open \"%s\"" | |
960 | ": %s\n",argv[i], strerror(errno)); | |
961 | return GETDNS_RETURN_GENERIC_ERROR; | |
962 | } | |
963 | if (getdns_fp2rr_list(fh, &hints, NULL, 3600)) { | |
964 | fprintf(stderr,"Could not parse " | |
965 | "\"%s\"\n", argv[i]); | |
966 | return GETDNS_RETURN_GENERIC_ERROR; | |
967 | } | |
968 | fclose(fh); | |
969 | if (getdns_context_set_dns_root_servers( | |
970 | context, hints)) { | |
971 | fprintf(stderr,"Could not set " | |
972 | "root servers from \"%s\"\n", | |
973 | argv[i]); | |
974 | return GETDNS_RETURN_GENERIC_ERROR; | |
975 | } | |
976 | getdns_list_destroy(hints); | |
977 | hints = NULL; | |
736 | 978 | break; |
737 | 979 | case 's': |
738 | 980 | getdns_context_set_resolution_type( |
773 | 1015 | getdns_context_set_idle_timeout( |
774 | 1016 | context, timeout); |
775 | 1017 | goto next; |
1018 | case 'W': | |
1019 | (void) getdns_context_set_append_name(context, | |
1020 | GETDNS_APPEND_NAME_ALWAYS); | |
1021 | break; | |
1022 | case '1': | |
1023 | (void) getdns_context_set_append_name(context, | |
1024 | GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE); | |
1025 | break; | |
1026 | case 'M': | |
1027 | (void) getdns_context_set_append_name(context, | |
1028 | GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE); | |
1029 | break; | |
1030 | case 'N': | |
1031 | (void) getdns_context_set_append_name(context, | |
1032 | GETDNS_APPEND_NAME_NEVER); | |
1033 | break; | |
1034 | case 'Z': | |
1035 | if (c[1] != 0 || ++i >= argc || !*argv[i]) { | |
1036 | fprintf(stderr, "suffixes expected" | |
1037 | "after -Z\n"); | |
1038 | return GETDNS_RETURN_GENERIC_ERROR; | |
1039 | } | |
1040 | if (!(suffixes = getdns_list_create())) | |
1041 | return GETDNS_RETURN_MEMORY_ERROR; | |
1042 | suffix = strtok(argv[i], ","); | |
1043 | j = 0; | |
1044 | while (suffix) { | |
1045 | bindata.size = strlen(suffix); | |
1046 | bindata.data = (void *)suffix; | |
1047 | (void) getdns_list_set_bindata( | |
1048 | suffixes, j++, &bindata); | |
1049 | suffix = strtok(NULL, ","); | |
1050 | } | |
1051 | (void) getdns_context_set_suffix(context, | |
1052 | suffixes); | |
1053 | getdns_list_destroy(suffixes); | |
1054 | goto next; | |
776 | 1055 | case 'T': |
777 | 1056 | getdns_context_set_dns_transport(context, |
778 | 1057 | GETDNS_TRANSPORT_TCP_ONLY); |
788 | 1067 | case 'E': |
789 | 1068 | getdns_context_set_dns_transport(context, |
790 | 1069 | GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); |
791 | break; | |
792 | case 'R': | |
793 | getdns_context_set_dns_transport(context, | |
794 | GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); | |
795 | 1070 | break; |
796 | 1071 | case 'u': |
797 | 1072 | getdns_context_set_dns_transport(context, |
818 | 1093 | break; |
819 | 1094 | case 'B': |
820 | 1095 | batch_mode = 1; |
821 | break; | |
1096 | break; | |
822 | 1097 | |
823 | 1098 | |
824 | 1099 | default: |
833 | 1108 | } |
834 | 1109 | if (r) |
835 | 1110 | return r; |
1111 | if (pubkey_pinset && upstream_count) { | |
1112 | getdns_dict *upstream; | |
1113 | /* apply the accumulated pubkey pinset to all upstreams: */ | |
1114 | for (i = 0; i < upstream_count; i++) { | |
1115 | if (r = getdns_list_get_dict(upstream_list, i, &upstream), r) { | |
1116 | fprintf(stderr, "Failed to get upstream %lu when adding pinset\n", (long unsigned int)i); | |
1117 | return r; | |
1118 | } | |
1119 | if (r = getdns_dict_set_list(upstream, "tls_pubkey_pinset", pubkey_pinset), r) { | |
1120 | fprintf(stderr, "Failed to set pubkey pinset on upstream %lu\n", (long unsigned int)i); | |
1121 | return r; | |
1122 | } | |
1123 | } | |
1124 | } | |
836 | 1125 | if (upstream_count && |
837 | 1126 | (r = getdns_context_set_upstream_recursive_servers( |
838 | 1127 | context, upstream_list))) { |
844 | 1133 | return CONTINUE; |
845 | 1134 | } |
846 | 1135 | if (print_trust_anchors) { |
847 | if ((tas = getdns_root_trust_anchor(NULL))) { | |
1136 | if (!getdns_context_get_dnssec_trust_anchors(context, &tas)) { | |
1137 | /* if ((tas = getdns_root_trust_anchor(NULL))) { */ | |
848 | 1138 | fprintf(stdout, "%s\n", getdns_pretty_print_list(tas)); |
849 | 1139 | return CONTINUE; |
850 | 1140 | } else |
0 | #include <stdio.h> | |
1 | #include <getdns/getdns.h> | |
2 | #include <getdns/getdns_extra.h> | |
3 | ||
4 | int main() | |
5 | { | |
6 | getdns_return_t r = GETDNS_RETURN_MEMORY_ERROR; | |
7 | getdns_dict *dict = NULL; | |
8 | unsigned char bladiebla_str[] = "bla die bla"; | |
9 | getdns_bindata bladiebla = { sizeof(bladiebla_str), bladiebla_str }; | |
10 | ||
11 | if (!(dict = getdns_dict_create())) | |
12 | fprintf(stderr, "Could not create dict"); | |
13 | ||
14 | else if ((r = getdns_dict_set_int(dict, "/bla/bloe/blie", 53280)) | |
15 | || (r = getdns_dict_set_int(dict, "/bla/hola", 53281)) | |
16 | || (r = getdns_dict_set_int(dict, "/bla/cola/-", 1)) | |
17 | || (r = getdns_dict_set_int(dict, "/bla/cola/-", 2)) | |
18 | || (r = getdns_dict_set_int(dict, "/bla/cola/-/drie", 3)) | |
19 | || (r = getdns_dict_set_int(dict, "/bla/cola/-", 4)) | |
20 | || (r = getdns_dict_set_int(dict, "/bla/cola/1", 5)) | |
21 | || (r = getdns_dict_set_int(dict, "/bla/cola/2/zes", 6)) | |
22 | || (r = getdns_dict_set_bindata(dict, "/die/bla", &bladiebla)) | |
23 | ) | |
24 | fprintf(stderr, "Error setting dict data"); | |
25 | else { | |
26 | char *dict_str = getdns_pretty_print_dict(dict); | |
27 | ||
28 | if (!dict_str) { | |
29 | fprintf(stderr, "Could not convert dict to string"); | |
30 | r = GETDNS_RETURN_MEMORY_ERROR; | |
31 | } else { | |
32 | printf("%s\n", dict_str); | |
33 | free(dict_str); | |
34 | } | |
35 | } | |
36 | if (r) | |
37 | fprintf(stderr, ": %s\n", getdns_get_errorstr_by_id(r)); | |
38 | ||
39 | if (dict) | |
40 | getdns_dict_destroy(dict); | |
41 | ||
42 | if (r) | |
43 | exit(EXIT_FAILURE); | |
44 | ||
45 | exit(EXIT_SUCCESS); | |
46 | } |
0 | { | |
1 | "bla": | |
2 | { | |
3 | "bloe": | |
4 | { | |
5 | "blie": 53280 | |
6 | }, | |
7 | "cola": | |
8 | [ | |
9 | 1, | |
10 | 5, | |
11 | { | |
12 | "drie": 3, | |
13 | "zes": 6 | |
14 | }, | |
15 | 4 | |
16 | ], | |
17 | "hola": 53281 | |
18 | }, | |
19 | "die": | |
20 | { | |
21 | "bla": <bindata of "bla die bla"> | |
22 | } | |
23 | } |
46 | 46 | #define TRANSPORT_PIPELINE "pipeline" |
47 | 47 | #define TRANSPORT_TLS_KEEPOPEN "tls" |
48 | 48 | #define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls" |
49 | #define TRANSPORT_STARTTLS_TCP_KEEPOPEN "starttls" | |
50 | 49 | #define RESOLUTION_STUB "stub" |
51 | 50 | #define RESOLUTION_REC "rec" |
52 | 51 | |
110 | 109 | getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN); |
111 | 110 | else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0) |
112 | 111 | getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); |
113 | else if (strncmp(transport, TRANSPORT_STARTTLS_TCP_KEEPOPEN, 8) == 0) | |
114 | getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); | |
115 | 112 | else if (strncmp(transport, TRANSPORT_UDP_TCP, 3) != 0) { |
116 | 113 | fprintf(stderr, "Invalid transport %s, must be one of udp, udp_tcp, tcp or pipeline\n", transport); |
117 | 114 | exit(EXIT_FAILURE); |
2 | 2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) |
3 | 3 | SERVER_IP="8.8.8.8" |
4 | 4 | TLS_SERVER_IP="185.49.141.38~getdnsapi.net" |
5 | TLS_SERVER_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9S=" | |
6 | TLS_SERVER_WRONG_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc1S=" | |
5 | 7 | GOOD_RESULT_SYNC="Status was: At least one response was returned" |
6 | 8 | GOOD_RESULT_ASYNC="successfull" |
7 | 9 | BAD_RESULT_SYNC="1 'Generic error'" |
48 | 50 | echo "it can be used to check the basic functionality for now. It is recommended that" |
49 | 51 | echo "local or known test servers are used, but it should work with the default servers:" |
50 | 52 | echo " - Google Open DNS for TCP and UDP only " |
51 | echo "- the getdnsapi.net test server Open Resolver for TLS, STARTTLS, TCP and UDP" | |
53 | echo "- the getdnsapi.net test server Open Resolver for TLS, TCP and UDP" | |
52 | 54 | echo "NOTE: By default this script assumes it is located in the same directory" |
53 | 55 | echo "as the getdns_query binary. If it is not, then the location of the binary" |
54 | 56 | echo "can be specified via the command line option." |
56 | 58 | echo "usage: test_transport.sh" |
57 | 59 | echo " -p path to getdns_query binary" |
58 | 60 | echo " -s server configured for only TCP and UDP" |
59 | echo " -t server configured for TLS, STARTTLS, TCP and UDP" | |
61 | echo " -t server configured for TLS, TCP and UDP" | |
60 | 62 | echo " (This must include the hostname e.g. 185.49.141.38~getdnsapi.net)" |
63 | echo " -k SPKI pin for server configured for TLS, TCP and UDP" | |
61 | 64 | } |
62 | 65 | |
63 | while getopts ":p:s:t:dh" opt; do | |
66 | while getopts ":p:s:t:k:dh" opt; do | |
64 | 67 | case $opt in |
65 | 68 | d ) set -x ;; |
66 | 69 | p ) DIR=$OPTARG ;; |
67 | 70 | s ) SERVER_IP=$OPTARG ; echo "Setting server to $OPTARG" ;; |
68 | 71 | t ) TLS_SERVER_IP=$OPTARG ; echo "Setting TLS server to $OPTARG" ;; |
72 | k ) TLS_SERVER_KEY=$OPTARG ; echo "Setting TLS server key to $OPTARG" ;; | |
69 | 73 | h ) usage ; exit ;; |
70 | 74 | esac |
71 | 75 | done |
72 | 76 | |
73 | 77 | TLS_SERVER_IP_NO_NAME=`echo ${TLS_SERVER_IP%~*}` |
74 | 78 | echo $TLS_SERVER_IP_NO_NAME |
79 | TLS_SERVER_IP_WRONG_NAME=`echo ${TLS_SERVER_IP::${#TLS_SERVER_IP}-1}` | |
75 | 80 | |
76 | 81 | GOOD_QUERIES=( |
77 | 82 | "-s -A -q getdnsapi.net -l U @${SERVER_IP} " |
78 | 83 | "-s -A -q getdnsapi.net -l T @${SERVER_IP} " |
79 | 84 | "-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP_NO_NAME}" |
80 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}") | |
81 | #"-s -A -q getdnsapi.net -l S @${TLS_SERVER_IP_NO_NAME}") | |
85 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}" | |
86 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" | |
87 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"" | |
88 | "-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") | |
82 | 89 | |
83 | 90 | GOOD_FALLBACK_QUERIES=( |
84 | 91 | "-s -A -q getdnsapi.net -l LT @${SERVER_IP}" |
89 | 96 | "-s -G -q DNSKEY getdnsapi.net -l UT @${SERVER_IP} -b 512 -D") |
90 | 97 | |
91 | 98 | NOT_AVAILABLE_QUERIES=( |
92 | "-s -A -q getdnsapi.net -l L @${SERVER_IP} " | |
93 | #"-s -A -q getdnsapi.net -l S @${SERVER_IP} " | |
94 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} " | |
95 | "-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") | |
99 | "-s -A -q getdnsapi.net -l L @${SERVER_IP}" | |
100 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME}" | |
101 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME}" | |
102 | "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} ${TLS_SERVER_WRONG_KEY}") | |
103 | ||
96 | 104 | |
97 | 105 | echo "Starting transport test" |
98 | 106 | echo |
115 | 115 | #define TIMEOUT_FOREVER ((int64_t)-1) |
116 | 116 | #define ASSERT_UNREACHABLE 0 |
117 | 117 | |
118 | #define GETDNS_TRANSPORTS_MAX 4 | |
119 | #define GETDNS_UPSTREAM_TRANSPORTS 3 | |
118 | #define GETDNS_TRANSPORTS_MAX 3 | |
119 | #define GETDNS_UPSTREAM_TRANSPORTS 2 | |
120 | 120 | |
121 | 121 | /** @} |
122 | 122 | */ |
202 | 202 | /* request type */ |
203 | 203 | uint16_t request_type; |
204 | 204 | |
205 | /* request class */ | |
206 | uint16_t request_class; | |
207 | ||
208 | 205 | /* dnssec status */ |
209 | 206 | int dnssec_status; |
207 | ||
208 | /* tsig status: | |
209 | * GETDNS_DNSSEC_INDETERMINATE means "No TSIG processing" | |
210 | * GETDNS_DNSSEC_INSECURE means "TSIG sent, validate reply" | |
211 | * GETDNS_DNSSEC_SECURE means "Validated" | |
212 | * GETDNS_DNSSEC_BOGUS means "Validation failed" | |
213 | */ | |
214 | int tsig_status; | |
210 | 215 | |
211 | 216 | /* For stub resolving */ |
212 | 217 | struct getdns_upstream *upstream; |
222 | 227 | int edns_maximum_udp_payload_size; |
223 | 228 | uint16_t max_udp_payload_size; |
224 | 229 | |
230 | size_t keepalive_sent; | |
231 | ||
225 | 232 | /* Network requests scheduled to write after me */ |
226 | 233 | struct getdns_network_req *write_queue_tail; |
227 | 234 | |
228 | /* Some fields to record info for return_call_debugging */ | |
235 | /* Some fields to record info for return_call_reporting */ | |
229 | 236 | uint64_t debug_start_time; |
230 | 237 | uint64_t debug_end_time; |
231 | 238 | size_t debug_tls_auth_status; |
270 | 277 | /* name */ |
271 | 278 | uint8_t name[256]; |
272 | 279 | size_t name_len; |
280 | ||
281 | getdns_append_name_t append_name; | |
282 | const uint8_t *suffix; | |
283 | size_t suffix_len; | |
284 | int suffix_appended; | |
285 | ||
286 | uint16_t request_class; | |
273 | 287 | |
274 | 288 | /* canceled flag */ |
275 | 289 | int canceled; |
288 | 302 | int edns_cookies; |
289 | 303 | int edns_client_subnet_private; |
290 | 304 | uint16_t tls_query_padding_blocksize; |
291 | int return_call_debugging; | |
305 | int return_call_reporting; | |
306 | int add_warning_for_bad_dns; | |
292 | 307 | |
293 | 308 | /* Internally used by return_validation_chain */ |
294 | 309 | int dnssec_ok_checking_disabled; |
378 | 393 | uint16_t code, uint16_t sz, const void* data); |
379 | 394 | void _getdns_network_req_clear_upstream_options(getdns_network_req * req); |
380 | 395 | |
396 | /* Adds TSIG signature (if needed) and returns query length */ | |
397 | size_t _getdns_network_req_add_tsig(getdns_network_req *req); | |
398 | ||
399 | void _getdns_network_validate_tsig(getdns_network_req *req); | |
400 | ||
401 | void _getdns_netreq_reinit(getdns_network_req *netreq); | |
402 | ||
381 | 403 | #endif |
382 | 404 | /* types-internal.h */ |
34 | 34 | #define UTIL_LOG_H |
35 | 35 | |
36 | 36 | #include "config.h" |
37 | #include "util-internal.h" | |
37 | #include "debug.h" | |
38 | 38 | |
39 | 39 | #if defined(SEC_DEBUG) && SEC_DEBUG |
40 | 40 | #define verbose(x, ...) DEBUG_NL(__VA_ARGS__) |
0 | /* | |
1 | * util/winsock_event.c - implementation of the getdns winsock event handler. | |
2 | * | |
3 | * Copyright (c) 2015, Verisign/NLnet Labs. All rights reserved. | |
4 | * | |
5 | * This software is open source. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * Redistributions of source code must retain the above copyright notice, | |
12 | * this list of conditions and the following disclaimer. | |
13 | * | |
14 | * Redistributions in binary form must reproduce the above copyright notice, | |
15 | * this list of conditions and the following disclaimer in the documentation | |
16 | * and/or other materials provided with the distribution. | |
17 | * | |
18 | * Neither the name of the NLNET LABS/Verisign nor the names of its contributors may | |
19 | * be used to endorse or promote products derived from this software without | |
20 | * specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
26 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
28 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
29 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | /** | |
35 | * \file | |
36 | * Implementation of the getdns WinSock2 API event notification handler | |
37 | * for the getdns Windows port. | |
38 | * Code is originally from the Unbound source for Windows. | |
39 | */ | |
40 | ||
41 | #include "config.h" | |
42 | #ifdef USE_WINSOCK // only included for Windows builds | |
43 | #include <signal.h> | |
44 | #ifdef HAVE_TIME_H | |
45 | #include <time.h> | |
46 | #endif | |
47 | #include <sys/time.h> | |
48 | #include "util/winsock_event.h" | |
49 | #include "util/fptr_wlist.h" | |
50 | ||
51 | /** | |
52 | * implementation of log_err | |
53 | * @param format: format string printf-style. | |
54 | */ | |
55 | void | |
56 | log_err(const char *format, ...) | |
57 | { | |
58 | va_list args; | |
59 | va_start(args, format); | |
60 | fprintf(stderr, "error "); | |
61 | fprintf(stderr, format, args); | |
62 | va_end(args); | |
63 | } | |
64 | ||
65 | ||
66 | char* wsa_strerror(DWORD err) | |
67 | { | |
68 | static char unknown[32]; | |
69 | ||
70 | switch (err) { | |
71 | case WSA_INVALID_HANDLE: return "Specified event object handle is invalid."; | |
72 | case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available."; | |
73 | case WSA_INVALID_PARAMETER: return "One or more parameters are invalid."; | |
74 | case WSA_OPERATION_ABORTED: return "Overlapped operation aborted."; | |
75 | case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state."; | |
76 | case WSA_IO_PENDING: return "Overlapped operations will complete later."; | |
77 | case WSAEINTR: return "Interrupted function call."; | |
78 | case WSAEBADF: return "File handle is not valid."; | |
79 | case WSAEACCES: return "Permission denied."; | |
80 | case WSAEFAULT: return "Bad address."; | |
81 | case WSAEINVAL: return "Invalid argument."; | |
82 | case WSAEMFILE: return "Too many open files."; | |
83 | case WSAEWOULDBLOCK: return "Resource temporarily unavailable."; | |
84 | case WSAEINPROGRESS: return "Operation now in progress."; | |
85 | case WSAEALREADY: return "Operation already in progress."; | |
86 | case WSAENOTSOCK: return "Socket operation on nonsocket."; | |
87 | case WSAEDESTADDRREQ: return "Destination address required."; | |
88 | case WSAEMSGSIZE: return "Message too long."; | |
89 | case WSAEPROTOTYPE: return "Protocol wrong type for socket."; | |
90 | case WSAENOPROTOOPT: return "Bad protocol option."; | |
91 | case WSAEPROTONOSUPPORT: return "Protocol not supported."; | |
92 | case WSAESOCKTNOSUPPORT: return "Socket type not supported."; | |
93 | case WSAEOPNOTSUPP: return "Operation not supported."; | |
94 | case WSAEPFNOSUPPORT: return "Protocol family not supported."; | |
95 | case WSAEAFNOSUPPORT: return "Address family not supported by protocol family."; | |
96 | case WSAEADDRINUSE: return "Address already in use."; | |
97 | case WSAEADDRNOTAVAIL: return "Cannot assign requested address."; | |
98 | case WSAENETDOWN: return "Network is down."; | |
99 | case WSAENETUNREACH: return "Network is unreachable."; | |
100 | case WSAENETRESET: return "Network dropped connection on reset."; | |
101 | case WSAECONNABORTED: return "Software caused connection abort."; | |
102 | case WSAECONNRESET: return "Connection reset by peer."; | |
103 | case WSAENOBUFS: return "No buffer space available."; | |
104 | case WSAEISCONN: return "Socket is already connected."; | |
105 | case WSAENOTCONN: return "Socket is not connected."; | |
106 | case WSAESHUTDOWN: return "Cannot send after socket shutdown."; | |
107 | case WSAETOOMANYREFS: return "Too many references."; | |
108 | case WSAETIMEDOUT: return "Connection timed out."; | |
109 | case WSAECONNREFUSED: return "Connection refused."; | |
110 | case WSAELOOP: return "Cannot translate name."; | |
111 | case WSAENAMETOOLONG: return "Name too long."; | |
112 | case WSAEHOSTDOWN: return "Host is down."; | |
113 | case WSAEHOSTUNREACH: return "No route to host."; | |
114 | case WSAENOTEMPTY: return "Directory not empty."; | |
115 | case WSAEPROCLIM: return "Too many processes."; | |
116 | case WSAEUSERS: return "User quota exceeded."; | |
117 | case WSAEDQUOT: return "Disk quota exceeded."; | |
118 | case WSAESTALE: return "Stale file handle reference."; | |
119 | case WSAEREMOTE: return "Item is remote."; | |
120 | case WSASYSNOTREADY: return "Network subsystem is unavailable."; | |
121 | case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range."; | |
122 | case WSANOTINITIALISED: return "Successful WSAStartup not yet performed."; | |
123 | case WSAEDISCON: return "Graceful shutdown in progress."; | |
124 | case WSAENOMORE: return "No more results."; | |
125 | case WSAECANCELLED: return "Call has been canceled."; | |
126 | case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid."; | |
127 | case WSAEINVALIDPROVIDER: return "Service provider is invalid."; | |
128 | case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize."; | |
129 | case WSASYSCALLFAILURE: return "System call failure."; | |
130 | case WSASERVICE_NOT_FOUND: return "Service not found."; | |
131 | case WSATYPE_NOT_FOUND: return "Class type not found."; | |
132 | case WSA_E_NO_MORE: return "No more results."; | |
133 | case WSA_E_CANCELLED: return "Call was canceled."; | |
134 | case WSAEREFUSED: return "Database query was refused."; | |
135 | case WSAHOST_NOT_FOUND: return "Host not found."; | |
136 | case WSATRY_AGAIN: return "Nonauthoritative host not found."; | |
137 | case WSANO_RECOVERY: return "This is a nonrecoverable error."; | |
138 | case WSANO_DATA: return "Valid name, no data record of requested type."; | |
139 | case WSA_QOS_RECEIVERS: return "QOS receivers."; | |
140 | case WSA_QOS_SENDERS: return "QOS senders."; | |
141 | case WSA_QOS_NO_SENDERS: return "No QOS senders."; | |
142 | case WSA_QOS_NO_RECEIVERS: return "QOS no receivers."; | |
143 | case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed."; | |
144 | case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error."; | |
145 | case WSA_QOS_POLICY_FAILURE: return "QOS policy failure."; | |
146 | case WSA_QOS_BAD_STYLE: return "QOS bad style."; | |
147 | case WSA_QOS_BAD_OBJECT: return "QOS bad object."; | |
148 | case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error."; | |
149 | case WSA_QOS_GENERIC_ERROR: return "QOS generic error."; | |
150 | case WSA_QOS_ESERVICETYPE: return "QOS service type error."; | |
151 | case WSA_QOS_EFLOWSPEC: return "QOS flowspec error."; | |
152 | case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer."; | |
153 | case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style."; | |
154 | case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type."; | |
155 | case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count."; | |
156 | case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length."; | |
157 | case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count."; | |
158 | /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/ | |
159 | case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object."; | |
160 | case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor."; | |
161 | case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec."; | |
162 | case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec."; | |
163 | case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object."; | |
164 | case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object."; | |
165 | case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type."; | |
166 | default: | |
167 | snprintf(unknown, sizeof(unknown), | |
168 | "unknown WSA error code %d", (int)err); | |
169 | return unknown; | |
170 | } | |
171 | } | |
172 | ||
173 | int _getdns_mini_ev_cmp(const void* a, const void* b) | |
174 | { | |
175 | const struct _getdns_event *e = (const struct _getdns_event*)a; | |
176 | const struct _getdns_event *f = (const struct _getdns_event*)b; | |
177 | if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) | |
178 | return -1; | |
179 | if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) | |
180 | return 1; | |
181 | if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) | |
182 | return -1; | |
183 | if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) | |
184 | return 1; | |
185 | if(e < f) | |
186 | return -1; | |
187 | if(e > f) | |
188 | return 1; | |
189 | return 0; | |
190 | } | |
191 | ||
192 | /** set time */ | |
193 | static int | |
194 | settime(struct _getdns_event_base* base) | |
195 | { | |
196 | if(gettimeofday(base->time_tv, NULL) < 0) { | |
197 | return -1; | |
198 | } | |
199 | #ifndef S_SPLINT_S | |
200 | *base->time_secs = (time_t)base->time_tv->tv_sec; | |
201 | #endif | |
202 | return 0; | |
203 | } | |
204 | ||
205 | #ifdef WINSOCK_DEBUG | |
206 | /** | |
207 | * Find a fd in the list of items. | |
208 | * Note that not all items have a fd associated (those are -1). | |
209 | * Signals are stored separately, and not searched. | |
210 | * @param base: event base to look in. | |
211 | * @param fd: what socket to look for. | |
212 | * @return the index in the array, or -1 on failure. | |
213 | */ | |
214 | static int | |
215 | find_fd(struct _getdns_event_base* base, int fd) | |
216 | { | |
217 | int i; | |
218 | for(i=0; i<base->max; i++) { | |
219 | if(base->items[i]->ev_fd == fd) | |
220 | return i; | |
221 | } | |
222 | return -1; | |
223 | } | |
224 | #endif | |
225 | ||
226 | /** Find ptr in base array */ | |
227 | static void | |
228 | zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) | |
229 | { | |
230 | int i; | |
231 | for(i=0; i<WSK_MAX_ITEMS; i++) { | |
232 | if(waitfor[i] == x) | |
233 | waitfor[i] = 0; | |
234 | } | |
235 | } | |
236 | ||
237 | void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv) | |
238 | { | |
239 | struct _getdns_event_base* base = (struct _getdns_event_base*)malloc( | |
240 | sizeof(struct _getdns_event_base)); | |
241 | if(!base) | |
242 | return NULL; | |
243 | memset(base, 0, sizeof(*base)); | |
244 | base->time_secs = time_secs; | |
245 | base->time_tv = time_tv; | |
246 | if(settime(base) < 0) { | |
247 | _getdns_event_base_free(base); | |
248 | return NULL; | |
249 | } | |
250 | base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, | |
251 | sizeof(struct _getdns_event*)); | |
252 | if(!base->items) { | |
253 | _getdns_event_base_free(base); | |
254 | return NULL; | |
255 | } | |
256 | base->cap = WSK_MAX_ITEMS; | |
257 | base->max = 0; | |
258 | base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); | |
259 | if(!base->times) { | |
260 | _getdns_event_base_free(base); | |
261 | return NULL; | |
262 | } | |
263 | base->signals = (struct _getdns_event**)calloc(MAX_SIG, | |
264 | sizeof(struct _getdns_event*)); | |
265 | if(!base->signals) { | |
266 | _getdns_event_base_free(base); | |
267 | return NULL; | |
268 | } | |
269 | base->tcp_stickies = 0; | |
270 | base->tcp_reinvigorated = 0; | |
271 | ||
272 | return base; | |
273 | } | |
274 | ||
275 | const char *_getdns_event_get_version(void) | |
276 | { | |
277 | return "winsock-event-"PACKAGE_VERSION; | |
278 | } | |
279 | ||
280 | const char *_getdns_event_get_method(void) | |
281 | { | |
282 | return "WSAWaitForMultipleEvents"; | |
283 | } | |
284 | ||
285 | /** call timeouts handlers, and return how long to wait for next one or -1 */ | |
286 | void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, | |
287 | struct timeval* wait) | |
288 | { | |
289 | struct _getdns_event* p; | |
290 | #ifndef S_SPLINT_S | |
291 | wait->tv_sec = (time_t)-1; | |
292 | #endif | |
293 | ||
294 | while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) | |
295 | !=RBTREE_NULL) { | |
296 | #ifndef S_SPLINT_S | |
297 | if(p->ev_timeout.tv_sec > now->tv_sec || | |
298 | (p->ev_timeout.tv_sec==now->tv_sec && | |
299 | p->ev_timeout.tv_usec > now->tv_usec)) { | |
300 | /* there is a next larger timeout. wait for it */ | |
301 | wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; | |
302 | if(now->tv_usec > p->ev_timeout.tv_usec) { | |
303 | wait->tv_sec--; | |
304 | wait->tv_usec = 1000000 - (now->tv_usec - | |
305 | p->ev_timeout.tv_usec); | |
306 | } else { | |
307 | wait->tv_usec = p->ev_timeout.tv_usec | |
308 | - now->tv_usec; | |
309 | } | |
310 | return; | |
311 | } | |
312 | #endif | |
313 | /* event times out, remove it */ | |
314 | (void)_getdns_rbtree_delete(base->times, p); | |
315 | p->ev_events &= ~EV_TIMEOUT; | |
316 | fptr_ok(fptr_whitelist_event(p->ev_callback)); | |
317 | (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); | |
318 | } | |
319 | } | |
320 | ||
321 | /** handle is_signal events and see if signalled */ | |
322 | static void _getdns_handle_signal(struct _getdns_event* ev) | |
323 | { | |
324 | printf("In _getdns_handle_signal\n"); | |
325 | DWORD ret; | |
326 | //log_assert(ev->is_signal && ev->hEvent); | |
327 | /* see if the event is signalled */ | |
328 | ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, | |
329 | 0 /* return immediately */, 0 /* not alertable for IOcomple*/); | |
330 | if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { | |
331 | log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", | |
332 | wsa_strerror(WSAGetLastError())); | |
333 | return; | |
334 | } | |
335 | if(ret == WSA_WAIT_TIMEOUT) { | |
336 | /* not signalled */ | |
337 | return; | |
338 | } | |
339 | ||
340 | /* reset the signal */ | |
341 | if(!WSAResetEvent(ev->hEvent)) | |
342 | log_err("getdns: WSAResetEvent failed: %s", | |
343 | wsa_strerror(WSAGetLastError())); | |
344 | /* do the callback (which may set the signal again) */ | |
345 | fptr_ok(fptr_whitelist_event(ev->ev_callback)); | |
346 | (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); | |
347 | } | |
348 | ||
349 | /** call select and callbacks for that */ | |
350 | int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) | |
351 | { | |
352 | DWORD timeout = 0; /* in milliseconds */ | |
353 | DWORD ret; | |
354 | WSANETWORKEVENTS netev; | |
355 | struct _getdns_event* eventlist[WSK_MAX_ITEMS]; | |
356 | int i, numwait = 0, startidx = 0; | |
357 | int newstickies = 0; | |
358 | struct timeval nultm; | |
359 | ||
360 | #ifndef S_SPLINT_S | |
361 | if(wait->tv_sec==(time_t)-1) | |
362 | wait = NULL; | |
363 | if (wait) | |
364 | // timeout = 10 + wait->tv_usec / 1000; | |
365 | timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; | |
366 | if(base->tcp_stickies) { | |
367 | wait = &nultm; | |
368 | nultm.tv_sec = 0; | |
369 | nultm.tv_usec = 0; | |
370 | timeout = 0; /* no waiting, we have sticky events */ | |
371 | } | |
372 | #endif | |
373 | ||
374 | /* prepare event array */ | |
375 | for(i=0; i<base->max; i++) { | |
376 | if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) | |
377 | continue; /* skip timer only events */ | |
378 | eventlist[numwait] = base->items[i]; | |
379 | base->waitfor[numwait++] = base->items[i]->hEvent; | |
380 | printf("winsock_event bmax=%d numwait=%d wait=%x " | |
381 | "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, | |
382 | (int)timeout, (int)base->items[i]->hEvent); | |
383 | if (numwait == WSK_MAX_ITEMS) | |
384 | break; /* sanity check */ | |
385 | } | |
386 | //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); | |
387 | ||
388 | /* do the wait */ | |
389 | if(numwait == 0) { | |
390 | /* WSAWaitFor.. doesn't like 0 event objects */ | |
391 | if(wait) { | |
392 | Sleep(timeout); | |
393 | } | |
394 | } | |
395 | else { | |
396 | //gv: do not schedule udp write | |
397 | for (i = 0; i<base->max; i++) { | |
398 | if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { | |
399 | printf("skip UDP sched\n"); | |
400 | (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, | |
401 | EV_WRITE & eventlist[i]->ev_events, | |
402 | eventlist[i]->ev_arg); | |
403 | return 0; | |
404 | } | |
405 | } | |
406 | printf("before wait %d\n", base->items[0]->ev_events); | |
407 | ret = WSAWaitForMultipleEvents(numwait, base->waitfor, | |
408 | 0 /* do not wait for all, just one will do */, | |
409 | wait?timeout:WSA_INFINITE, | |
410 | 0); /* we are not alertable (IO completion events) */ | |
411 | printf("after wait %d %d\n", (int)ret, numwait); | |
412 | if(ret == WSA_WAIT_IO_COMPLETION) { | |
413 | //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); | |
414 | return -1; | |
415 | } else if(ret == WSA_WAIT_FAILED) { | |
416 | //printf("getdns: WSAWaitForMultipleEvents failed: %s", | |
417 | // wsa_strerror(WSAGetLastError())); | |
418 | return -1; | |
419 | } else if(ret == WSA_WAIT_TIMEOUT) { | |
420 | printf("timeout\n"); | |
421 | } else | |
422 | startidx = ret - WSA_WAIT_EVENT_0; | |
423 | } | |
424 | ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", | |
425 | // was_timeout, startidx); | |
426 | ||
427 | /* get new time after wait */ | |
428 | if(settime(base) < 0) | |
429 | return -1; | |
430 | ||
431 | /* callbacks */ | |
432 | if(base->tcp_stickies) | |
433 | startidx = 0; /* process all events, some are sticky */ | |
434 | for(i=startidx; i<numwait; i++) | |
435 | eventlist[i]->just_checked = 1; | |
436 | ||
437 | //verbose(VERB_CLIENT, "winsock_event signals"); | |
438 | for(i=startidx; i<numwait; i++) { | |
439 | if(!base->waitfor[i]) | |
440 | continue; /* was deleted */ | |
441 | if(eventlist[i]->is_signal) { | |
442 | eventlist[i]->just_checked = 0; | |
443 | _getdns_handle_signal(eventlist[i]); | |
444 | } | |
445 | } | |
446 | /* early exit - do not process network, exit quickly */ | |
447 | if(base->need_to_exit) | |
448 | return 0; | |
449 | ||
450 | //verbose(VERB_CLIENT, "winsock_event net"); | |
451 | for(i=startidx; i<numwait; i++) { | |
452 | short bits = 0; | |
453 | /* eventlist[i] fired */ | |
454 | /* see if eventlist[i] is still valid and just checked from | |
455 | * WSAWaitForEvents */ | |
456 | if(!base->waitfor[i]) | |
457 | continue; /* was deleted */ | |
458 | if(!eventlist[i]->just_checked) | |
459 | continue; /* added by other callback */ | |
460 | if(eventlist[i]->is_signal) | |
461 | continue; /* not a network event at all */ | |
462 | eventlist[i]->just_checked = 0; | |
463 | ||
464 | if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, | |
465 | base->waitfor[i], /* reset the event handle */ | |
466 | /*NULL,*/ /* do not reset the event handle */ | |
467 | &netev) != 0) { | |
468 | log_err("getdns: WSAEnumNetworkEvents failed: %s", | |
469 | wsa_strerror(WSAGetLastError())); | |
470 | return -1; | |
471 | } | |
472 | if((netev.lNetworkEvents & FD_READ)) { | |
473 | if(netev.iErrorCode[FD_READ_BIT] != 0) | |
474 | printf("FD_READ_BIT error: %s\n", | |
475 | wsa_strerror(netev.iErrorCode[FD_READ_BIT])); | |
476 | bits |= EV_READ; | |
477 | printf("FD_READ_BIT\n"); | |
478 | } | |
479 | if((netev.lNetworkEvents & FD_WRITE)) { | |
480 | if(netev.iErrorCode[FD_WRITE_BIT] != 0) | |
481 | printf("FD_WRITE_BIT error: %s\n", | |
482 | wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); | |
483 | bits |= EV_WRITE; | |
484 | printf("FD_WRITE_BIT\n"); | |
485 | } | |
486 | if((netev.lNetworkEvents & FD_CONNECT)) { | |
487 | if(netev.iErrorCode[FD_CONNECT_BIT] != 0) | |
488 | printf("FD_CONNECT_BIT error: %s\n", | |
489 | wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); | |
490 | bits |= EV_READ; | |
491 | bits |= EV_WRITE; | |
492 | printf("FD_CONNECT_BIT\n"); | |
493 | } | |
494 | if((netev.lNetworkEvents & FD_ACCEPT)) { | |
495 | if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) | |
496 | printf("FD_ACCEPT_BIT error: %s\n", | |
497 | wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); | |
498 | bits |= EV_READ; | |
499 | printf("FD_ACCEPT_BIT\n"); | |
500 | } | |
501 | if((netev.lNetworkEvents & FD_CLOSE)) { | |
502 | if(netev.iErrorCode[FD_CLOSE_BIT] != 0) | |
503 | printf("FD_CLOSE_BIT error: %s\n", | |
504 | wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); | |
505 | //g bits |= EV_READ; | |
506 | //g bits |= EV_WRITE; | |
507 | printf("FD_CLOSE_BIT\n"); | |
508 | } | |
509 | if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { | |
510 | ||
511 | printf("winsock %d pass sticky %s%s\n", | |
512 | eventlist[i]->ev_fd, | |
513 | (eventlist[i]->old_events&EV_READ)?"EV_READ":"", | |
514 | (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); | |
515 | ||
516 | bits |= eventlist[i]->old_events; | |
517 | } | |
518 | if(eventlist[i]->is_tcp && bits) { | |
519 | eventlist[i]->old_events = bits; | |
520 | eventlist[i]->stick_events = 1; | |
521 | if((eventlist[i]->ev_events & bits)) { | |
522 | newstickies = 1; | |
523 | } | |
524 | ||
525 | printf("winsock %d store sticky %s%s", | |
526 | eventlist[i]->ev_fd, | |
527 | (eventlist[i]->old_events&EV_READ)?"EV_READ":"", | |
528 | (eventlist[i]->old_events&EV_WRITE) ? "EV_WRITE" : ""); | |
529 | ||
530 | } | |
531 | if((bits & eventlist[i]->ev_events)) { | |
532 | printf( "winsock event callback %p fd=%d " | |
533 | "%s%s%s%s%s ; %s%s%s\n", | |
534 | eventlist[i], eventlist[i]->ev_fd, | |
535 | (netev.lNetworkEvents&FD_READ)?" FD_READ":"", | |
536 | (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", | |
537 | (netev.lNetworkEvents&FD_CONNECT)? | |
538 | " FD_CONNECT":"", | |
539 | (netev.lNetworkEvents&FD_ACCEPT)? | |
540 | " FD_ACCEPT":"", | |
541 | (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", | |
542 | (bits&EV_READ)?" EV_READ":"", | |
543 | (bits&EV_WRITE)?" EV_WRITE":"", | |
544 | (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); | |
545 | ||
546 | fptr_ok(fptr_whitelist_event( | |
547 | eventlist[i]->ev_callback)); | |
548 | (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, | |
549 | bits & eventlist[i]->ev_events, | |
550 | eventlist[i]->ev_arg); | |
551 | } | |
552 | ||
553 | if(eventlist[i]->is_tcp && bits) | |
554 | printf( "winsock %d got sticky %s%s\n", | |
555 | eventlist[i]->ev_fd, | |
556 | (eventlist[i]->old_events&EV_READ)?"EV_READ":"", | |
557 | (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); | |
558 | ||
559 | } | |
560 | //verbose(VERB_CLIENT, "winsock_event net"); | |
561 | if(base->tcp_reinvigorated) { | |
562 | printf("winsock_event reinvigorated\n"); | |
563 | base->tcp_reinvigorated = 0; | |
564 | newstickies = 1; | |
565 | } | |
566 | base->tcp_stickies = newstickies; | |
567 | //gprintf("winsock_event handle_select end\n"); | |
568 | return 0; | |
569 | } | |
570 | ||
571 | int _getdns_event_base_dispatch(struct _getdns_event_base *base) | |
572 | { | |
573 | struct timeval wait; | |
574 | if(settime(base) < 0) | |
575 | return -1; | |
576 | while(!base->need_to_exit) | |
577 | { | |
578 | /* see if timeouts need handling */ | |
579 | _getdns_handle_timeouts(base, base->time_tv, &wait); | |
580 | if(base->need_to_exit) | |
581 | return 0; | |
582 | /* do select */ | |
583 | if(_getdns_handle_select(base, &wait) < 0) { | |
584 | if(base->need_to_exit) | |
585 | return 0; | |
586 | return -1; | |
587 | } | |
588 | } | |
589 | return 0; | |
590 | } | |
591 | ||
592 | int _getdns_event_base_loopexit(struct _getdns_event_base *base, | |
593 | struct timeval * ATTR_UNUSED(tv)) | |
594 | { | |
595 | base->need_to_exit = 1; | |
596 | return 0; | |
597 | } | |
598 | ||
599 | void _getdns_event_base_free(struct _getdns_event_base *base) | |
600 | { | |
601 | if(!base) | |
602 | return; | |
603 | if(base->items) | |
604 | free(base->items); | |
605 | if(base->times) | |
606 | free(base->times); | |
607 | if(base->signals) | |
608 | free(base->signals); | |
609 | free(base); | |
610 | } | |
611 | ||
612 | void _getdns_event_set(struct _getdns_event *ev, int fd, short bits, | |
613 | void (*cb)(int, short, void *), void *arg) | |
614 | { | |
615 | ev->node.key = ev; | |
616 | ev->ev_fd = fd; | |
617 | ev->ev_events = bits; | |
618 | ev->ev_callback = cb; | |
619 | fptr_ok(fptr_whitelist_event(ev->ev_callback)); | |
620 | ev->ev_arg = arg; | |
621 | ev->just_checked = 0; | |
622 | ev->added = 0; | |
623 | } | |
624 | ||
625 | int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event *ev) | |
626 | { | |
627 | ev->ev_base = base; | |
628 | ev->old_events = 0; | |
629 | ev->stick_events = 0; | |
630 | ev->added = 0; | |
631 | return 0; | |
632 | } | |
633 | ||
634 | int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) | |
635 | { | |
636 | printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n", | |
637 | ev, ev->added, ev->ev_fd, | |
638 | (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), | |
639 | (ev->ev_events&EV_READ)?" EV_READ":"", | |
640 | (ev->ev_events&EV_WRITE)?" EV_WRITE":"", | |
641 | (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); | |
642 | ||
643 | if(ev->added) | |
644 | _getdns_event_del(ev); | |
645 | ||
646 | ev->is_tcp = 0; | |
647 | ev->is_signal = 0; | |
648 | ev->just_checked = 0; | |
649 | ||
650 | if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) { | |
651 | BOOL b = 0; | |
652 | int t, l; | |
653 | long events = 0; | |
654 | //gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events); | |
655 | ||
656 | if (ev->ev_base->max == ev->ev_base->cap) | |
657 | return -1; | |
658 | ev->idx = ev->ev_base->max++; | |
659 | ev->ev_base->items[ev->idx] = ev; | |
660 | ||
661 | if ((ev->ev_events&EV_READ)) | |
662 | events |= FD_READ; | |
663 | if ((ev->ev_events&EV_WRITE)) | |
664 | { | |
665 | events |= FD_CONNECT; | |
666 | events |= FD_WRITE; | |
667 | } | |
668 | ||
669 | //printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events); | |
670 | ||
671 | l = sizeof(t); | |
672 | if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, | |
673 | (void*)&t, &l) != 0) | |
674 | log_err("getdns: getsockopt(SO_TYPE) failed: %s", | |
675 | wsa_strerror(WSAGetLastError())); | |
676 | if(t == SOCK_STREAM) { | |
677 | /* TCP socket */ | |
678 | ev->is_tcp = 1; | |
679 | events |= FD_CLOSE; | |
680 | if( (ev->ev_events&EV_WRITE) ) | |
681 | events |= FD_CONNECT; | |
682 | l = sizeof(b); | |
683 | if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, | |
684 | (void*)&b, &l) != 0) | |
685 | log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s", | |
686 | wsa_strerror(WSAGetLastError())); | |
687 | if(b) /* TCP accept socket */ | |
688 | events |= FD_ACCEPT; | |
689 | } | |
690 | ev->hEvent = WSACreateEvent(); | |
691 | if(ev->hEvent == WSA_INVALID_EVENT) | |
692 | log_err("getdns: WSACreateEvent failed: %s", | |
693 | wsa_strerror(WSAGetLastError())); | |
694 | /* automatically sets fd to nonblocking mode. | |
695 | * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ | |
696 | printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent); | |
697 | if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { | |
698 | log_err("getdns: WSAEventSelect in getdns failed: %s", | |
699 | wsa_strerror(WSAGetLastError())); | |
700 | } | |
701 | if(ev->is_tcp && ev->stick_events && | |
702 | (ev->ev_events & ev->old_events)) { | |
703 | /* go to processing the sticky event right away */ | |
704 | printf("\nWSAEventSelect sticky %d events %d hEvent %d\n", ev->ev_fd, (int)events, (int)ev->hEvent); | |
705 | ev->ev_base->tcp_reinvigorated = 1; | |
706 | } | |
707 | } | |
708 | ||
709 | if(tv && (ev->ev_events&EV_TIMEOUT)) { | |
710 | printf("\nWSAEventSelect timeout %d hEvent %d\n", ev->ev_fd, (int)ev->hEvent); | |
711 | ||
712 | #ifndef S_SPLINT_S | |
713 | struct timeval *now = ev->ev_base->time_tv; | |
714 | ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; | |
715 | ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; | |
716 | while(ev->ev_timeout.tv_usec > 1000000) { | |
717 | ev->ev_timeout.tv_usec -= 1000000; | |
718 | ev->ev_timeout.tv_sec++; | |
719 | } | |
720 | #endif | |
721 | (void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node); | |
722 | } | |
723 | ev->added = 1; | |
724 | return 0; | |
725 | } | |
726 | ||
727 | int _getdns_event_del(struct _getdns_event *ev) | |
728 | { | |
729 | //verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", | |
730 | // ev, ev->added, ev->ev_fd, | |
731 | // (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ | |
732 | // (long long)ev->ev_timeout.tv_usec/1000:-1, | |
733 | // (ev->ev_events&EV_READ)?" EV_READ":"", | |
734 | // (ev->ev_events&EV_WRITE)?" EV_WRITE":"", | |
735 | // (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); | |
736 | if(!ev->added) | |
737 | return 0; | |
738 | //log_assert(ev->added); | |
739 | if((ev->ev_events&EV_TIMEOUT)) | |
740 | (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node); | |
741 | if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { | |
742 | //log_assert(ev->ev_base->max > 0); | |
743 | /* remove item and compact the list */ | |
744 | ev->ev_base->items[ev->idx] = | |
745 | ev->ev_base->items[ev->ev_base->max-1]; | |
746 | ev->ev_base->items[ev->ev_base->max-1] = NULL; | |
747 | ev->ev_base->max--; | |
748 | if(ev->idx < ev->ev_base->max) | |
749 | ev->ev_base->items[ev->idx]->idx = ev->idx; | |
750 | zero_waitfor(ev->ev_base->waitfor, ev->hEvent); | |
751 | ||
752 | if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) | |
753 | log_err("getdns: WSAEventSelect(disable) failed: %s", | |
754 | wsa_strerror(WSAGetLastError())); | |
755 | if(!WSACloseEvent(ev->hEvent)) | |
756 | log_err("getdns: WSACloseEvent failed: %s", | |
757 | wsa_strerror(WSAGetLastError())); | |
758 | } | |
759 | ev->just_checked = 0; | |
760 | ev->added = 0; | |
761 | return 0; | |
762 | } | |
763 | ||
764 | /** which base gets to handle signals */ | |
765 | static struct _getdns_event_base* signal_base = NULL; | |
766 | /** signal handler */ | |
767 | static RETSIGTYPE sigh(int sig) | |
768 | { | |
769 | if(!signal_base || sig < 0 || sig >= MAX_SIG) | |
770 | return; | |
771 | } | |
772 | ||
773 | int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv)) | |
774 | { | |
775 | if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) | |
776 | return -1; | |
777 | signal_base = ev->ev_base; | |
778 | ev->ev_base->signals[ev->ev_fd] = ev; | |
779 | ev->added = 1; | |
780 | if(signal(ev->ev_fd, sigh) == SIG_ERR) { | |
781 | return -1; | |
782 | } | |
783 | return 0; | |
784 | } | |
785 | ||
786 | int _getdns_signal_del(struct _getdns_event *ev) | |
787 | { | |
788 | if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) | |
789 | return -1; | |
790 | ev->ev_base->signals[ev->ev_fd] = NULL; | |
791 | ev->added = 0; | |
792 | return 0; | |
793 | } | |
794 | ||
795 | void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits) | |
796 | { | |
797 | printf("winsock: tcp wouldblock %s\n", | |
798 | eventbits==EV_READ?"EV_READ":"EV_WRITE"); | |
799 | ev->old_events &= (~eventbits); | |
800 | if(ev->old_events == 0) | |
801 | ev->stick_events = 0; | |
802 | /* in case this is the last sticky event, we could | |
803 | * possibly run an empty handler loop to reset the base | |
804 | * tcp_stickies variable | |
805 | */ | |
806 | } | |
807 | ||
808 | int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, | |
809 | WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) | |
810 | { | |
811 | if(base->max == base->cap) | |
812 | return 0; | |
813 | memset(ev, 0, sizeof(*ev)); | |
814 | ev->ev_fd = -1; | |
815 | ev->ev_events = EV_READ; | |
816 | ev->ev_callback = cb; | |
817 | ev->ev_arg = arg; | |
818 | ev->is_signal = 1; | |
819 | ev->hEvent = wsaevent; | |
820 | ev->added = 1; | |
821 | ev->ev_base = base; | |
822 | ev->idx = ev->ev_base->max++; | |
823 | ev->ev_base->items[ev->idx] = ev; | |
824 | return 1; | |
825 | } | |
826 | ||
827 | void winsock_unregister_wsaevent(struct _getdns_event* ev) | |
828 | { | |
829 | if(!ev || !ev->added) return; | |
830 | //log_assert(ev->added && ev->ev_base->max > 0) | |
831 | /* remove item and compact the list */ | |
832 | ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; | |
833 | ev->ev_base->items[ev->ev_base->max-1] = NULL; | |
834 | ev->ev_base->max--; | |
835 | if(ev->idx < ev->ev_base->max) | |
836 | ev->ev_base->items[ev->idx]->idx = ev->idx; | |
837 | ev->added = 0; | |
838 | } | |
839 | ||
840 | #else /* USE_WINSOCK */ | |
841 | /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ | |
842 | int winsock_unused_symbol = 1; | |
843 | #endif /* USE_WINSOCK */ |
0 | /* | |
1 | * util/winsock_event.h - getdns event handling for winsock on windows | |
2 | * extracted from Unbound source code and modified for getdns | |
3 | * | |
4 | * Copyright (c) 2015, NLnet Labs/Verisign. All rights reserved. | |
5 | * | |
6 | * This software is open source. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * Redistributions of source code must retain the above copyright notice, | |
13 | * this list of conditions and the following disclaimer. | |
14 | * | |
15 | * Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * | |
19 | * Neither the name of the NLNET LABS or Verisign nor the names of its contributors may | |
20 | * be used to endorse or promote products derived from this software without | |
21 | * specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | /** | |
37 | * \file | |
38 | * | |
39 | * This file contains interface functions with the WinSock2 API on Windows. | |
40 | * It uses the winsock WSAWaitForMultipleEvents interface on a number of | |
41 | * sockets. | |
42 | * Code is originally from the Unbound source for Windows. | |
43 | * | |
44 | * Note that windows can only wait for max 64 events at one time. | |
45 | * | |
46 | * Also, file descriptors cannot be waited for. | |
47 | * | |
48 | * Named pipes are not easily available (and are not usable in select() ). | |
49 | * For interprocess communication, it is possible to wait for a hEvent to | |
50 | * be signaled by another thread. | |
51 | * | |
52 | * When a socket becomes readable, then it will not be flagged as | |
53 | * readable again until you have gotten WOULDBLOCK from a recv routine. | |
54 | * That means the event handler must store the readability (edge notify) | |
55 | * and process the incoming data until it blocks. | |
56 | * The function performing recv then has to inform the event handler that | |
57 | * the socket has blocked, and the event handler can mark it as such. | |
58 | * Thus, this file transforms the edge notify from windows to a level notify | |
59 | * that is compatible with UNIX. | |
60 | * The WSAEventSelect page says that it does do level notify, as long | |
61 | * as you call a recv/write/accept at least once when it is signalled. | |
62 | * This last bit is not true, even though documented in server2008 api docs | |
63 | * from microsoft, it does not happen at all. Instead you have to test for | |
64 | * WSAEWOULDBLOCK on a tcp stream, and only then retest the socket. | |
65 | * And before that remember the previous result as still valid. | |
66 | * | |
67 | * To stay 'fair', instead of emptying a socket completely, the event handler | |
68 | * can test the other (marked as blocking) sockets for new events. | |
69 | * | |
70 | * Additionally, TCP accept sockets get special event support. | |
71 | * | |
72 | * Socket numbers are not starting small, they can be any number (say 33060). | |
73 | * Therefore, bitmaps are not used, but arrays. | |
74 | * | |
75 | * on winsock, you must use recv() and send() for TCP reads and writes, | |
76 | * not read() and write(), those work only on files. | |
77 | * | |
78 | * Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode. | |
79 | * | |
80 | * When under a high load windows gives out lots of errors, from recvfrom | |
81 | * on udp sockets for example (WSAECONNRESET). Even though the udp socket | |
82 | * has no connection per se. | |
83 | */ | |
84 | ||
85 | #ifndef UTIL_WINSOCK_EVENT_H | |
86 | #define UTIL_WINSOCK_EVENT_H | |
87 | ||
88 | // Only enabled for Windows | |
89 | #ifdef USE_WINSOCK | |
90 | ||
91 | #ifndef HAVE_EVENT_BASE_FREE | |
92 | #define HAVE_EVENT_BASE_FREE | |
93 | #endif | |
94 | ||
95 | /* redefine the calls to different names so that there is no name | |
96 | * collision with other code that uses libevent names. (that uses libunbound)*/ | |
97 | #define _getdns_event_init winsockevent_init | |
98 | #define event_get_version winsockevent_get_version | |
99 | #define event_get_method winsockevent_get_method | |
100 | #define _getdns_event_base_dispatch winsockevent_base_dispatch | |
101 | #define event_base_loopexit winsockevent_base_loopexit | |
102 | #define _getdns_event_base_free winsockevent_base_free | |
103 | #define _getdns_event_set winsockevent_set | |
104 | #define _getdns_event_base_set winsockevent_base_set | |
105 | #define _getdns_event_add winsockevent_add | |
106 | #define _getdns_event_del winsockevent_del | |
107 | #define signal_add winsocksignal_add | |
108 | #define signal_del winsocksignal_del | |
109 | ||
110 | /** event timeout */ | |
111 | #define EV_TIMEOUT 0x01 | |
112 | /** event fd readable */ | |
113 | #define EV_READ 0x02 | |
114 | /** event fd writable */ | |
115 | #define EV_WRITE 0x04 | |
116 | /** event signal */ | |
117 | #define EV_SIGNAL 0x08 | |
118 | /** event must persist */ | |
119 | #define EV_PERSIST 0x10 | |
120 | ||
121 | /* needs our redblack tree */ | |
122 | #include "util/rbtree.h" | |
123 | ||
124 | /** max number of signals to support */ | |
125 | #define MAX_SIG 32 | |
126 | ||
127 | /** The number of items that the winsock event handler can service. | |
128 | * Windows cannot handle more anyway */ | |
129 | #define WSK_MAX_ITEMS 64 | |
130 | ||
131 | /** | |
132 | * event base for winsock event handler | |
133 | */ | |
134 | struct _getdns_event_base | |
135 | { | |
136 | /** sorted by timeout (absolute), ptr */ | |
137 | _getdns_rbtree_t* times; | |
138 | /** array (first part in use) of handles to work on */ | |
139 | struct _getdns_event** items; | |
140 | /** number of items in use in array */ | |
141 | int max; | |
142 | /** capacity of array, size of array in items */ | |
143 | int cap; | |
144 | /** array of 0 - maxsig of ptr to event for it */ | |
145 | struct _getdns_event** signals; | |
146 | /** if we need to exit */ | |
147 | int need_to_exit; | |
148 | /** where to store time in seconds */ | |
149 | time_t* time_secs; | |
150 | /** where to store time in microseconds */ | |
151 | struct timeval* time_tv; | |
152 | /** | |
153 | * TCP streams have sticky events to them, these are not | |
154 | * reported by the windows event system anymore, we have to | |
155 | * keep reporting those events as present until wouldblock() is | |
156 | * signalled by the handler back to use. | |
157 | */ | |
158 | int tcp_stickies; | |
159 | /** | |
160 | * should next cycle process reinvigorated stickies, | |
161 | * these are stickies that have been stored, but due to a new | |
162 | * event_add a sudden interest in the event has incepted. | |
163 | */ | |
164 | int tcp_reinvigorated; | |
165 | /** The list of events that is currently being processed. */ | |
166 | WSAEVENT waitfor[WSK_MAX_ITEMS]; | |
167 | ||
168 | /* fdset for read write, for fds ready, and added */ | |
169 | fd_set | |
170 | /** fds for reading */ | |
171 | reads, | |
172 | /** fds for writing */ | |
173 | writes, | |
174 | /** fds determined ready for use */ | |
175 | ready, | |
176 | /** ready plus newly added events. */ | |
177 | content; | |
178 | }; | |
179 | ||
180 | /** | |
181 | * Event structure. Has some of the event elements. | |
182 | */ | |
183 | struct _getdns_event { | |
184 | /** node in timeout rbtree */ | |
185 | _getdns_rbnode_t node; | |
186 | /** is event already added */ | |
187 | int added; | |
188 | ||
189 | /** event base it belongs to */ | |
190 | struct _getdns_event_base *ev_base; | |
191 | /** fd to poll or -1 for timeouts. signal number for sigs. */ | |
192 | int ev_fd; | |
193 | /** what events this event is interested in, see EV_.. above. */ | |
194 | short ev_events; | |
195 | /** timeout value */ | |
196 | struct timeval ev_timeout; | |
197 | ||
198 | /** callback to call: fd, eventbits, userarg */ | |
199 | void (*ev_callback)(int, short, void *); | |
200 | /** callback user arg */ | |
201 | void *ev_arg; | |
202 | ||
203 | /* ----- nonpublic part, for winsock_event only ----- */ | |
204 | /** index of this event in the items array (if added) */ | |
205 | int idx; | |
206 | /** the event handle to wait for new events to become ready */ | |
207 | WSAEVENT hEvent; | |
208 | /** true if this filedes is a TCP socket and needs special attention */ | |
209 | int is_tcp; | |
210 | /** remembered EV_ values */ | |
211 | short old_events; | |
212 | /** should remembered EV_ values be used for TCP streams. | |
213 | * Reset after WOULDBLOCK is signaled using the function. */ | |
214 | int stick_events; | |
215 | ||
216 | /** true if this event is a signaling WSAEvent by the user. | |
217 | * User created and user closed WSAEvent. Only signaled/unsigneled, | |
218 | * no read/write/distinctions needed. */ | |
219 | int is_signal; | |
220 | /** used during callbacks to see which events were just checked */ | |
221 | int just_checked; | |
222 | }; | |
223 | ||
224 | char* wsa_strerror(DWORD err); | |
225 | void log_err(const char *format, ...); | |
226 | /** create event base */ | |
227 | void *_getdns_event_init(time_t* time_secs, struct timeval* time_tv); | |
228 | /** get version */ | |
229 | const char *event_get_version(void); | |
230 | /** get polling method (select,epoll) */ | |
231 | const char *event_get_method(void); | |
232 | /** run select in a loop */ | |
233 | int _getdns_event_base_dispatch(struct _getdns_event_base *); | |
234 | /** exit that loop */ | |
235 | int event_base_loopexit(struct _getdns_event_base *, struct timeval *); | |
236 | /** free event base. Free events yourself */ | |
237 | void _getdns_event_base_free(struct _getdns_event_base *); | |
238 | /** set content of event */ | |
239 | void _getdns_event_set(struct _getdns_event *, int, short, void (*)(int, short, void *), void *); | |
240 | ||
241 | /** add event to a base. You *must* call this for every event. */ | |
242 | int _getdns_event_base_set(struct _getdns_event_base *, struct _getdns_event *); | |
243 | /** add event to make it active. You may not change it with event_set anymore */ | |
244 | int _getdns_event_add(struct _getdns_event *, struct timeval *); | |
245 | /** remove event. You may change it again */ | |
246 | int _getdns_event_del(struct _getdns_event *); | |
247 | ||
248 | #define evtimer_add(ev, tv) event_add(ev, tv) | |
249 | #define evtimer_del(ev) event_del(ev) | |
250 | ||
251 | /* uses different implementation. Cannot mix fd/timeouts and signals inside | |
252 | * the same struct event. create several event structs for that. */ | |
253 | /** install signal handler */ | |
254 | int signal_add(struct _getdns_event *, struct timeval *); | |
255 | /** set signal event contents */ | |
256 | #define signal_set(ev, x, cb, arg) \ | |
257 | event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) | |
258 | /** remove signal handler */ | |
259 | int signal_del(struct _getdns_event *); | |
260 | ||
261 | /** compare events in tree, based on timevalue, ptr for uniqueness */ | |
262 | int getdns_mini_ev_cmp(const void* a, const void* b); | |
263 | ||
264 | /** | |
265 | * Routine for windows only, where the handling layer can signal that | |
266 | * a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs | |
267 | * retesting the event. | |
268 | * Pass if EV_READ or EV_WRITE gave wouldblock. | |
269 | */ | |
270 | void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); | |
271 | ||
272 | /** | |
273 | * Routine for windows only. where you pass a signal WSAEvent that | |
274 | * you wait for. When the event is signaled, the callback gets called. | |
275 | * The callback has to WSAResetEvent to disable the signal. | |
276 | * @param base: the event base. | |
277 | * @param ev: the event structure for data storage | |
278 | * can be passed uninitialised. | |
279 | * @param wsaevent: the WSAEvent that gets signaled. | |
280 | * @param cb: callback routine. | |
281 | * @param arg: user argument to callback routine. | |
282 | * @return false on error. | |
283 | */ | |
284 | int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, | |
285 | WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); | |
286 | ||
287 | /** | |
288 | * Unregister a wsaevent. User has to close the WSAEVENT itself. | |
289 | * @param ev: event data storage. | |
290 | */ | |
291 | void winsock_unregister_wsaevent(struct _getdns_event* ev); | |
292 | ||
293 | #endif /* USE_WINSOCK */ | |
294 | #endif /* UTIL_WINSOCK_EVENT_H */ |
71 | 71 | #endif |
72 | 72 | {"return_api_information", t_int}, |
73 | 73 | {"return_both_v4_and_v6", t_int}, |
74 | {"return_call_debugging", t_int}, | |
74 | {"return_call_reporting", t_int}, | |
75 | 75 | {"specify_class", t_int}, |
76 | 76 | }; |
77 | 77 | |
171 | 171 | _getdns_rr_iter2rr_dict(struct mem_funcs *mf, _getdns_rr_iter *i) |
172 | 172 | { |
173 | 173 | getdns_dict *rr_dict, *rdata_dict; |
174 | getdns_bindata bindata; | |
174 | const uint8_t *bin_data; | |
175 | size_t bin_size; | |
175 | 176 | uint32_t int_val = 0; |
176 | getdns_data_type val_type; | |
177 | enum wf_data_type { wf_int, wf_bindata, wf_special } val_type; | |
177 | 178 | _getdns_rdf_iter rdf_storage, *rdf; |
178 | 179 | getdns_list *repeat_list = NULL; |
179 | 180 | getdns_dict *repeat_dict = NULL; |
184 | 185 | if (!(rr_dict = _getdns_dict_create_with_mf(mf))) |
185 | 186 | return NULL; |
186 | 187 | |
187 | bindata.data = _getdns_owner_if_or_as_decompressed( | |
188 | i, ff_bytes, &bindata.size); | |
188 | bin_data = _getdns_owner_if_or_as_decompressed( | |
189 | i, ff_bytes, &bin_size); | |
189 | 190 | |
190 | 191 | /* question */ |
191 | 192 | if (_getdns_rr_iter_section(i) == GLDNS_SECTION_QUESTION) { |
196 | 197 | getdns_dict_set_int(rr_dict, "qclass", |
197 | 198 | (uint32_t) gldns_read_uint16(i->rr_type + 2)) || |
198 | 199 | |
199 | getdns_dict_set_bindata(rr_dict, "qname", &bindata)) { | |
200 | _getdns_dict_set_const_bindata( | |
201 | rr_dict, "qname", bin_size, bin_data)) { | |
200 | 202 | |
201 | 203 | goto error; |
202 | 204 | } |
233 | 235 | getdns_dict_set_int(rr_dict, "ttl", |
234 | 236 | (uint32_t) gldns_read_uint32(i->rr_type + 4)) || |
235 | 237 | |
236 | getdns_dict_set_bindata(rr_dict, "name", &bindata)) { | |
238 | _getdns_dict_set_const_bindata( | |
239 | rr_dict, "name", bin_size, bin_data)) { | |
237 | 240 | |
238 | 241 | goto error; |
239 | 242 | } |
241 | 244 | return NULL; |
242 | 245 | |
243 | 246 | if (i->rr_type + 10 <= i->nxt) { |
244 | bindata.size = i->nxt - (i->rr_type + 10); | |
245 | bindata.data = i->rr_type + 10; | |
246 | if (getdns_dict_set_bindata(rdata_dict, "rdata_raw", &bindata)) | |
247 | bin_size = i->nxt - (i->rr_type + 10); | |
248 | bin_data = i->rr_type + 10; | |
249 | if (_getdns_dict_set_const_bindata( | |
250 | rdata_dict, "rdata_raw", bin_size, bin_data)) | |
247 | 251 | goto rdata_error; |
248 | 252 | } |
249 | 253 | for ( rdf = _getdns_rdf_iter_init(&rdf_storage, i) |
250 | 254 | ; rdf; rdf = _getdns_rdf_iter_next(rdf)) { |
251 | 255 | if (rdf->rdd_pos->type & GETDNS_RDF_INTEGER) { |
252 | val_type = t_int; | |
256 | val_type = wf_int; | |
253 | 257 | switch (rdf->rdd_pos->type & GETDNS_RDF_FIXEDSZ) { |
254 | 258 | case 1: int_val = *rdf->pos; |
255 | 259 | break; |
261 | 265 | goto rdata_error; |
262 | 266 | } |
263 | 267 | } else if (rdf->rdd_pos->type & GETDNS_RDF_DNAME) { |
264 | val_type = t_bindata; | |
265 | ||
266 | bindata.data = _getdns_rdf_if_or_as_decompressed( | |
267 | rdf, ff_bytes, &bindata.size); | |
268 | val_type = wf_bindata; | |
269 | ||
270 | bin_data = _getdns_rdf_if_or_as_decompressed( | |
271 | rdf, ff_bytes, &bin_size); | |
268 | 272 | |
269 | 273 | } else if (rdf->rdd_pos->type & GETDNS_RDF_BINDATA) { |
270 | val_type = t_bindata; | |
274 | val_type = wf_bindata; | |
271 | 275 | if (rdf->rdd_pos->type & GETDNS_RDF_FIXEDSZ) { |
272 | bindata.size = rdf->rdd_pos->type | |
273 | & GETDNS_RDF_FIXEDSZ; | |
274 | bindata.data = rdf->pos; | |
276 | bin_size = rdf->rdd_pos->type | |
277 | & GETDNS_RDF_FIXEDSZ; | |
278 | bin_data = rdf->pos; | |
275 | 279 | |
276 | 280 | } else switch(rdf->rdd_pos->type & GETDNS_RDF_LEN_VAL){ |
277 | 281 | case 0x100: |
278 | bindata.size = *rdf->pos; | |
279 | bindata.data = rdf->pos + 1; | |
282 | bin_size = *rdf->pos; | |
283 | bin_data = rdf->pos + 1; | |
280 | 284 | break; |
281 | 285 | case 0x200: |
282 | bindata.size = gldns_read_uint16(rdf->pos); | |
283 | bindata.data = rdf->pos + 2; | |
286 | bin_size = gldns_read_uint16(rdf->pos); | |
287 | bin_data = rdf->pos + 2; | |
284 | 288 | break; |
285 | 289 | default: |
286 | bindata.size = rdf->nxt - rdf->pos; | |
287 | bindata.data = rdf->pos; | |
290 | bin_size = rdf->nxt - rdf->pos; | |
291 | bin_data = rdf->pos; | |
288 | 292 | break; |
289 | 293 | } |
290 | 294 | } else if (rdf->rdd_pos->type == GETDNS_RDF_SPECIAL) |
291 | /* Abuse t_dict for special values */ | |
292 | val_type = t_dict; | |
295 | val_type = wf_special; | |
293 | 296 | else |
294 | 297 | assert(0); |
295 | 298 | |
296 | 299 | if (! rdf->rdd_repeat) { |
297 | 300 | switch (val_type) { |
298 | case t_int: | |
301 | case wf_int: | |
299 | 302 | if (getdns_dict_set_int(rdata_dict, |
300 | 303 | rdf->rdd_pos->name, int_val)) |
301 | 304 | goto rdata_error; |
302 | 305 | break; |
303 | case t_bindata: | |
304 | if (getdns_dict_set_bindata(rdata_dict, | |
305 | rdf->rdd_pos->name, &bindata)) | |
306 | case wf_bindata: | |
307 | if (_getdns_dict_set_const_bindata(rdata_dict, | |
308 | rdf->rdd_pos->name, bin_size, bin_data)) | |
306 | 309 | goto rdata_error; |
307 | 310 | break; |
308 | case t_dict: | |
309 | if (rdf->rdd_pos->special->dict_set_value( | |
311 | case wf_special: | |
312 | if (rdf->rdd_pos->special->wire2dict( | |
310 | 313 | rdata_dict, rdf->pos)) |
311 | 314 | goto rdata_error; |
312 | 315 | default: |
323 | 326 | goto rdata_error; |
324 | 327 | |
325 | 328 | switch (val_type) { |
326 | case t_int: | |
329 | case wf_int: | |
327 | 330 | if (_getdns_list_append_int(repeat_list, |
328 | 331 | int_val)) |
329 | 332 | goto rdata_error; |
330 | 333 | break; |
331 | case t_bindata: | |
332 | if (_getdns_list_append_bindata(repeat_list, | |
333 | &bindata)) | |
334 | case wf_bindata: | |
335 | if (_getdns_list_append_const_bindata( | |
336 | repeat_list, bin_size, bin_data)) | |
334 | 337 | goto rdata_error; |
335 | 338 | break; |
336 | case t_dict: | |
337 | if (rdf->rdd_pos->special->list_append_value( | |
339 | case wf_special: | |
340 | if (rdf->rdd_pos->special->wire2list( | |
338 | 341 | repeat_list, rdf->pos)) |
339 | 342 | goto rdata_error; |
340 | 343 | default: |
362 | 365 | } |
363 | 366 | assert(repeat_dict); |
364 | 367 | switch (val_type) { |
365 | case t_int: | |
368 | case wf_int: | |
366 | 369 | if (getdns_dict_set_int(repeat_dict, |
367 | 370 | rdf->rdd_pos->name, int_val)) |
368 | 371 | goto rdata_error; |
369 | 372 | break; |
370 | case t_bindata: | |
371 | if (getdns_dict_set_bindata(repeat_dict, | |
372 | rdf->rdd_pos->name, &bindata)) | |
373 | case wf_bindata: | |
374 | if (_getdns_dict_set_const_bindata(repeat_dict, | |
375 | rdf->rdd_pos->name, bin_size, bin_data)) | |
373 | 376 | goto rdata_error; |
374 | 377 | break; |
375 | case t_dict: | |
376 | if (rdf->rdd_pos->special->dict_set_value( | |
378 | case wf_special: | |
379 | if (rdf->rdd_pos->special->wire2dict( | |
377 | 380 | repeat_dict, rdf->pos)) |
378 | 381 | goto rdata_error; |
379 | 382 | default: |
433 | 436 | if (*var) |
434 | 437 | getdns_dict_destroy(*var); |
435 | 438 | return *var = value; |
439 | } | |
440 | ||
441 | inline static int has_all_numeric_label(const uint8_t *dname) | |
442 | { | |
443 | size_t i; | |
444 | ||
445 | while (*dname && !(*dname & 0xc0)) { | |
446 | for (i = 1; i <= *dname; i++) { | |
447 | if (!isdigit(dname[i])) | |
448 | break; | |
449 | } | |
450 | if (i > *dname) | |
451 | return 1; | |
452 | dname += *dname + 1; | |
453 | } | |
454 | return 0; | |
436 | 455 | } |
437 | 456 | |
438 | 457 | #define SET_WIRE_INT(X,Y) if (getdns_dict_set_int(header, #X , (int) \ |
496 | 515 | getdns_dict *rr_dict = NULL; |
497 | 516 | _getdns_rr_iter rr_iter_storage, *rr_iter; |
498 | 517 | _getdns_rdf_iter rdf_iter_storage, *rdf_iter; |
499 | getdns_bindata bindata; | |
518 | size_t bin_size; | |
519 | const uint8_t *bin_data; | |
500 | 520 | gldns_pkt_section section; |
501 | uint8_t canonical_name_space[256], | |
502 | *canonical_name = canonical_name_space; | |
503 | uint8_t owner_name_space[256], *owner_name; | |
521 | uint8_t canonical_name_space[256], owner_name_space[256]; | |
522 | const uint8_t *canonical_name = canonical_name_space, *owner_name; | |
504 | 523 | size_t canonical_name_len = sizeof(canonical_name_space), |
505 | 524 | owner_name_len = sizeof(owner_name_space); |
506 | int new_canonical = 0; | |
525 | int new_canonical = 0, cnames_followed, | |
526 | request_answered, all_numeric_label; | |
507 | 527 | uint16_t rr_type; |
508 | 528 | getdns_dict *header = NULL; |
529 | getdns_list *bad_dns = NULL; | |
509 | 530 | |
510 | 531 | if (!result) |
511 | 532 | goto error; |
591 | 612 | &rdf_iter_storage, rr_iter))) |
592 | 613 | continue; |
593 | 614 | |
594 | bindata.size = rdf_iter->nxt - rdf_iter->pos; | |
595 | bindata.data = rdf_iter->pos; | |
615 | bin_size = rdf_iter->nxt - rdf_iter->pos; | |
616 | bin_data = rdf_iter->pos; | |
596 | 617 | if (!set_dict(&rr_dict, getdns_dict_create_with_context(context)) || |
597 | 618 | |
598 | 619 | getdns_dict_util_set_string(rr_dict, "address_type", |
599 | 620 | rr_type == GETDNS_RRTYPE_A ? "IPv4" : "IPv6" ) || |
600 | 621 | |
601 | getdns_dict_set_bindata(rr_dict,"address_data",&bindata) || | |
622 | _getdns_dict_set_const_bindata( | |
623 | rr_dict, "address_data", bin_size, bin_data) || | |
602 | 624 | |
603 | 625 | (just_addrs && _getdns_list_append_dict(just_addrs, rr_dict))) { |
604 | 626 | |
623 | 645 | if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS)) |
624 | 646 | goto error; |
625 | 647 | |
648 | cnames_followed = new_canonical; | |
626 | 649 | while (new_canonical) { |
627 | 650 | new_canonical = 0; |
628 | 651 | |
629 | 652 | for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage |
630 | , req->response | |
631 | , req->response_len) | |
653 | , req->response | |
654 | , req->response_len) | |
632 | 655 | ; rr_iter && _getdns_rr_iter_section(rr_iter) |
633 | 656 | <= GLDNS_SECTION_ANSWER |
634 | 657 | ; rr_iter = _getdns_rr_iter_next(rr_iter)) { |
655 | 678 | new_canonical = 1; |
656 | 679 | } |
657 | 680 | } |
658 | bindata.data = canonical_name; | |
659 | bindata.size = canonical_name_len; | |
660 | if (getdns_dict_set_bindata(result, "canonical_name", &bindata)) | |
681 | if (_getdns_dict_set_const_bindata( | |
682 | result, "canonical_name", canonical_name_len, canonical_name)) | |
683 | goto error; | |
684 | ||
685 | if (!req->owner->add_warning_for_bad_dns) | |
686 | goto success; | |
687 | ||
688 | if (!(bad_dns = getdns_list_create_with_context(context))) | |
689 | goto error; | |
690 | ||
691 | if (cnames_followed && req->request_type != GETDNS_RRTYPE_CNAME) { | |
692 | request_answered = 0; | |
693 | for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage | |
694 | , req->response | |
695 | , req->response_len) | |
696 | ; rr_iter && _getdns_rr_iter_section(rr_iter) | |
697 | <= GLDNS_SECTION_ANSWER | |
698 | ; rr_iter = _getdns_rr_iter_next(rr_iter)) { | |
699 | ||
700 | if (_getdns_rr_iter_section(rr_iter) != | |
701 | GLDNS_SECTION_ANSWER) | |
702 | continue; | |
703 | if (gldns_read_uint16(rr_iter->rr_type) != | |
704 | req->request_type) | |
705 | continue; | |
706 | ||
707 | owner_name=_getdns_owner_if_or_as_decompressed( | |
708 | rr_iter, owner_name_space,&owner_name_len); | |
709 | if (_getdns_dname_equal( | |
710 | canonical_name, owner_name)) { | |
711 | request_answered = 1; | |
712 | break; | |
713 | } | |
714 | } | |
715 | if (!request_answered && | |
716 | _getdns_list_append_int(bad_dns, | |
717 | GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE)) | |
718 | goto error; | |
719 | } | |
720 | all_numeric_label = 0; | |
721 | for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage | |
722 | , req->response | |
723 | , req->response_len) | |
724 | ; rr_iter && !all_numeric_label | |
725 | ; rr_iter = _getdns_rr_iter_next(rr_iter)) { | |
726 | ||
727 | owner_name = _getdns_owner_if_or_as_decompressed( | |
728 | rr_iter, owner_name_space, &owner_name_len); | |
729 | ||
730 | if (has_all_numeric_label(owner_name)) { | |
731 | all_numeric_label = 1; | |
732 | break; | |
733 | } | |
734 | if (_getdns_rr_iter_section(rr_iter) == | |
735 | GLDNS_SECTION_QUESTION) | |
736 | continue; | |
737 | ||
738 | for ( rdf_iter = _getdns_rdf_iter_init(&rdf_iter_storage, rr_iter) | |
739 | ; rdf_iter; rdf_iter = _getdns_rdf_iter_next(rdf_iter)) { | |
740 | ||
741 | if (!(rdf_iter->rdd_pos->type & GETDNS_RDF_DNAME)) | |
742 | continue; | |
743 | ||
744 | owner_name = _getdns_rdf_if_or_as_decompressed( | |
745 | rdf_iter, owner_name_space, &owner_name_len); | |
746 | ||
747 | if (has_all_numeric_label(owner_name)) { | |
748 | all_numeric_label = 1; | |
749 | break; | |
750 | } | |
751 | } | |
752 | } | |
753 | if (all_numeric_label && | |
754 | _getdns_list_append_int(bad_dns, GETDNS_BAD_DNS_ALL_NUMERIC_LABEL)) | |
755 | goto error; | |
756 | ||
757 | if (getdns_dict_set_list(result, "bad_dns", bad_dns)) | |
661 | 758 | goto error; |
662 | 759 | |
663 | 760 | goto success; |
671 | 768 | getdns_list_destroy(sections[GLDNS_SECTION_AUTHORITY]); |
672 | 769 | getdns_list_destroy(sections[GLDNS_SECTION_ANSWER]); |
673 | 770 | getdns_dict_destroy(question); |
771 | getdns_list_destroy(bad_dns); | |
674 | 772 | return result; |
675 | 773 | } |
676 | 774 | |
677 | 775 | getdns_dict * |
678 | _getdns_create_call_debugging_dict( | |
776 | _getdns_create_call_reporting_dict( | |
679 | 777 | getdns_context *context, getdns_network_req *netreq) |
680 | 778 | { |
681 | 779 | getdns_bindata qname; |
728 | 826 | return NULL; |
729 | 827 | } |
730 | 828 | getdns_dict_destroy(address_debug); |
829 | ||
830 | if (transport != GETDNS_TRANSPORT_UDP) { | |
831 | /* Report the idle timeout actually used on the connection. Must trim, | |
832 | maximum used in practice is 6553500ms, but this is stored in a uint64_t.*/ | |
833 | if (netreq->upstream->keepalive_timeout > UINT32_MAX) { | |
834 | if (getdns_dict_set_int( netreq_debug, "idle timeout in ms (overflow)", UINT32_MAX)) { | |
835 | getdns_dict_destroy(netreq_debug); | |
836 | return NULL; | |
837 | } | |
838 | } else{ | |
839 | uint32_t idle_timeout = netreq->upstream->keepalive_timeout; | |
840 | if (getdns_dict_set_int( netreq_debug, "idle timeout in ms", idle_timeout)) { | |
841 | getdns_dict_destroy(netreq_debug); | |
842 | return NULL; | |
843 | } | |
844 | } | |
845 | } | |
731 | 846 | |
732 | 847 | if (netreq->upstream->transport != GETDNS_TRANSPORT_TLS) |
733 | 848 | return netreq_debug; |
750 | 865 | getdns_list *just_addrs = NULL; |
751 | 866 | getdns_list *replies_full; |
752 | 867 | getdns_list *replies_tree; |
753 | getdns_list *call_debugging = NULL; | |
868 | getdns_list *call_reporting = NULL; | |
754 | 869 | getdns_network_req *netreq, **netreq_p; |
755 | 870 | int rrsigs_in_answer = 0; |
756 | 871 | getdns_dict *reply; |
791 | 906 | if (!(replies_tree = getdns_list_create_with_context(context))) |
792 | 907 | goto error_free_replies_full; |
793 | 908 | |
794 | if (completed_request->return_call_debugging && | |
795 | !(call_debugging = getdns_list_create_with_context(context))) | |
909 | if (completed_request->return_call_reporting && | |
910 | !(call_reporting = getdns_list_create_with_context(context))) | |
796 | 911 | goto error_free_replies_full; |
797 | 912 | |
798 | 913 | for ( netreq_p = completed_request->netreqs |
800 | 915 | |
801 | 916 | if (! netreq->response_len) |
802 | 917 | continue; |
918 | ||
919 | if (netreq->tsig_status == GETDNS_DNSSEC_INSECURE) | |
920 | _getdns_network_validate_tsig(netreq); | |
803 | 921 | |
804 | 922 | nreplies++; |
805 | 923 | if (netreq->dnssec_status == GETDNS_DNSSEC_SECURE) |
819 | 937 | else if (completed_request->dnssec_return_only_secure |
820 | 938 | && netreq->dnssec_status != GETDNS_DNSSEC_SECURE) |
821 | 939 | continue; |
940 | else if (netreq->tsig_status == GETDNS_DNSSEC_BOGUS) | |
941 | continue; | |
822 | 942 | } |
823 | 943 | if (!(reply = _getdns_create_reply_dict(context, |
824 | 944 | netreq, just_addrs, &rrsigs_in_answer))) |
846 | 966 | netreq->dnssec_status)) |
847 | 967 | goto error; |
848 | 968 | } |
849 | ||
969 | if (netreq->tsig_status != GETDNS_DNSSEC_INDETERMINATE) { | |
970 | if (getdns_dict_set_int(reply, "tsig_status", | |
971 | netreq->tsig_status)) | |
972 | goto error; | |
973 | } | |
850 | 974 | if (_getdns_list_append_dict(replies_tree, reply)) { |
851 | 975 | getdns_dict_destroy(reply); |
852 | 976 | goto error; |
853 | 977 | } |
854 | 978 | |
855 | if (call_debugging) { | |
979 | if (call_reporting) { | |
856 | 980 | if (!(netreq_debug = |
857 | _getdns_create_call_debugging_dict(context,netreq))) | |
981 | _getdns_create_call_reporting_dict(context,netreq))) | |
858 | 982 | goto error; |
859 | 983 | |
860 | 984 | if (_getdns_list_append_dict( |
861 | call_debugging, netreq_debug)) { | |
985 | call_reporting, netreq_debug)) { | |
862 | 986 | |
863 | 987 | getdns_dict_destroy(netreq_debug); |
864 | 988 | goto error; |
878 | 1002 | goto error; |
879 | 1003 | getdns_list_destroy(replies_tree); |
880 | 1004 | |
881 | if (call_debugging && | |
882 | getdns_dict_set_list(result, "call_debugging", call_debugging)) | |
883 | goto error_free_call_debugging; | |
1005 | if (call_reporting && | |
1006 | getdns_dict_set_list(result, "call_reporting", call_reporting)) | |
1007 | goto error_free_call_reporting; | |
884 | 1008 | |
885 | 1009 | if (getdns_dict_set_list(result, "replies_full", replies_full)) |
886 | 1010 | goto error_free_replies_full; |
905 | 1029 | error: |
906 | 1030 | /* cleanup */ |
907 | 1031 | getdns_list_destroy(replies_tree); |
908 | error_free_call_debugging: | |
909 | getdns_list_destroy(call_debugging); | |
1032 | error_free_call_reporting: | |
1033 | getdns_list_destroy(call_reporting); | |
910 | 1034 | error_free_replies_full: |
911 | 1035 | getdns_list_destroy(replies_full); |
912 | 1036 | error_free_result: |
1005 | 1129 | , netreq->request_type); |
1006 | 1130 | gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE |
1007 | 1131 | + netreq->owner->name_len + 2 |
1008 | , netreq->request_class); | |
1132 | , netreq->owner->request_class); | |
1009 | 1133 | |
1010 | 1134 | netreq->response_len = GLDNS_HEADER_SIZE + netreq->owner->name_len + 4; |
1011 | 1135 |
41 | 41 | #include "context.h" |
42 | 42 | #include "rr-iter.h" |
43 | 43 | |
44 | #define UNCONST_UINT8_p uint8_t * | |
44 | 45 | |
45 | 46 | #ifdef S_SPLINT_S |
46 | 47 | # define INLINE |
79 | 80 | |
80 | 81 | getdns_return_t _getdns_list_append_int(getdns_list *list, |
81 | 82 | uint32_t child_uint32); |
83 | ||
84 | getdns_return_t _getdns_list_append_const_bindata(getdns_list *list, | |
85 | size_t size, const void *data); | |
86 | ||
87 | getdns_return_t _getdns_dict_set_const_bindata(getdns_dict *dict, | |
88 | const char *name, size_t size, const void *data); | |
82 | 89 | |
83 | 90 | /** |
84 | 91 | * private function (API users should not be calling this), this uses library |
152 | 159 | */ |
153 | 160 | getdns_return_t _getdns_validate_extensions(struct getdns_dict * extensions); |
154 | 161 | |
155 | #define DEBUG_ON(...) do { \ | |
156 | struct timeval tv; \ | |
157 | struct tm tm; \ | |
158 | char buf[10]; \ | |
159 | \ | |
160 | gettimeofday(&tv, NULL); \ | |
161 | gmtime_r(&tv.tv_sec, &tm); \ | |
162 | strftime(buf, 10, "%T", &tm); \ | |
163 | fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ | |
164 | fprintf(stderr, __VA_ARGS__); \ | |
165 | } while (0) | |
166 | ||
167 | #define DEBUG_NL(...) do { \ | |
168 | struct timeval tv; \ | |
169 | struct tm tm; \ | |
170 | char buf[10]; \ | |
171 | \ | |
172 | gettimeofday(&tv, NULL); \ | |
173 | gmtime_r(&tv.tv_sec, &tm); \ | |
174 | strftime(buf, 10, "%T", &tm); \ | |
175 | fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ | |
176 | fprintf(stderr, __VA_ARGS__); \ | |
177 | fprintf(stderr, "\n"); \ | |
178 | } while (0) | |
179 | ||
180 | ||
181 | #define DEBUG_OFF(...) do {} while (0) | |
182 | ||
183 | #if defined(SCHED_DEBUG) && SCHED_DEBUG | |
184 | #include <time.h> | |
185 | #define DEBUG_SCHED(...) DEBUG_ON(__VA_ARGS__) | |
186 | #else | |
187 | #define DEBUG_SCHED(...) DEBUG_OFF(__VA_ARGS__) | |
188 | #endif | |
189 | ||
190 | #if defined(STUB_DEBUG) && STUB_DEBUG | |
191 | #include <time.h> | |
192 | #define DEBUG_STUB(...) DEBUG_ON(__VA_ARGS__) | |
193 | #else | |
194 | #define DEBUG_STUB(...) DEBUG_OFF(__VA_ARGS__) | |
195 | #endif | |
196 | ||
197 | #if defined(SEC_DEBUG) && SEC_DEBUG | |
198 | #include <time.h> | |
199 | #define DEBUG_SEC(...) DEBUG_ON(__VA_ARGS__) | |
200 | #else | |
201 | #define DEBUG_SEC(...) DEBUG_OFF(__VA_ARGS__) | |
202 | #endif | |
203 | ||
204 | 162 | INLINE getdns_eventloop_event *getdns_eventloop_event_init( |
205 | 163 | getdns_eventloop_event *ev,void *userarg, getdns_eventloop_callback read_cb, |
206 | 164 | getdns_eventloop_callback write_cb, getdns_eventloop_callback timeout_cb) |
34 | 34 | |
35 | 35 | const char *getdns_get_version(void) |
36 | 36 | { |
37 | return "0.5.1"; | |
37 | return "0.9.0"; | |
38 | 38 | } |
39 | 39 | |
40 | 40 | uint32_t getdns_get_version_number(void) |
41 | 41 | { |
42 | return 0x00050100; | |
42 | return 0x00090000; | |
43 | 43 | } |
44 | 44 | |
45 | 45 | const char *getdns_get_api_version(void) |
46 | 46 | { |
47 | return "October 2015"; | |
47 | return "December 2015"; | |
48 | 48 | } |
49 | 49 | |
50 | 50 | uint32_t getdns_get_api_version_number(void) |
51 | 51 | { |
52 | return 0x07df0a00; | |
52 | return 0x07df0c00; | |
53 | 53 | } |
54 | 54 | |
55 | 55 | /* version.c */ |