Browse Source

intial commit

master
boB Rudis 6 years ago
parent
commit
eb4ed032aa
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 11
      DESCRIPTION
  2. 8
      NAMESPACE
  3. 18
      R/install-zdns.R
  4. 8
      R/ns-refresh.R
  5. 16
      R/utils-keepers.R
  6. 320
      R/utils-mappers.R
  7. 11
      R/utils-pipe.R
  8. 100
      R/zdns-bulk-query.R
  9. 23
      R/zdns-exec.R
  10. 14
      R/zdnsr-package.R
  11. 26
      R/zzz.R
  12. 13
      README.Rmd
  13. 40
      README.md
  14. 11
      man/install_zdns.Rd
  15. 12
      man/pipe.Rd
  16. 11
      man/refresh_publc_nameservers_list.Rd
  17. 16
      man/zdns_exec.Rd
  18. 53
      man/zdns_query.Rd
  19. 9
      man/zdnsr.Rd

11
DESCRIPTION

@ -1,6 +1,6 @@
Package: zdnsr
Type: Package
Title: zdnsr title goes here otherwise CRAN checks fail
Title: Perform Bulk 'DNS' Queries Using 'zdns'
Version: 0.1.0
Date: 2018-09-07
Authors@R: c(
@ -8,7 +8,10 @@ Authors@R: c(
comment = c(ORCID = "0000-0001-5670-2640"))
)
Maintainer: Bob Rudis <bob@rud.is>
Description: A good description goes here otherwise CRAN checks fail.
Description: Provides wrapper/helper methods for executing 'zdns'
(<https://github.com/zmap/zdns>) bulk queries along with utility methods
to retrieve and cache 'Public DNS' (<http://public-dns.info/>) nameserver
lists.
URL: https://gitlab.com/hrbrmstr/zdnsr
BugReports: https://gitlab.com/hrbrmstr/zdnsr/issues
Encoding: UTF-8
@ -19,6 +22,6 @@ Suggests:
Depends:
R (>= 3.2.0)
Imports:
httr,
jsonlite
jsonlite,
magrittr
RoxygenNote: 6.0.1.9000

8
NAMESPACE

@ -1,4 +1,10 @@
# Generated by roxygen2: do not edit by hand
import(httr)
export("%>%")
export(install_zdns)
export(refresh_publc_nameservers_list)
export(zdns_exec)
export(zdns_help)
export(zdns_query)
importFrom(jsonlite,fromJSON)
importFrom(magrittr,"%>%")

18
R/install-zdns.R

@ -0,0 +1,18 @@
#' Helper to try to get zdns installed
#' @export
install_zdns <- function() {
res <- Sys.which("go")
if (res == "") {
packageStartupMessage(
"Go (golang) not found. Please install Go (https://golang.org/dl/) for ",
"your platform and try reloading the package again."
)
} else {
message(
"Attempting to install Go (golang). Please monitor the output for any ",
"errors that might occur during installation.")
res <- system2("go", c("get", "github.com/zmap/zdns/zdns"), stdout="")
}
}

8
R/ns-refresh.R

@ -0,0 +1,8 @@
#' Refresh the list of valid public nameservers
#'
#' @export
refresh_publc_nameservers_list <- function() {
if (!dir.exists(path.expand("~/.zdnsr"))) dir.create(path.expand("~/.zdnsr"))
xdf <- read.csv("https://public-dns.info/nameservers.csv", stringsAsFactors=FALSE)
saveRDS(xdf, file.path(path.expand("~/.zdnsr"), "public-nameservers.rds"))
}

16
R/utils-keepers.R

@ -0,0 +1,16 @@
# NOTE!!!
# This requires map_lgl() which requries map()
is_empty <- function(x) length(x) == 0
keep <- function(.x, .p, ...) {
.x[map_lgl(.x, .p, ...)]
}
discard <- function(.x, .p, ...) {
.x[!map_lgl(.x, .p, ...)]
}
compact <- function(.x, .p=identity) {
discard(.x, function(x) is_empty(.p(x)))
}

320
R/utils-mappers.R

@ -0,0 +1,320 @@
# NOTE: At the bottom of this source file show the equivalents to purrr mappers
#
# NOTE these aren't 100% equivalent to the purrr mappers but cover very common use-cases
#
# NOTE formula function (e.g. ~{}) are 100% supported
#
# NOTE: THESE DO NOT SUPPORT list EXTRACTORS
set_names <- function(object = nm, nm) {
names(object) <- nm
object
}
map <- function(.x, .f, ..., .default) {
default_exists <- !missing(.default)
if (inherits(.f, "formula")) {
.body <- dimnames(attr(terms(.f), "factors"))[[1]]
.f <- function(.x, . = .x) {}
body(.f) <- as.expression(parse(text=.body))
}
nm <- names(.x)
if (inherits(.f, "function")) {
lapply(.x, function(x) {
res <- .f(x, ...)
if ((length(res) == 0) & default_exists) res <- .default
res
}) -> out
} else if (is.numeric(.f) | is.character(.f)) {
lapply(.x, function(x) {
res <- try(x[[.f]], silent = TRUE)
if (inherits(res, "try-error")) res <- NULL
if ((length(res) == 0) & default_exists) res <- .default
res
}) -> out
}
if (length(nm) > 0) out <- set_names(out, nm)
out
}
map2 <- function(.x, .y, .f, ..., .default) {
default_exists <- !missing(.default)
if (inherits(.f, "formula")) {
.body <- dimnames(attr(terms(.f), "factors"))[[1]]
.f <- function(.x, .y, . = .x) {}
body(.f) <- as.expression(parse(text=.body))
}
if (inherits(.f, "function")) {
mapply(
function(x, ...) {
res <- .f(x, ...)
if ((length(res) == 0) & default_exists) res <- .default
res
},
.x, .y,
...,
SIMPLIFY=FALSE, USE.NAMES=FALSE
)
}
}
map_chr <- function(.x, .f, ...) {
nm <- names(.x)
out <- as.character((map(.x, .f, ..., .default = .default)))
if (length(nm) > 0) set_names(out, nm) else out
}
map2_chr <- function(.x, .y, .f, ...) {
as.character(unlist(map2(.x, .y, .f, ..., .default = .default)))
}
map_lgl <- function(.x, .f, ...) {
nm <- names(.x)
out <- as.logical(unlist(map(.x, .f, ..., .default = .default)))
if (length(nm) > 0) set_names(out, nm) else out
}
map2_lgl <- function(.x, .y, .f, ...) {
as.logical(unlist(map2(.x, .y, .f, ..., .default = .default)))
}
map_dbl <- function(.x, .f, ...) {
nm <- names(.x)
out <- as.double(unlist(map(.x, .f, ..., .default = .default)))
if (length(nm) > 0) set_names(out, nm) else out
}
map2_dbl <- function(.x, .y, .f, ...) {
as.double(unlist(map2(.x, .y, .f, ..., .default = .default)))
}
map_int <- function(.x, .f, ..., .default) {
nm <- names(.x)
out <- as.integer(unlist(map(.x, .f, ..., .default = .default)))
if (length(nm) > 0) set_names(out, nm) else out
}
map2_int <- function(.x, .y, .f, ...) {
as.integer(unlist(map2(.x, .y, .f, ..., .default = .default)))
}
map_df <- function(.x, .f, ..., .id=NULL) {
res <- map(.x, .f, ...)
out <- bind_rows(res, .id=.id)
out
}
map_dfr <- map_df
map_dfc <- function(.x, .f, ...) {
res <- map(.x, .f, ...)
out <- bind_cols(res)
out
}
map2_df <- function(.x, .y, .f, ..., .id=NULL) {
res <- map2(.x, .y, .f, ...)
out <- bind_rows(res, .id = .id)
out
}
map2_dfc <- function(.x, .y, .f, ...) {
res <- map2(.x, .y, .f, ...)
out <- bind_cols(res)
out
}
# this has limitations and is more like 75% of dplyr::bind_rows()
# this is also orders of magnitude slower than dplyr::bind_rows()
bind_rows <- function(..., .id = NULL) {
res <- list(...)
if (length(res) == 1) res <- res[[1]]
cols <- unique(unlist(lapply(res, names), use.names = FALSE))
if (!is.null(.id)) {
inthere <- cols[.id %in% cols]
if (length(inthere) > 0) {
.id <- make.unique(c(inthere, .id))[2]
}
}
id_vals <- if (is.null(names(res))) 1:length(res) else names(res)
saf <- default.stringsAsFactors()
options(stringsAsFactors = FALSE)
on.exit(options(stringsAsFactors = saf))
idx <- 1
do.call(
rbind.data.frame,
lapply(res, function(.x) {
x_names <- names(.x)
moar_names <- setdiff(cols, x_names)
if (length(moar_names) > 0) {
for (i in 1:length(moar_names)) {
.x[[moar_names[i]]] <- rep(NA, length(.x[[1]]))
}
}
if (!is.null(.id)) {
.x[[.id]] <- id_vals[idx]
idx <<- idx + 1
}
.x
})
) -> out
rownames(out) <- NULL
class(out) <- c("tbl_df", "tbl", "data.frame")
out
}
bind_cols <- function(...) {
res <- list(...)
row_mismatch <- lapply(res, nrow) != nrow(res[[1]])
if (any(row_mismatch)) {
first_mismatch_pos <- which(row_mismatch)[1]
stop(paste0("Argument ", first_mismatch_pos,
" must be length ", nrow(res[[1]]),
", not ", nrow(res[[first_mismatch_pos]])))
}
if (length(res) == 1) res <- res[[1]]
col_names <- unlist(lapply(res, names), use.names = FALSE)
col_names <- make.unique(col_names, sep = "")
saf <- default.stringsAsFactors()
options(stringsAsFactors = FALSE)
on.exit(options(stringsAsFactors = saf))
out <- do.call(cbind.data.frame, res)
names(out) <- col_names
rownames(out) <- NULL
class(out) <- c("tbl_df", "tbl", "data.frame")
out
}
# set.seed(1)
# 1:10 %>%
# map(rnorm, n = 10) %>%
# map_dbl(mean)
#
# set.seed(1)
# 1:10 %>%
# purrr::map(rnorm, n = 10) %>%
# purrr::map_dbl(mean)
#
#
# # Or use an anonymous function
# set.seed(1)
# 1:10 %>%
# map(function(x) rnorm(10, x))
#
# set.seed(1)
# 1:10 %>%
# purrr::map(function(x) rnorm(10, x))
#
# # Or a formula
# set.seed(1)
# 1:10 %>%
# map(~ rnorm(10, .x))
#
# set.seed(1)
# 1:10 %>%
# purrr::map(~ rnorm(10, .x))
#
# # Extract by name or position
# # .default specifies value for elements that are missing or NULL
# l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
# l1 %>% map("a", .default = "???")
# l1 %>% purrr::map("a", .default = "???")
#
# l1 %>% map_int("b", .default = NA)
# l1 %>% purrr::map_int("b", .default = NA)
#
# l1 %>% map_int(2, .default = NA)
# l1 %>% purrr::map_int(2, .default = NA)
#
# # Supply multiple values to index deeply into a list
# l2 <- list(
# list(num = 1:3, letters[1:3]),
# list(num = 101:103, letters[4:6]),
# list()
# )
# l2 %>% map(c(2, 2))
# l2 %>% purrr::map(c(2, 2))
#
#
# # A more realistic example: split a data frame into pieces, fit a
# # model to each piece, summarise and extract R^2
# mtcars %>%
# split(.$cyl) %>%
# map(~ lm(mpg ~ wt, data = .x)) %>%
# map(summary) %>%
# map_dbl("r.squared")
#
# mtcars %>%
# split(.$cyl) %>%
# purrr::map(~ lm(mpg ~ wt, data = .x)) %>%
# purrr::map(summary) %>%
# purrr::map_dbl("r.squared")
#
#
# # Use map_lgl(), map_dbl(), etc to reduce to a vector.
# # * list
# mtcars %>% map(sum)
# mtcars %>% purrr::map(sum)
# # * vector
# mtcars %>% map_dbl(sum)
# mtcars %>% purrr::map_dbl(sum)
#
# # If each element of the output is a data frame, use
# # map_dfr to row-bind them together:
# mtcars %>%
# split(.$cyl) %>%
# map(~ lm(mpg ~ wt, data = .x)) %>%
# map_dfr(~ as.data.frame(t(as.matrix(coef(.)))))
#
# mtcars %>%
# split(.$cyl) %>%
# purrr::map(~ lm(mpg ~ wt, data = .x)) %>%
# purrr::map_dfr(~ as.data.frame(t(as.matrix(coef(.)))))

11
R/utils-pipe.R

@ -0,0 +1,11 @@
#' Pipe operator
#'
#' See \code{magrittr::\link[magrittr]{\%>\%}} for details.
#'
#' @name %>%
#' @rdname pipe
#' @keywords internal
#' @export
#' @importFrom magrittr %>%
#' @usage lhs \%>\% rhs
NULL

100
R/zdns-bulk-query.R

@ -0,0 +1,100 @@
#' Bulk query using zdns
#'
#' Given an entity list and an output file, `zdns` will be executed and
#' JSON output stored in `output_file` and an optional `log` file
#' (if specified).
#'
#' @md
#' @param entities a character vector of entities to resolve
#' @param input_file if not `NULL`, overrides `entities` and this file
#' will be used as the entities source. It *must* be a plain text
#' file with one entity to resovle per-line. `path.expand()` will
#' be run on this value.
#' @param query_type anything `zdns` supports. Presently, one of `A`, `AAAA`,
#' `ANY`, `AXFR`, `CAA`, `CNAME`, `DMARC`, `MX`, `NS`, `PTR`, `TXT`,
#' `SOA`, or `SPF` (can be lower-case). Default is `A`.
#' @param output_file path + file to the JSON output. `path.expand()` will be run
#' on this value.
#' @param num_nameservers total number of nameservers to use. They will be randomly
#' selected from the cached list of valid, public nameservers. It is _highly_
#' recommended that you refresh this list periodicaly (perhaps daily).
#' @param num_retries how many times should `zdns` retry query if timeout or
#' temporary failure? Defaults to `3`.
#' @param log if `TRUE` the JSON error log file will be automatically generated and
#' the location printed to the console. If a length 1 character vector, this
#' path + file will be used to save the JSON error log. If `FALSE` no error
#' log will be captured.
#' @param verbose a value between `1` and `5` indicating the verbosity level. Defaults
#' to `3`. Set this to `1` if you're working inside RStudio or other
#' environments that can't handle a great deal of console text since
#' the messages are placed on `stdout` when `log` equals `FALSE`.
#' @return value from the `system2()` call to `zdns` (invisibly)
#' @note if you specified `TRUE` for `log` then _you_ are responsible for
#' removing the auto-generated log file.
#' @export
zdns_query <- function(entities, input_file = NULL, query_type = "A", output_file,
num_nameservers = 3000L, num_retries = 3,
log = TRUE, verbose = 3) {
# setup entities to lookup
if (!is.null(input_file)) {
input_file <- path.expand(input_file)
if (!file.exists(input_file)) stop("input file not found", call.=FALSE)
} else {
tf <- tempfile(fileext=".txt")
on.exit(unlink(tf), add=TRUE)
writeLines(entities, tf)
input_file <- tf
}
# make sure query type is legit
match.arg(
toupper(query_type),
c(
"A", "AAAA", "ANY", "AXFR", "CAA", "CNAME", "DMARC",
"MX", "NS", "PTR", "TXT", "SOA", "SPF"
)
) -> query_type
# prep nameservers list
ns_df <- readRDS(file.path(path.expand("~/.zdnsr"), "public-nameservers.rds"))
ns_df <- ns_df[ns_df$reliability>0.75,]
ns_file <- tempfile(pattern = "resolvers", fileext = ".txt")
writeLines(sprintf("nameserver %s", ns_df[sample(nrow(ns_df), num_nameservers),]$ip), ns_file)
on.exit(unlink(ns_file), add=TRUE)
# setup logging (if any)
logging <- FALSE
if (inherits(log, "character")) {
log_file <- log
logging <- TRUE
} else {
if (inherits(log, "logical")) {
if (log) {
log_file <- tempfile("zmap-error", fileext=".json")
logging <- TRUE
message("zmap error log will be stored in ", log_file)
} else {
message("Not logging errors.")
}
} else {
message("Not logging errors.")
}
}
# prep args for call to zdns
zdns_args <- c(
query_type,
"-input-file", input_file,
"-conf-file", ns_file,
"-output-file", output_file,
"-retries", num_retries,
"-verbosity", verbose
)
if (logging) zdns_args <- c(zdns_args, "-log-file", log_file)
invisible(zdns_exec(zdns_args))
}

23
R/zdns-exec.R

@ -0,0 +1,23 @@
#' Raw interface to zdns
#'
#' Pass in command-line arguments via `args`. Not a recommended function
#' unless you _really_ know what you're doing. Run `zdns_help()`
#' to see a list of options.
#'
#' @md
#' @export
zdns_exec <- function(args=c(), stdout="", stdin="") {
zdns_bin <- Sys.which("zdns")
res <- system2(zdns_bin, args=args, stdout=stdout, stdin=stdin)
invisible(res)
}
#' @rdname zdns_exec
#' @export
zdns_help <- function(x) {
zdns_exec("--help")
}

14
R/zdnsr-package.R

@ -1,12 +1,18 @@
#' ...
#'
#' Perform Bulk 'DNS' Queries Using 'zdns'
#'
#' Provides wrapper/helper methods for executing 'zdns'
#' (<https://github.com/zmap/zdns>) bulk queries along with utility methods to
#' retrieve and cache 'Public DNS' (<http://public-dns.info/>) nameserver lists.
#'
#' - `zdns`: <https://github.com/zmap/zdns>
#' - `Public DNS Lists`: <http://public-dns.info/>
#'
#' - URL: <https://gitlab.com/hrbrmstr/zdnsr>
#' - BugReports: <https://gitlab.com/hrbrmstr/zdnsr/issues>
#'
#'
#' @md
#' @name zdnsr
#' @docType package
#' @author Bob Rudis (bob@@rud.is)
#' @import httr
#' @importFrom jsonlite fromJSON
NULL

26
R/zzz.R

@ -0,0 +1,26 @@
.onLoad <- function(libname, pkgname) {
if (!dir.exists(path.expand("~/.zdnsr"))) {
message("Bootstrapping public nameservers list...")
refresh_publc_nameservers_list()
}
res <- Sys.which("go")
if (res == "") {
packageStartupMessage(
"Go (golang) not found. Please install Go (https://golang.org/dl/) for ",
"your platform and try reloading the package again."
)
} else {
res <- Sys.which("zdns")
if (res == "") {
packageStartupMessage(
"zdns not found. Please go to https://github.com/zmap/zdns to find ",
"installation instructions or try running install_zdns()."
)
}
}
}

13
README.Rmd

@ -4,12 +4,25 @@ output: rmarkdown::github_document
# zdnsr
Perform Bulk 'DNS' Queries Using 'zdns'
## Description
Provides wrapper/helper methods for executing 'zdns' (<https://github.com/zmap/zdns>) bulk queries along with utility methods to retrieve and cache 'Public DNS' (<http://public-dns.info/>) nameserver lists.
- `zdns`: <https://github.com/zmap/zdns>
- `Public DNS Lists`: <http://public-dns.info/>
## What's Inside The Tin
The following functions are implemented:
- `install_zdns`: Helper to try to get `zdns` installed
- `refresh_publc_nameservers_list`: Refresh the list of valid public nameservers
- `zdns_exec`: Raw interface to `zdns`
- `zdns_help`: Raw interface to `zdns`
- `zdns_query`: Bulk query using `zdns`
## Installation
```{r eval=FALSE}

40
README.md

@ -1,2 +1,42 @@
# zdnsr
Perform Bulk ‘DNS’ Queries Using ‘zdns’
## Description
Provides wrapper/helper methods for executing ‘zdns’
(<https://github.com/zmap/zdns>) bulk queries along with utility methods
to retrieve and cache ‘Public DNS’ (<http://public-dns.info/>)
nameserver lists.
- `zdns`: <https://github.com/zmap/zdns>
- `Public DNS Lists`: <http://public-dns.info/>
## What’s Inside The Tin
The following functions are implemented:
- `install_zdns`: Helper to try to get `zdns` installed
- `refresh_publc_nameservers_list`: Refresh the list of valid public
nameservers
- `zdns_exec`: Raw interface to `zdns`
- `zdns_help`: Raw interface to `zdns`
- `zdns_query`: Bulk query using `zdns`
## Installation
``` r
devtools::install_github("hrbrmstr/zdnsr")
```
## Usage
``` r
library(zdnsr)
# current verison
packageVersion("zdnsr")
```
## [1] '0.1.0'

11
man/install_zdns.Rd

@ -0,0 +1,11 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/install-zdns.R
\name{install_zdns}
\alias{install_zdns}
\title{Helper to try to get zdns installed}
\usage{
install_zdns()
}
\description{
Helper to try to get zdns installed
}

12
man/pipe.Rd

@ -0,0 +1,12 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils-pipe.R
\name{\%>\%}
\alias{\%>\%}
\title{Pipe operator}
\usage{
lhs \%>\% rhs
}
\description{
See \code{magrittr::\link[magrittr]{\%>\%}} for details.
}
\keyword{internal}

11
man/refresh_publc_nameservers_list.Rd

@ -0,0 +1,11 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/ns-refresh.R
\name{refresh_publc_nameservers_list}
\alias{refresh_publc_nameservers_list}
\title{Refresh the list of valid public nameservers}
\usage{
refresh_publc_nameservers_list()
}
\description{
Refresh the list of valid public nameservers
}

16
man/zdns_exec.Rd

@ -0,0 +1,16 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/zdns-exec.R
\name{zdns_exec}
\alias{zdns_exec}
\alias{zdns_help}
\title{Raw interface to zdns}
\usage{
zdns_exec(args = c(), stdout = "", stdin = "")
zdns_help(x)
}
\description{
Pass in command-line arguments via \code{args}. Not a recommended function
unless you \emph{really} know what you're doing. Run \code{zdns_help()}
to see a list of options.
}

53
man/zdns_query.Rd

@ -0,0 +1,53 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/zdns-bulk-query.R
\name{zdns_query}
\alias{zdns_query}
\title{Bulk query using zdns}
\usage{
zdns_query(entities, input_file = NULL, query_type = "A", output_file,
num_nameservers = 3000L, num_retries = 3, log = TRUE, verbose = 3)
}
\arguments{
\item{entities}{a character vector of entities to resolve}
\item{input_file}{if not \code{NULL}, overrides \code{entities} and this file
will be used as the entities source. It \emph{must} be a plain text
file with one entity to resovle per-line. \code{path.expand()} will
be run on this value.}
\item{query_type}{anything \code{zdns} supports. Presently, one of \code{A}, \code{AAAA},
\code{ANY}, \code{AXFR}, \code{CAA}, \code{CNAME}, \code{DMARC}, \code{MX}, \code{NS}, \code{PTR}, \code{TXT},
\code{SOA}, or \code{SPF} (can be lower-case). Default is \code{A}.}
\item{output_file}{path + file to the JSON output. \code{path.expand()} will be run
on this value.}
\item{num_nameservers}{total number of nameservers to use. They will be randomly
selected from the cached list of valid, public nameservers. It is \emph{highly}
recommended that you refresh this list periodicaly (perhaps daily).}
\item{num_retries}{how many times should \code{zdns} retry query if timeout or
temporary failure? Defaults to \code{3}.}
\item{log}{if \code{TRUE} the JSON error log file will be automatically generated and
the location printed to the console. If a length 1 character vector, this
path + file will be used to save the JSON error log. If \code{FALSE} no error
log will be captured.}
\item{verbose}{a value between \code{1} and \code{5} indicating the verbosity level. Defaults
to \code{3}. Set this to \code{1} if you're working inside RStudio or other
environments that can't handle a great deal of console text since
the messages are placed on \code{stdout} when \code{log} equals \code{FALSE}.}
}
\value{
value from the \code{system2()} call to \code{zdns} (invisibly)
}
\description{
Given an entity list and an output file, \code{zdns} will be executed and
JSON output stored in \code{output_file} and an optional \code{log} file
(if specified).
}
\note{
if you specified \code{TRUE} for \code{log} then \emph{you} are responsible for
removing the auto-generated log file.
}

9
man/zdnsr.Rd

@ -4,9 +4,16 @@
\name{zdnsr}
\alias{zdnsr}
\alias{zdnsr-package}
\title{...}
\title{Perform Bulk 'DNS' Queries Using 'zdns'}
\description{
Provides wrapper/helper methods for executing 'zdns'
(\url{https://github.com/zmap/zdns}) bulk queries along with utility methods to
retrieve and cache 'Public DNS' (\url{http://public-dns.info/}) nameserver lists.
}
\details{
\itemize{
\item \code{zdns}: \url{https://github.com/zmap/zdns}
\item \code{Public DNS Lists}: \url{http://public-dns.info/}
\item URL: \url{https://gitlab.com/hrbrmstr/zdnsr}
\item BugReports: \url{https://gitlab.com/hrbrmstr/zdnsr/issues}
}

Loading…
Cancel
Save