~hrbrmstr/playdoh

ref: cda06176bb2626c26f9e20881df13246d1c51818 playdoh/R/doh-post.R -rw-r--r-- 1.6 KiB
cda06176boB Rudis add RFC 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#' Make a POST DoH Request (wireformat)
#'
#' Issue the query of type `type` for `name` to the DoH endpoint specified at `server_path`.
#'
#' @param name name to query for
#' @param type DNS query type (defaults to "`A`")
#' @param server_path full URL path to the DoH server quer endpoint (defaults to Quad9).
#' @return `NULL` (if the query failed) or a `data.frame` (tibble)
#' @references <https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-05.html>
#' @export
doh_post <- function(name, type = "A", server_path = "https://dns.quad9.net/dns-query") {

  # for now, use python's {dnslib} as a crutch to
  # encode/decode wireformat DNS questions and answers

  .dns$DNSRecord$question(
    qname = tolower(name[1]),
    qtype = toupper(type[1]),
    qclass = "IN"
  ) -> q

  qpak <- q$pack()

  # now, send it off to the server

  httr::POST(
    url = server_path[1],
    httr::add_headers(
      `Content-Type` = "application/dns-message",
      `Accept` = "application/dns-message"
    ),
    encode = "raw",
    body = qpak
  ) -> res

  httr::warn_for_status(res)

  # if the response is OK, make it a data frame

  if (httr::status_code(res) == 200) {

    r <- .dns$DNSRecord$parse(httr::content(res))

    q <- r$get_q()

    do.call(
      rbind.data.frame,
      lapply(r$rr, function(.x) {
        data.frame(
          query = py_str(q$qname),
          qtype = q$qtype,
          rname = py_str(.x$rname),
          rtype = .x$rtype,
          rdata = py_str(.x$rdata),
          ttl = .x$ttl,
          stringsAsFactors = FALSE
        )
      })

    ) -> xdf

    class(xdf) <- c("tbl_df", "tbl", "data.frame")

    xdf

  } else {
    NULL
  }

}