#' Create a gdns DNS over TLS context and populate it with a resolver #' for use in resolution functions #' #' @note [DNS Privacy](https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers#DNSPrivacyTestServers-DoTservers) #' maintains a list of DNS over TLS servers. #' @param resolvers character vector of valid DNS over TLS resolvers; #' Defaults to Quad9 (`9.9.9.9`). #' @export #' @family query functions #' @examples #' x <- gdns_context() #' x <- gdns_context("1.1.1.1") gdns_context <- function(resolvers = "9.9.9.9") { int_gdns_context(resolvers) } #' Changes the list of resolvers in an already created context for use in resolution functions #' #' @note [DNS Privacy](https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers#DNSPrivacyTestServers-DoTservers) #' maintains a list of DNS over TLS servers. #' @param gctx gdns resolver context created with [gdns_resolver()] #' @param resolvers character vector of valid DNS over TLS resolvers #' @family context functions #' @export #' @examples #' x <- gdns_context() #' x <- gdns_update_resolvers(x, "1.1.1.1") gdns_update_resolvers<- function(gctx, resolvers) { int_gdns_update_resolvers(gctx, resolvers) } #' Initialized the context's local names namespace with values from the given hosts file. #' #' @param gctx gdns resolver context created with [gdns_resolver()] #' @param hosts_file path to a valid `hosts` file (e.g. "`/etc/hosts`). This value #' will be [path.expand()]ed. #' @export #' @family context functions #' @examples #' x <- gdns_context() #' gdns_set_hosts(x, "/etc/hosts") gdns_set_hosts<- function(gctx, hosts_file) { hosts_file <- path.expand(hosts_file[1]) stopifnot(file.exists(hosts_file)) int_gdns_set_hosts(gctx, hosts_file) } #' Retrieve the list of addresses in use for looking up top-level domains in use by the context. #' #' @param gctx gdns resolver context created with [gdns_resolver()] #' @export #' @family context functions # x <- gdns_context() # gdns_get_root_servers(x) gdns_get_root_servers <- function(gctx) { x <- int_gdns_get_root_servers(gctx); if (length(x)) jsonlite::fromJSON(x) else NULL } #' Arbitrary DNS queries #' #' Perform any valid resource record inquiry for a given name. See `Details`. #' #' This returns a fairly complex result object but that is the nature #' of DNS queries. You're likely going to want what is in `$replies_tree$answer` #' but the rest of the structure contains lovely metadata about the query and #' remote query environment. There will eventually be "as data frame"-ish helpers #' for this object. #' #' Valid values for `rr_type`: #' - `a` #' - `a6` #' - `aaaa` #' - `afsdb` #' - `any` #' - `apl` #' - `atma` #' - `avc` #' - `axfr` #' - `caa` #' - `cdnskey` #' - `cds` #' - `cert` #' - `cname` #' - `csync` #' - `dhcid` #' - `dlv` #' - `dname` #' - `dnskey` #' - `doa` #' - `ds` #' - `eid` #' - `eui48` #' - `eui64` #' - `gid` #' - `gpos` #' - `hinfo` #' - `hip` #' - `ipseckey` #' - `isdn` #' - `ixfr` #' - `key` #' - `kx` #' - `l32` #' - `l64` #' - `loc` #' - `lp` #' - `maila` #' - `mailb` #' - `mb` #' - `md` #' - `mf` #' - `mg` #' - `minfo` #' - `mr` #' - `mx` #' - `naptr` #' - `nid` #' - `nimloc` #' - `ninfo` #' - `ns` #' - `nsap` #' - `nsap_ptr` #' - `nsec` #' - `nsec3` #' - `nsec3param` #' - `null` #' - `nxt` #' - `openpgpkey` #' - `opt` #' - `ptr` #' - `px` #' - `rkey` #' - `rp` #' - `rrsig` #' - `rt` #' - `sig` #' - `sink` #' - `smimea` #' - `soa` #' - `spf` #' - `srv` #' - `sshfp` #' - `ta` #' - `talink` #' - `tkey` #' - `tlsa` #' - `tsig` #' - `txt` #' - `uid` #' - `uinfo` #' - `unspec` #' - `uri` #' - `wks` #' - `x25` #' - `zonemd` #' #' @note Local hosts files are ignored when using this `getdns` API endpoint #' @param gctx gdns resolver context created with [gdns_resolver()]. If `NULL` a #' temporary context will be created but is not ideal since there is overhead #' associated with context creation and garbage collection. #' @param name an entity to query for #' @param rr_type what resource record type do you want to queyr for? See `Details`. #' @param include_reporting if `TRUE` include debugging information for queries #' such as the length of time it takes for each query. Default: `FALSE` #' @references #' @family query functions #' @export #' @examples #' x <- gdns_resolver() #' gdns_query(x, "example.com") gdns_query <- function(gctx = NULL, name, rr_type = "txt", rr_class = 1L, include_reporting = FALSE) { if (is.null(gctx)) gctx <- gdns_context() stopifnot(is_gctx(gctx)) rr_class <- rr_class[1] if (!rr_class %in% c(1, 3, 4, 254, 255)) rr_class <- 1 rr_type <- match.arg(trimws(tolower(rr_type[1])), names(rr_types)) res <- int_gdns_query(gctx, name, unname(as.integer(rr_types[rr_type])), as.logical(include_reporting)) if (length(res)) { out <- jsonlite::fromJSON(res) class(out) <- c("gdns_response", "list") out } else { NULL } } #' Printer for gdns_response objects #' #' @param x a `gdns_response` object #' @param ... ignored #' @keywords internal #' @export print.gdns_response <- function(x, ...) { cat( "Query: ", x$replies_tree$question$qname[1], " ", toupper(rr_types_rev[x$replies_tree$question$qtype[1]]), "\n", sep="" ) qtype <- as.character(x$replies_tree$question$qtype[[1]]) ans <- x$replies_tree$answer[[1]] ans$rdata$rdata_raw <- NULL switch( qtype, "1" = { cat( "Answer: ", paste0(unlist(x$just_address_answers$address_data), collapse="\n"), "\n", sep="" ) }, "2" ={ cat( "Answer: ", paste0(ans$rdata$nsdname, collapse=", "), "\n", sep="" ) }, "15" = { cat( "Answer: \n", paste0(glue::glue_data(ans$rdata, "{preference} {exchange}"), collapse="\n"), "\n", sep="" ) }, "16" = { rd <- ans$rdata typs <- ans$type typs <- which(typs == 16) if (length(typs)) { cat( "Answer: ", paste0(unlist(rd$txt_strings[typs]), collapse="\n"), "\n", sep="" ) } }, "28" = { cat( "Answer: ", paste0(unlist(x$just_address_answers$address_data), collapse="\n"), "\n", sep="" ) }, "257" = { cat( "Answer: \n", paste0(glue::glue_data(ans$rdata, "{flags} {tag} {value}"), collapse="\n"), "\n", sep="" ) }, { print(str(ans$rdata, give.attr = FALSE)) } ) }