From 42d845fbbc1e6d00997af52f218c15113be74a8c Mon Sep 17 00:00:00 2001 From: boB Rudis Date: Sun, 20 Jan 2019 10:29:22 -0500 Subject: [PATCH] lookup works --- DESCRIPTION | 11 +++- NAMESPACE | 3 + R/RcppExports.R | 16 +++++ R/clandnstine-package.R | 13 ++-- README.Rmd | 74 ++++++++++++++++++++++- README.md | 154 +++++++++++++++++++++++++++++++++++++++++++++++ man/get_address.Rd | 21 +++++++ src/.gitignore | 3 + src/Makevars | 3 + src/RcppExports.cpp | 29 +++++++++ src/clandnstine-main.cpp | 79 ++++++++++++++++++++++++ 11 files changed, 398 insertions(+), 8 deletions(-) create mode 100644 R/RcppExports.R create mode 100644 man/get_address.Rd create mode 100644 src/.gitignore create mode 100644 src/Makevars create mode 100644 src/RcppExports.cpp create mode 100644 src/clandnstine-main.cpp diff --git a/DESCRIPTION b/DESCRIPTION index a8574ac..e3a0c84 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: clandnstine Type: Package -Title: clandnstine title goes here otherwise CRAN checks fail +Title: Perform 'DNS' over 'TLS' Queries Version: 0.1.0 Date: 2019-01-18 Authors@R: c( @@ -8,7 +8,9 @@ Authors@R: c( comment = c(ORCID = "0000-0001-5670-2640")) ) Maintainer: Bob Rudis -Description: A good description goes here otherwise CRAN checks fail. +Description: Something something 'DNS. Something something 'TLS'. + Something something 'getdns API/library'. +SystemRequirements: C++11 URL: https://gitlab.com/hrbrmstr/clandnstine BugReports: https://gitlab.com/hrbrmstr/clandnstine/issues Encoding: UTF-8 @@ -20,6 +22,9 @@ Depends: R (>= 3.2.0) Imports: httr, - jsonlite + jsonlite, + Rcpp Roxygen: list(markdown = TRUE) RoxygenNote: 6.1.1 +LinkingTo: + Rcpp diff --git a/NAMESPACE b/NAMESPACE index 5b4b9ae..c703ef0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,4 +1,7 @@ # Generated by roxygen2: do not edit by hand +export(get_address) import(httr) +importFrom(Rcpp,sourceCpp) importFrom(jsonlite,fromJSON) +useDynLib(clandnstine, .registration = TRUE) diff --git a/R/RcppExports.R b/R/RcppExports.R new file mode 100644 index 0000000..add781b --- /dev/null +++ b/R/RcppExports.R @@ -0,0 +1,16 @@ +# Generated by using Rcpp::compileAttributes() -> do not edit by hand +# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#' Lookup IP Address(es) for a Given Host +#' +#' @param host host (length 1 ) +#' @param resolver resolver address. defaults to Quad9; (length 1 ) +#' @export +#' @examples +#' get_address("r-project.org") +#' get_address("yahoo.com", "1.1.1.1") +#' get_address("microsoft.com", "8.8.8.8") +get_address <- function(host, resolver = "9.9.9.9") { + .Call(`_clandnstine_get_address`, host, resolver) +} + diff --git a/R/clandnstine-package.R b/R/clandnstine-package.R index 0f7f6f4..03cf0c3 100644 --- a/R/clandnstine-package.R +++ b/R/clandnstine-package.R @@ -1,12 +1,17 @@ -#' ... -#' +#' Perform 'DNS' over 'TLS' Queries +#' +#' Something something 'DNS. Something something 'TLS'. +#' Something something 'getdns API/library'. +#' #' - URL: #' - BugReports: -#' +#' #' @md #' @name clandnstine #' @docType package #' @author Bob Rudis (bob@@rud.is) #' @import httr #' @importFrom jsonlite fromJSON -NULL +#' @useDynLib clandnstine, .registration = TRUE +#' @importFrom Rcpp sourceCpp +NULL \ No newline at end of file diff --git a/README.Rmd b/README.Rmd index 7b570aa..59ba952 100644 --- a/README.Rmd +++ b/README.Rmd @@ -4,7 +4,7 @@ editor_options: chunk_output_type: inline --- ```{r pkg-knitr-opts, include=FALSE} -knitr$opts_chunk$set(collapse=TRUE, fig.retina=2, message=FALSE, warning=FALSE) +knitr::opts_chunk$set(collapse=TRUE, fig.retina=2, message=FALSE, warning=FALSE) options(width=120) ``` @@ -14,12 +14,76 @@ options(width=120) # clandnstine +Perform 'DNS' over 'TLS' Queries + ## Description +Something something 'DNS. Something something 'TLS'. Something something 'getdns API/library'. + +## NOTE + +Requires [`getdns`](https://getdnsapi.net/) to be installed and available for compilation (no guard rails setup yet): + +- Use `brew install getdns` on macOS +- Install `libgetdns-dev` on debian/ubuntu +- (Nothing to see here Windows folks stuck in a backwards ecosysem) + +## TODO/WAT + +I finally grok the getdns api so the package api is going to change wildly and fast. It's only going to support DNS over TLS but will support all types of DNS queries. + +The current "got it working" single function is stupid slow since it creates and destroys a context or each lookup. DNS over TLS was designed to support maintaining a session to avoid this overhead so the package is going to migrate to a "create a resolver" then "use this resolver to resolve X" then "destroy (or have R autodestroy)" the C-size resolver context when the R object goes away model pretty quickly. + +## Why? + +Well, for starters, to help research DNS over TLS servers. Plus, for fun! + +If you're asking "Why DNS over TLS at all?" then "faux" privacy. Why "faux"? Well, _something_ is handing your query and that something knows your IP address and what you looked for. So, you're relying on the good faith, honest nature and technical capability of the destination server to not mess with you. I don't trust Cloudflare or Google and am witholding judgement on Quad9 either way (they've been doing good things and are less "look at how cool we are" than CF is). + +Also "faux" in that you're going to be using a standard port (853) and a TLS session for the queries so your internet provider will know you're doing _something_ and the current, sorry state of SSL certificates, certificate authorities, and authoritarian companies and regimes combined means confidentiality and integrity are always kinda in question unless done super-well. + +## What's Different About This vs Regular DNS? + +Well, if we lookup the addresses for `yahoo.com` the old-fashioned way it's cleartext UDP on the wire: + + 1 0.000000 10.1.10.57 → 10.1.10.200 DNS 80 Standard query 0x8af8 A yahoo.com OPT + 2 0.003297 10.1.10.200 → 10.1.10.57 DNS 176 Standard query response 0x8af8 A yahoo.com A 72.30.35.10 A 98.138.219.231 A 72.30.35.9 A 98.137.246.7 A 98.138.219.232 A 98.137.246.8 OPT + +I watched for port 53 UDP traffic with `tshark` as `yahoo.com` was being looked up. Notice the fast and diminuitive — and plaintext — response. (I'm fibbing a bit since I pre-loaded the local home DNS server with this query since I tested it alot before knitting this readme. My home server forwards all queries to a custom DNS over TLS server since I really don't trust any of the providers when it comes down to it. So, in reality for me, it's even slower than the below — at least initially). + +This is the same query via DNS over TLS + + 1 0.000000 10.1.10.57 → 9.9.9.9 TCP 78 52128 → 853 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=64 TSval=602885491 TSecr=0 SACK_PERM=1 TFO=R + 2 0.021188 9.9.9.9 → 10.1.10.57 TCP 74 853 → 52128 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=3426782438 TSecr=602885491 WS=256 + 3 0.021308 10.1.10.57 → 9.9.9.9 TLSv1 373 Client Hello + 4 0.045324 9.9.9.9 → 10.1.10.57 TLSv1.2 1514 Server Hello + 5 0.045333 9.9.9.9 → 10.1.10.57 TLSv1.2 73 [TCP Previous segment not captured] , Ignored Unknown Record + 6 0.045334 9.9.9.9 → 10.1.10.57 TCP 1514 [TCP Out-Of-Order] 853 → 52128 [ACK] Seq=1449 Ack=308 Win=30208 Len=1448 TSval=3426782459 TSecr=602885512 + 7 0.045491 10.1.10.57 → 9.9.9.9 TCP 78 52128 → 853 [ACK] Seq=308 Ack=1449 Win=130304 Len=0 TSval=602885536 TSecr=3426782459 SLE=2897 SRE=2904 + 8 0.045492 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=308 Ack=2904 Win=128832 Len=0 TSval=602885536 TSecr=3426782459 + 9 0.050527 10.1.10.57 → 9.9.9.9 TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message + 10 0.069107 9.9.9.9 → 10.1.10.57 TLSv1.2 117 Change Cipher Spec, Encrypted Handshake Message + 11 0.069255 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=434 Ack=2955 Win=131008 Len=0 TSval=602885559 TSecr=3426782487 + 12 0.069516 10.1.10.57 → 9.9.9.9 TLSv1.2 225 Application Data + 13 0.091087 9.9.9.9 → 10.1.10.57 TLSv1.2 303 Application Data + 14 0.091207 10.1.10.57 → 9.9.9.9 TLSv1.2 225 Application Data + 15 0.106738 9.9.9.9 → 10.1.10.57 TLSv1.2 231 Application Data + 16 0.106836 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=752 Ack=3357 Win=130880 Len=0 TSval=602885595 TSecr=3426782525 + 17 0.107200 10.1.10.57 → 9.9.9.9 TLSv1.2 97 Encrypted Alert + 18 0.107411 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [FIN, ACK] Seq=783 Ack=3357 Win=131072 Len=0 TSval=602885595 TSecr=3426782525 + 19 0.126603 9.9.9.9 → 10.1.10.57 TLSv1.2 97 Encrypted Alert + 20 0.126608 9.9.9.9 → 10.1.10.57 TCP 66 853 → 52128 [FIN, ACK] Seq=3388 Ack=784 Win=32256 Len=0 TSval=3426782545 TSecr=602885595 + 21 0.126717 10.1.10.57 → 9.9.9.9 TCP 54 52128 → 853 [RST] Seq=784 Win=0 Len=0 + 22 0.126718 10.1.10.57 → 9.9.9.9 TCP 54 52128 → 853 [RST] Seq=784 Win=0 Len=0 + +It's stupid slow, consumes more CPU and bandwidth but forces adversaries to work pretty hard to try to figure out what you're looking for. + ## What's Inside The Tin The following functions are implemented: +- `get_address`: Lookup IP Address(es) for a Given Host + ## Installation ```{r install-ex, eval=FALSE} @@ -38,6 +102,14 @@ packageVersion("clandnstine") ``` +```{r addr} +get_address("r-project.org") # use built-in default of Quad9 (9.9.9.9) + +get_address("yahoo.com", "8.8.8.8") # use google and get a bigger return back, too + +get_address("doesnotexist.commmm", "1.1.1.1") # nothing to find +``` + ## clandnstine Metrics ```{r cloc, echo=FALSE} diff --git a/README.md b/README.md index 1dd850f..81088cf 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,156 @@ + +[![Travis-CI Build +Status](https://travis-ci.org/hrbrmstr/clandnstine.svg?branch=master)](https://travis-ci.org/hrbrmstr/clandnstine) +[![Coverage +Status](https://codecov.io/gh/hrbrmstr/clandnstine/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/clandnstine) +[![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/clandnstine)](https://cran.r-project.org/package=clandnstine) + # clandnstine +Perform ‘DNS’ over ‘TLS’ Queries + +## Description + +Something something ‘DNS. Something something ’TLS’. Something something +‘getdns API/library’. + +## NOTE + +Requires [`getdns`](https://getdnsapi.net/) to be installed and +available for compilation (no guard rails setup yet): + + - Use `brew install getdns` on macOS + - Install `libgetdns-dev` on debian/ubuntu + - (Nothing to see here Windows folks stuck in a backwards ecosysem) + +## TODO/WAT + +I finally grok the getdns api so the package api is going to change +wildly and fast. It’s only going to support DNS over TLS but will +support all types of DNS queries. + +The current “got it working” single function is stupid slow since it +creates and destroys a context or each lookup. DNS over TLS was designed +to support maintaining a session to avoid this overhead so the package +is going to migrate to a “create a resolver” then “use this resolver to +resolve X” then “destroy (or have R autodestroy)” the C-size resolver +context when the R object goes away model pretty quickly. + +## Why? + +Well, for starters, to help research DNS over TLS servers. Plus, for +fun\! + +If you’re asking “Why DNS over TLS at all?” then “faux” privacy. Why +“faux”? Well, *something* is handing your query and that something +knows your IP address and what you looked for. So, you’re relying on the +good faith, honest nature and technical capability of the destination +server to not mess with you. I don’t trust Cloudflare or Google and am +witholding judgement on Quad9 either way (they’ve been doing good things +and are less “look at how cool we are” than CF is). + +Also “faux” in that you’re going to be using a standard port (853) and a +TLS session for the queries so your internet provider will know you’re +doing *something* and the current, sorry state of SSL certificates, +certificate authorities, and authoritarian companies and regimes +combined means confidentiality and integrity are always kinda in +question unless done super-well. + +## What’s Different About This vs Regular DNS? + +Well, if we lookup the addresses for `yahoo.com` the old-fashioned way +it’s cleartext UDP on the + wire: + + 1 0.000000 10.1.10.57 → 10.1.10.200 DNS 80 Standard query 0x8af8 A yahoo.com OPT + 2 0.003297 10.1.10.200 → 10.1.10.57 DNS 176 Standard query response 0x8af8 A yahoo.com A 72.30.35.10 A 98.138.219.231 A 72.30.35.9 A 98.137.246.7 A 98.138.219.232 A 98.137.246.8 OPT + +I watched for port 53 UDP traffic with `tshark` as `yahoo.com` was being +looked up. Notice the fast and diminuitive — and plaintext — response. +(I’m fibbing a bit since I pre-loaded the local home DNS server with +this query since I tested it alot before knitting this readme. My home +server forwards all queries to a custom DNS over TLS server since I +really don’t trust any of the providers when it comes down to it. So, in +reality for me, it’s even slower than the below — at least initially). + +This is the same query via DNS over +TLS + +``` + 1 0.000000 10.1.10.57 → 9.9.9.9 TCP 78 52128 → 853 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=64 TSval=602885491 TSecr=0 SACK_PERM=1 TFO=R + 2 0.021188 9.9.9.9 → 10.1.10.57 TCP 74 853 → 52128 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=3426782438 TSecr=602885491 WS=256 + 3 0.021308 10.1.10.57 → 9.9.9.9 TLSv1 373 Client Hello + 4 0.045324 9.9.9.9 → 10.1.10.57 TLSv1.2 1514 Server Hello + 5 0.045333 9.9.9.9 → 10.1.10.57 TLSv1.2 73 [TCP Previous segment not captured] , Ignored Unknown Record + 6 0.045334 9.9.9.9 → 10.1.10.57 TCP 1514 [TCP Out-Of-Order] 853 → 52128 [ACK] Seq=1449 Ack=308 Win=30208 Len=1448 TSval=3426782459 TSecr=602885512 + 7 0.045491 10.1.10.57 → 9.9.9.9 TCP 78 52128 → 853 [ACK] Seq=308 Ack=1449 Win=130304 Len=0 TSval=602885536 TSecr=3426782459 SLE=2897 SRE=2904 + 8 0.045492 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=308 Ack=2904 Win=128832 Len=0 TSval=602885536 TSecr=3426782459 + 9 0.050527 10.1.10.57 → 9.9.9.9 TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message +10 0.069107 9.9.9.9 → 10.1.10.57 TLSv1.2 117 Change Cipher Spec, Encrypted Handshake Message +11 0.069255 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=434 Ack=2955 Win=131008 Len=0 TSval=602885559 TSecr=3426782487 +12 0.069516 10.1.10.57 → 9.9.9.9 TLSv1.2 225 Application Data +13 0.091087 9.9.9.9 → 10.1.10.57 TLSv1.2 303 Application Data +14 0.091207 10.1.10.57 → 9.9.9.9 TLSv1.2 225 Application Data +15 0.106738 9.9.9.9 → 10.1.10.57 TLSv1.2 231 Application Data +16 0.106836 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [ACK] Seq=752 Ack=3357 Win=130880 Len=0 TSval=602885595 TSecr=3426782525 +17 0.107200 10.1.10.57 → 9.9.9.9 TLSv1.2 97 Encrypted Alert +18 0.107411 10.1.10.57 → 9.9.9.9 TCP 66 52128 → 853 [FIN, ACK] Seq=783 Ack=3357 Win=131072 Len=0 TSval=602885595 TSecr=3426782525 +19 0.126603 9.9.9.9 → 10.1.10.57 TLSv1.2 97 Encrypted Alert +20 0.126608 9.9.9.9 → 10.1.10.57 TCP 66 853 → 52128 [FIN, ACK] Seq=3388 Ack=784 Win=32256 Len=0 TSval=3426782545 TSecr=602885595 +21 0.126717 10.1.10.57 → 9.9.9.9 TCP 54 52128 → 853 [RST] Seq=784 Win=0 Len=0 +22 0.126718 10.1.10.57 → 9.9.9.9 TCP 54 52128 → 853 [RST] Seq=784 Win=0 Len=0 +``` + +It’s stupid slow, consumes more CPU and bandwidth but forces adversaries +to work pretty hard to try to figure out what you’re looking for. + +## What’s Inside The Tin + +The following functions are implemented: + + - `get_address`: Lookup IP Address(es) for a Given Host + +## Installation + +``` r +devtools::install_git("https://gitlab.com/hrbrmstr/clandnstine.git") +# or +devtools::install_github("hrbrmstr/clandnstine") +``` + +## Usage + +``` r +library(clandnstine) + +# current version +packageVersion("clandnstine") +## [1] '0.1.0' +``` + +``` r +get_address("r-project.org") # use built-in default of Quad9 (9.9.9.9) +## [1] "137.208.57.37" + +get_address("yahoo.com", "8.8.8.8") # use google and get a bigger return back, too +## [1] "2001:4998:c:1023::4" "2001:4998:c:1023::5" "2001:4998:58:1836::11" "2001:4998:44:41d::4" +## [5] "2001:4998:58:1836::10" "2001:4998:44:41d::3" "72.30.35.10" "98.137.246.7" +## [9] "98.137.246.8" "98.138.219.231" "72.30.35.9" "98.138.219.232" + +get_address("doesnotexist.commmm", "1.1.1.1") # nothing to find +## character(0) +``` + +## clandnstine Metrics + +| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) | +| :--- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: | +| C++ | 2 | 0.29 | 72 | 0.79 | 23 | 0.35 | 13 | 0.11 | +| Rmd | 1 | 0.14 | 10 | 0.11 | 38 | 0.58 | 74 | 0.64 | +| R | 4 | 0.57 | 9 | 0.10 | 4 | 0.06 | 28 | 0.24 | + +## Code of Conduct + +Please note that this project is released with a [Contributor Code of +Conduct](CONDUCT.md). By participating in this project you agree to +abide by its terms. diff --git a/man/get_address.Rd b/man/get_address.Rd new file mode 100644 index 0000000..0c0e4b2 --- /dev/null +++ b/man/get_address.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{get_address} +\alias{get_address} +\title{Lookup IP Address(es) for a Given Host} +\usage{ +get_address(host, resolver = "9.9.9.9") +} +\arguments{ +\item{host}{host (length 1 )} + +\item{resolver}{resolver address. defaults to Quad9; (length 1 )} +} +\description{ +Lookup IP Address(es) for a Given Host +} +\examples{ +get_address("r-project.org") +get_address("yahoo.com", "1.1.1.1") +get_address("microsoft.com", "8.8.8.8") +} diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..22034c4 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +*.dll diff --git a/src/Makevars b/src/Makevars new file mode 100644 index 0000000..469df2b --- /dev/null +++ b/src/Makevars @@ -0,0 +1,3 @@ +CXX_STD = CXX11 +PKG_CXXFLAGS = +PKG_LIBS = -lgetdns diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp new file mode 100644 index 0000000..6e82a23 --- /dev/null +++ b/src/RcppExports.cpp @@ -0,0 +1,29 @@ +// Generated by using Rcpp::compileAttributes() -> do not edit by hand +// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#include + +using namespace Rcpp; + +// get_address +CharacterVector get_address(std::string host, std::string resolver); +RcppExport SEXP _clandnstine_get_address(SEXP hostSEXP, SEXP resolverSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< std::string >::type host(hostSEXP); + Rcpp::traits::input_parameter< std::string >::type resolver(resolverSEXP); + rcpp_result_gen = Rcpp::wrap(get_address(host, resolver)); + return rcpp_result_gen; +END_RCPP +} + +static const R_CallMethodDef CallEntries[] = { + {"_clandnstine_get_address", (DL_FUNC) &_clandnstine_get_address, 2}, + {NULL, NULL, 0} +}; + +RcppExport void R_init_clandnstine(DllInfo *dll) { + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); +} diff --git a/src/clandnstine-main.cpp b/src/clandnstine-main.cpp new file mode 100644 index 0000000..85982d1 --- /dev/null +++ b/src/clandnstine-main.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +using namespace Rcpp; + +//' Lookup IP Address(es) for a Given Host +//' +//' @param host host (length 1 ) +//' @param resolver resolver address. defaults to Quad9; (length 1 ) +//' @export +//' @examples +//' get_address("r-project.org") +//' get_address("yahoo.com", "1.1.1.1") +//' get_address("microsoft.com", "8.8.8.8") +// [[Rcpp::export]] +CharacterVector get_address(std::string host, std::string resolver = "9.9.9.9") { + + uint32_t err; + size_t sz; + getdns_return_t r; + getdns_context *ctxt = NULL; + getdns_dict *resp = NULL; + getdns_list *addrs; + std::vector< std::string > out; + bool ok = false; + + getdns_dict *resolver_dict = getdns_dict_create(); + r = getdns_str2dict(resolver.c_str(), &resolver_dict); + + getdns_list *resolver_list = getdns_list_create(); + r = getdns_list_set_dict(resolver_list, 0, resolver_dict); + + getdns_transport_list_t tls_transport[] = { GETDNS_TRANSPORT_TLS }; + + if ((r = getdns_context_create(&ctxt, 1))) { + } else if ((r = getdns_context_set_dns_transport_list(ctxt, 1, tls_transport))) { + } else if ((r = getdns_context_set_upstream_recursive_servers(ctxt, resolver_list))) { + } else if ((r = getdns_context_set_resolution_type(ctxt, GETDNS_RESOLUTION_STUB))) { + } else if ((r = getdns_address_sync(ctxt, host.c_str(), NULL, &resp))) { + } else if ((r = getdns_dict_get_int(resp, "status", &err))) { + } else if (err != GETDNS_RESPSTATUS_GOOD) { + } else if ((r = getdns_dict_get_list(resp, "just_address_answers", &addrs))) { + } else if (r != GETDNS_RETURN_GOOD) { + } else if ((r = getdns_list_get_length(addrs, &sz))) { + } else { + ok = true; + } + + if (ok) { + + out.reserve(sz); + + for (size_t i = 0; i < sz; ++i) { + + getdns_dict *cur_addr; + getdns_bindata *address; + + r = getdns_list_get_dict(addrs, i, &cur_addr); + r = getdns_dict_get_bindata(cur_addr, "address_data", &address); + + if (address->size == 4 || address->size == 16) { // this is unlikely + char *addr_str = getdns_display_ip_address(address); + out.push_back(addr_str); + if (addr_str) free(addr_str); + } + + } + + out.shrink_to_fit(); + + } + + if (resp) getdns_dict_destroy(resp); + if (ctxt) getdns_context_destroy(ctxt); + + if (ok) return(wrap(out)); else return(CharacterVector()); + +}