Selaa lähdekoodia

DoH POST support

boB Rudis 5 kuukautta sitten
vanhempi
commit
a114a9a6fa
No known key found for this signature in database

+ 6
- 5
DESCRIPTION Näytä tiedosto

@@ -1,15 +1,14 @@
1 1
 Package: clandnstine
2 2
 Type: Package
3 3
 Title: Perform Secure-by-default 'DNS' Queries
4
-Version: 0.1.0
5
-Date: 2019-01-18
4
+Version: 0.2.0
5
+Date: 2019-05-26
6 6
 Authors@R: c(
7 7
     person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"), 
8 8
            comment = c(ORCID = "0000-0001-5670-2640"))
9 9
   )
10 10
 Maintainer: Bob Rudis <bob@rud.is>
11
-Description: Something something 'DNS. Something something 'TLS'. 
12
-    Something something 'getdns API/library'.
11
+Description: Perform and process 'DNS over TLS' and 'DNS over HTTPS' queries.
13 12
 SystemRequirements: C++11; libgetdns v1.5.1 or higher
14 13
 URL: https://gitlab.com/hrbrmstr/clandnstine
15 14
 BugReports: https://gitlab.com/hrbrmstr/clandnstine/issues
@@ -24,7 +23,9 @@ Imports:
24 23
     jsonlite,
25 24
     Rcpp,
26 25
     magrittr,
27
-    glue
26
+    glue,
27
+    httr,
28
+    R6
28 29
 Roxygen: list(markdown = TRUE)
29 30
 RoxygenNote: 6.1.1
30 31
 LinkingTo: 

+ 4
- 0
NAMESPACE Näytä tiedosto

@@ -3,6 +3,8 @@
3 3
 S3method(print,gctx)
4 4
 S3method(print,gdns_response)
5 5
 export("%>%")
6
+export(doh_post)
7
+export(doh_servers)
6 8
 export(gdns_context)
7 9
 export(gdns_get_address)
8 10
 export(gdns_get_hosts)
@@ -24,6 +26,8 @@ export(gdns_set_tls_ca_path)
24 26
 export(gdns_set_transports)
25 27
 export(gdns_update_resolvers)
26 28
 export(is_gctx)
29
+import(R6)
30
+import(httr)
27 31
 importFrom(Rcpp,sourceCpp)
28 32
 importFrom(glue,glue_data)
29 33
 importFrom(jsonlite,fromJSON)

+ 83
- 0
R/DNSHeader-class.R Näytä tiedosto

@@ -0,0 +1,83 @@
1
+R6Class(
2
+
3
+  classname = "DNSHeader",
4
+
5
+  public = list(
6
+
7
+    q = NULL,
8
+    a = NULL,
9
+    id = NULL,
10
+    auth = NULL,
11
+    bitmap = 0L,
12
+    qr = NULL,
13
+    opcode = NULL,
14
+    aa = NULL,
15
+    tc = NULL,
16
+    rd = NULL,
17
+    ra = NULL,
18
+    z = NULL,
19
+    ad = NULL,
20
+    ar = NULL,
21
+    cd = NULL,
22
+    rcode = NULL,
23
+
24
+    set_rd = function(val) {
25
+
26
+      bits(self$bitmap, 8) <- as.integer(val)
27
+
28
+    },
29
+
30
+    initialize = function(id = NULL, bitmap = NULL, q = 0L,
31
+                          a = 0L, auth = 0L, ar = 0L, ...) {
32
+
33
+      self$id <- id %||% sample(0:65535, 1)
34
+
35
+      self$bitmap <- bitmap %||% 0L
36
+      if (is.null(bitmap)) self$set_rd(1L)
37
+
38
+      self$q <- q
39
+      self$a <- a
40
+      self$auth <- auth
41
+      self$ar <- ar
42
+
43
+      valid <- c("qr", "opcode", "aa", "tc", "rd", "ra", "z", "ad", "cd", "rcode")
44
+
45
+      args <- list(...)
46
+      args <- setNames(args, tolower(colnames(args)))
47
+      args <- Filter(Negate(is.null), args[valid])
48
+
49
+      for (n in names(args)) self[[n]] <- args[[n]]
50
+
51
+    },
52
+
53
+    parse = function(buf, buf_pos = 1L) {
54
+
55
+      self$id <- readBin(buf[buf_pos:(buf_pos+1)], "int", size = 2, endian = "big")
56
+      self$bitmap <- readBin(buf[(buf_pos+2):(buf_pos+3)], "int", size = 2, endian = "big")
57
+      self$q <- readBin(buf[(buf_pos+4):(buf_pos+5)], "int", size = 2, endian = "big")
58
+      self$a <- readBin(buf[(buf_pos+6):(buf_pos+7)], "int", size = 2, endian = "big")
59
+      self$auth <- readBin(buf[(buf_pos+8):(buf_pos+9)], "int", size = 2, endian = "big")
60
+      self$ar <- readBin(buf[(buf_pos+10):(buf_pos+11)], "int", size = 2, endian = "big")
61
+
62
+      attr(self, "buflen") <- 12L
63
+
64
+      self
65
+
66
+    },
67
+
68
+    pack = function() {
69
+
70
+      c(
71
+        writeBin(as.integer(self$id), raw(), size = 2, endian = "big"),
72
+        writeBin(as.integer(self$bitmap), raw(), size = 2, endian = "big"),
73
+        writeBin(as.integer(self$q), raw(), size = 2, endian = "big"),
74
+        writeBin(as.integer(self$a), raw(), size = 2, endian = "big"),
75
+        writeBin(as.integer(self$auth), raw(), size = 2, endian = "big"),
76
+        writeBin(as.integer(self$ar), raw(), size = 2, endian = "big")
77
+      )
78
+
79
+    }
80
+
81
+  )
82
+
83
+) -> DNSHeader

+ 43
- 0
R/DNSLabel-class.R Näytä tiedosto

@@ -0,0 +1,43 @@
1
+R6Class(
2
+
3
+  classname = "DNSLabel",
4
+
5
+  public = list(
6
+
7
+    label = NULL,
8
+
9
+    initialize = function(label) {
10
+
11
+      if (inherits(label, "DNSLabel")) {
12
+
13
+        self$label <- label$label
14
+
15
+      } else if (length(label) > 1) {
16
+
17
+        self$label <- as.character(label)
18
+
19
+      } else if (is.character(label)) {
20
+        label <- sub("\\.$", "", label)
21
+        self$label <- unlist(strsplit(label, "\\."), use.names = FALSE)
22
+      }
23
+
24
+    },
25
+
26
+    encode = function() {
27
+
28
+      sz <- nchar(self$label)
29
+      out <- raw()
30
+      for (i in seq_along(self$label)) {
31
+        out <- c(out, as.raw(sz[[i]]), charToRaw(self$label[[i]]))
32
+      }
33
+      c(out, as.raw(0x00))
34
+
35
+    },
36
+
37
+    parse = function(buf, buf_pos) {
38
+
39
+    }
40
+
41
+  )
42
+
43
+) -> DNSLabel

+ 51
- 0
R/DNSQuestion-class.R Näytä tiedosto

@@ -0,0 +1,51 @@
1
+R6Class(
2
+
3
+  classname = "DNSQuestion",
4
+
5
+  public = list(
6
+
7
+    qname = NULL,
8
+    qtype = NULL,
9
+    qclass = NULL,
10
+
11
+    initialize = function(qname = NULL, qtype = 1L, qclass = 1L) {
12
+
13
+      if (inherits(qname, "DNSLabel")) {
14
+        self$qname <- qname
15
+      } else {
16
+        if (length(qname)) self$qname <- DNSLabel$new(qname)
17
+      }
18
+
19
+      self$qtype <- qtype
20
+      self$qclass <- qclass
21
+
22
+    },
23
+
24
+    pack = function() {
25
+      c(
26
+        self$qname$encode(),
27
+        writeBin(as.integer(self$qtype), raw(), size = 2, endian = "big"),
28
+        writeBin(as.integer(self$qclass), raw(), size = 2, endian = "big")
29
+      )
30
+    },
31
+
32
+    parse = function(buf, buf_pos = 1L) {
33
+
34
+      ret <- DNSLabel$new()$parse(buf, buf_pos)
35
+
36
+      self$qname <- ret
37
+
38
+      buf_pos <- buf_pos + attr(ret, "buflen")
39
+
40
+      self$qtype <- readBin(buf[buf_pos:(buf_pos+1)], "int", size = 2, endian = "big")
41
+      self$qclass <- readBin(buf[(buf_pos+2):(buf_pos+3)], "int", size = 2, endian = "big")
42
+
43
+      attr(self, "buflen") <- attr(ret, "buflen") + 4L
44
+
45
+      self
46
+
47
+    }
48
+
49
+  )
50
+
51
+) -> DNSQuestion

+ 90
- 0
R/DNSRecord-class.R Näytä tiedosto

@@ -0,0 +1,90 @@
1
+R6Class(
2
+
3
+  classname = "DNSRecord",
4
+
5
+  public = list(
6
+
7
+    header = NULL,
8
+    questions = list(),
9
+    rr = list(),
10
+    auth = list(),
11
+    ar = list(),
12
+
13
+    initialize = function(header = NULL, questions = NULL,
14
+                          rr = NULL, q = NULL, a = NULL,
15
+                          auth = NULL, ar = NULL) {
16
+
17
+      self$header <- header %||% DNSHeader$new()
18
+      self$questions <- questions %||% list()
19
+      self$rr <- rr %||% list()
20
+      self$auth <- auth %||% list()
21
+      self$ar <- ar %||% list()
22
+
23
+      if (length(q)) self$questions <- append(self$questions, q)
24
+      if (length(a)) self$rr <- append(self$rr, a)
25
+
26
+      self$set_header_qa()
27
+
28
+    },
29
+
30
+    question = function(qname, qtype = "A", qclass = "IN") {
31
+      DNSRecord$new(
32
+        q = DNSQuestion$new(
33
+          qname = qname,
34
+          qtype = .qtype[toupper(qtype)],
35
+          qclass = .class[toupper(qclass)]
36
+        )
37
+      )
38
+    },
39
+
40
+    parse = function(buf, buf_pos = 1L) {
41
+
42
+      #self$header <- NULL
43
+      self$questions <- list()
44
+      self$rr <- list()
45
+      self$auth <- list()
46
+      self$ar <- list()
47
+
48
+      buf_pos <- 1L
49
+
50
+      ret <- DNSHeader$new()$parse(buf)
51
+
52
+      self$header <- ret
53
+
54
+      buf_pos <- attr(ret, "buflen") + 1L
55
+
56
+      message(buf_pos)
57
+
58
+      self$questions <- lapply(1:self$header$q, function(.idx) {
59
+
60
+        ret <- DNSQuestion$new()$parse(buf, buf_pos)
61
+        buf_pos <<- buf_pos + attr(ret, "buflen")
62
+        ret
63
+
64
+      })
65
+
66
+      self
67
+
68
+    },
69
+
70
+    # Reset header q/a/auth/ar counts to match numver of records (normally done transparently)
71
+
72
+    set_header_qa = function() {
73
+      self$header$q <- length(self$questions)
74
+      self$header$a <- length(self$rr)
75
+      self$header$auth <- length(self$auth)
76
+      self$header$ar <- length(self$ar)
77
+    },
78
+
79
+    pack = function() {
80
+      out <- self$header$pack()
81
+      for (q in self$questions) out <- c(out, q$pack())
82
+      out
83
+    }
84
+
85
+  ),
86
+
87
+  private = list(
88
+  )
89
+
90
+) -> DNSRecord

+ 4
- 0
R/RcppExports.R Näytä tiedosto

@@ -137,6 +137,10 @@ int_gdns_get_root_servers <- function(gctx) {
137 137
     .Call(`_clandnstine_int_gdns_get_root_servers`, gctx)
138 138
 }
139 139
 
140
+int_dns_wire_to_list <- function(buf) {
141
+    .Call(`_clandnstine_int_dns_wire_to_list`, buf)
142
+}
143
+
140 144
 #' Test whether an object is an external pointer
141 145
 #'
142 146
 #' @param x object to test

+ 2
- 1
R/clandnstine-package.R Näytä tiedosto

@@ -1,4 +1,4 @@
1
-#' Perform Secure-by-default 'DNS' Queries
1
+#' Perform Secure-by-Default 'DNS' Queries
2 2
 #'
3 3
 #' Something something 'DNS. Something something 'TLS'.
4 4
 #' Something something 'getdns API/library'.
@@ -11,6 +11,7 @@
11 11
 #' @docType package
12 12
 #' @author Bob Rudis (bob@@rud.is)
13 13
 #' @keywords internal
14
+#' @import httr R6
14 15
 #' @importFrom glue glue_data
15 16
 #' @importFrom jsonlite fromJSON
16 17
 #' @useDynLib clandnstine, .registration = TRUE

+ 46
- 0
R/doh-query.R Näytä tiedosto

@@ -0,0 +1,46 @@
1
+#' Make a DoH Request (POST/wireformat)
2
+#'
3
+#' Issue a `POST` wireformat query of type `type` for `name` to
4
+#' the DoH endpoint specified at `server_path`.
5
+#'
6
+#' @param name name to query for
7
+#' @param type DNS query type (defaults to "`A`")
8
+#' @param server_path full URL path to the DoH server quer endpoint (defaults to Quad9).
9
+#' @return `NULL` (if the query failed) or a `data.frame` (tibble)
10
+#' @references <https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-05.html>
11
+#' @export
12
+#' @examples
13
+#' doh_post("rud.is", "A")
14
+doh_post <- function(name, type = "A", server_path = "https://dns.quad9.net/dns-query") {
15
+
16
+  DNSRecord$new()$question(
17
+    qname = tolower(name[1]),
18
+    qtype = toupper(type[1]),
19
+    qclass = "IN"
20
+  ) -> q
21
+
22
+  # now, send it off to the server
23
+
24
+  httr::POST(
25
+    url = server_path[1],
26
+    httr::add_headers(
27
+      `Content-Type` = "application/dns-message",
28
+      `Accept` = "application/dns-message"
29
+    ),
30
+    encode = "raw",
31
+    body = q$pack()
32
+  ) -> res
33
+
34
+  httr::stop_for_status(res)
35
+
36
+  res <- int_dns_wire_to_list(httr::content(res, as = "raw"))
37
+
38
+  if (length(res)) {
39
+    out <- jsonlite::fromJSON(res)
40
+    # class(out) <- c("gdns_response", "list")
41
+    out
42
+  } else {
43
+    NULL
44
+  }
45
+
46
+}

+ 118
- 0
R/globals.R Näytä tiedosto

@@ -0,0 +1,118 @@
1
+c(
2
+  'A' = 1L, 'NS' = 2L, 'CNAME' = 5L, 'SOA' = 6L, 'PTR' = 12L, 'HINFO' = 13L,
3
+  'MX' = 15L, 'TXT' = 16L, 'RP' = 17L, 'AFSDB' = 18L, 'SIG' = 24L,
4
+  'KEY' = 25L, 'AAAA' = 28L, 'LOC' = 29, 'SRV' = 33L, 'NAPTR' = 35L,
5
+  'KX' = 36L, 'CERT' = 37L, 'A6' = 38L, 'DNAME' = 39L, 'OPT' = 41,
6
+  'APL' = 42L, 'DS' = 43L, 'SSHFP' = 44L, 'IPSECKEY' = 45L, 'RRSIG' = 46L,
7
+  'NSEC' = 47L, 'DNSKEY' = 48L, 'DHCID' = 49L, 'NSEC3' = 50L,
8
+  'NSEC3PARAM' = 51L, 'TLSA' = 52L, 'HIP' = 55L, 'CDS' = 59L,
9
+  'CDNSKEY' = 60L, 'OPENPGPKEY' = 61L, 'SPF' = 99L, 'TKEY' = 249L,
10
+  'TSIG' = 250L, 'IXFR' = 251L, 'AXFR' = 252L, 'ANY' = 255L,
11
+  'URI' = 256L, 'CAA' = 257L, 'TA' = 32768L, 'DLV' = 32769L
12
+) -> .qtype
13
+
14
+c(
15
+  'IN' = 1L,
16
+  'CS' = 2L,
17
+  'CH' = 3L,
18
+  'Hesiod' = 4L,
19
+  'None' = 254L,
20
+  '*' = 255L
21
+) -> .class
22
+
23
+.qr <- c('QUERY' = 0, 'RESPONSE' = 1)
24
+
25
+c(
26
+  'NOERROR' = 0L,
27
+  'FORMERR' = 1L,
28
+  'SERVFAIL' = 2L,
29
+  'NXDOMAIN' = 3L,
30
+  'NOTIMP' = 4L,
31
+  'REFUSED' = 5L,
32
+  'YXDOMAIN' = 6L,
33
+  'YXRRSET' = 7L,
34
+  'NXRRSET' = 8L,
35
+  'NOTAUTH' = 9L,
36
+  'NOTZONE' = 10L
37
+) -> .rcode
38
+
39
+c(
40
+  'QUERY' = 0L,
41
+  'IQUERY' = 1L,
42
+  'STATUS' = 2L,
43
+  'UPDATE' = 5L
44
+) -> .opcode
45
+
46
+#' Built-in list of DoH Servers
47
+#'
48
+#' The `url` element has the URL for `GET`/`POST` requests and
49
+#' the `extra_params` element has any needed query parameters
50
+#' for `GET` requests.
51
+#'
52
+#' The list so far.
53
+#' - `google`: <https://dns.google.com/experimental>
54
+#' - `cloudflare`: <https://cloudflare-dns.com/dns-query>
55
+#' - `quad9`: <https://dns.quad9.net/dns-query>
56
+#' - `securedns_eu`: <https://doh.securedns.eu/dns-query>
57
+#' - `dnswarden_adblock`: <https://doh.dnswarden.com/adblock>
58
+#' - `dnswarden_uncensored`: <https://doh.dnswarden.com/uncensored>
59
+#' - `cleanbrowsing_security`: <https://doh.cleanbrowsing.org/doh/security-filter/>
60
+#' - `cleanbrowsing_family`: <https://doh.cleanbrowsing.org/doh/family-filter/>
61
+#' - `cleanbrowsing_adult`: <https://doh.cleanbrowsing.org/doh/adult-filter/>
62
+#' - `power_dns`: <https://doh.powerdns.org>
63
+#' - `appliedprivacy`: <https://doh.appliedprivacy.net/query>
64
+#'
65
+#' @docType data
66
+#' @export
67
+list(
68
+  google = list(
69
+    url = "https://dns.google.com/experimental",
70
+    extra_params = list()
71
+  ),
72
+  cloudflare = list(
73
+    url = "https://cloudflare-dns.com/dns-query",
74
+    extra_params = list(
75
+      cd = "false",
76
+      do = "true",
77
+      ct = "application/dns-json"
78
+    )
79
+  ),
80
+  quad9 = list(
81
+    url = "https://dns.quad9.net/dns-query",
82
+    extra_params = list()
83
+  ),
84
+  securedns_eu = list(
85
+    url = "https://doh.securedns.eu/dns-query",
86
+    extra_params = list(
87
+      edns_client_subnet = NULL
88
+    )
89
+  ),
90
+  dnswarden_adblock = list(
91
+    url = "https://doh.dnswarden.com/adblock",
92
+    extra_params = list()
93
+  ),
94
+  dnswarden_uncensored = list(
95
+    url = "https://doh.dnswarden.com/uncensored",
96
+    extra_params = list()
97
+  ),
98
+  cleanbrowsing_security = list(
99
+    url = "https://doh.cleanbrowsing.org/doh/security-filter/",
100
+    extra_params = list(cd = "false")
101
+  ),
102
+  cleanbrowsing_family = list(
103
+    url = "https://doh.cleanbrowsing.org/doh/family-filter/",
104
+    extra_params = list()
105
+  ),
106
+  cleanbrowsing_adult = list(
107
+    url = "https://doh.cleanbrowsing.org/doh/adult-filter/",
108
+    extra_params = list()
109
+  ),
110
+  power_dns = list(
111
+    url = "https://doh.powerdns.org",
112
+    extra_params = list()
113
+  ),
114
+  appliedprivacy = list(
115
+    url = "https://doh.appliedprivacy.net/query",
116
+    extra_params = list()
117
+  )
118
+) -> doh_servers

+ 4
- 0
R/utils-infix-helpers.R Näytä tiedosto

@@ -0,0 +1,4 @@
1
+`%l0%` <- function(x, y) if (length(x) == 0) y else x
2
+`%||%` <- function(x, y) if (is.null(x)) y else x
3
+`%@%` <- function(x, name) attr(x, name, exact = TRUE)
4
+`%nin%` <- function(x, table)  match(x, table, nomatch = 0) == 0

+ 9
- 0
R/utils.R Näytä tiedosto

@@ -0,0 +1,9 @@
1
+"bits" <- function(object, bit) {
2
+  (object %/% (2^bit)) %% 2
3
+}
4
+
5
+"bits<-" <- function(object, bit, value) {
6
+  mask <- 2^bit
7
+  object <- object+(value - ((object %/% mask) %% 2))*mask
8
+  object
9
+}

+ 21
- 6
README.Rmd Näytä tiedosto

@@ -18,7 +18,7 @@ Perform Secure-by-default 'DNS' Queries
18 18
 
19 19
 ## Description
20 20
 
21
-Something something 'DNS. Something something 'TLS'.  Something something 'getdns API/library'.
21
+Perform and process 'DNS over TLS' and 'DNS over HTTPS' queries.
22 22
 
23 23
 ## NOTE
24 24
 
@@ -35,15 +35,15 @@ I've gotten this running on macOS and Ubuntu 16.04. For the latter I had to ensu
35 35
 
36 36
 ## TODO/WAT
37 37
 
38
-I finally grok the getdns api so the package api is going to change wildly and fast. The default mode will be to perform queries using DNS over TLS but also supports UDP and TCP transports.
38
+I finally grok the getdns api so the package api is going to change wildly and fast. The default mode will be to perform queries using DNS over TLS but also supports UDP and TCP transports along with support for DNS over HTTPS.
39 39
 
40 40
 ## Why?
41 41
 
42
-Well, for starters, to help research DNS over TLS servers. Plus, for fun!
42
+Well, for starters, to help research DNS over TLS/DNS over HTTPS servers. Plus, for fun!
43 43
 
44
-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).
44
+If you're asking "Why DNS over TLS/HTTPS 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).
45 45
 
46
-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.
46
+Also "faux" in that you're going to be using (for DoT) 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.
47 47
 
48 48
 ## What's Different About This vs Regular DNS?
49 49
 
@@ -85,6 +85,13 @@ It's stupid slow, consumes more CPU and bandwidth but forces adversaries to work
85 85
 
86 86
 The following functions are implemented:
87 87
 
88
+### DNS over HTTPS
89
+
90
+- `doh_post`: Make a DoH Request (POST/wireformat)
91
+- `doh_servers`: Built-in list of DoH servers.
92
+
93
+### DNS over TLS
94
+
88 95
 - `gdns_context`:  Create a gdns DNS over TLS context and populate it with a resolver for use in resolution functions
89 96
 - `gdns_get_address`:  Resolve a host to an addrss
90 97
 - `gdns_get_resolution_type`:	Get the current resolution type setting
@@ -106,7 +113,9 @@ The following functions are implemented:
106 113
 ## Installation
107 114
 
108 115
 ```{r install-ex, eval=FALSE}
109
-devtools::install_git("https://gitlab.com/hrbrmstr/clandnstine.git")
116
+devtools::install_git("https://git.sr.ht/~hrbrmstr/clandnstine")
117
+# or 
118
+devtools::install_gitlab("hrbrmstr/clandnstine.git")
110 119
 # or
111 120
 devtools::install_github("hrbrmstr/clandnstine")
112 121
 ```
@@ -155,6 +164,12 @@ sort(unlist(leno$replies_tree$answer[[1]]$rdata$txt_strings))
155 164
 
156 165
 Yep. Advertising even in DNS `TXT` records (see item number 8).
157 166
 
167
+### DOH
168
+
169
+```{r doh}
170
+str(doh_post("rud.is")$answer)
171
+```
172
+
158 173
 ## clandnstine Metrics
159 174
 
160 175
 ```{r cloc, echo=FALSE}

+ 57
- 34
README.md Näytä tiedosto

@@ -11,8 +11,7 @@ Perform Secure-by-default ‘DNS’ Queries
11 11
 
12 12
 ## Description
13 13
 
14
-Something something ‘DNS. Something something ’TLS’. Something something
15
-‘getdns API/library’.
14
+Perform and process ‘DNS over TLS’ and ‘DNS over HTTPS’ queries.
16 15
 
17 16
 ## NOTE
18 17
 
@@ -29,7 +28,7 @@ install.
29 28
 
30 29
 I’ve gotten this running on macOS and Ubuntu 16.04. For the latter I had
31 30
 to ensure `libidn2-0-dev` and `libunbound-dev` were installed then had
32
-to grab the 1.5.1 tarball (e.g. `aria2c
31
+to grab the 1.5.1 tarball (e.g. `aria2c
33 32
 https://getdnsapi.net/releases/getdns-1-5-1/getdns-1.5.1.tar.gz`),
34 33
 extract it and `config`/`make`/`make install` (plus `ldconfig` after).
35 34
 
@@ -37,33 +36,33 @@ extract it and `config`/`make`/`make install` (plus `ldconfig` after).
37 36
 
38 37
 I finally grok the getdns api so the package api is going to change
39 38
 wildly and fast. The default mode will be to perform queries using DNS
40
-over TLS but also supports UDP and TCP transports.
39
+over TLS but also supports UDP and TCP transports along with support for
40
+DNS over HTTPS.
41 41
 
42 42
 ## Why?
43 43
 
44
-Well, for starters, to help research DNS over TLS servers. Plus, for
45
-fun\!
44
+Well, for starters, to help research DNS over TLS/DNS over HTTPS
45
+servers. Plus, for fun\!
46 46
 
47
-If you’re asking “Why DNS over TLS at all?” then “faux” privacy. Why
48
-“faux”? Well, *something* is handing your query and that something
47
+If you’re asking “Why DNS over TLS/HTTPS at all?” then “faux” privacy.
48
+Why “faux”? Well, *something* is handing your query and that something
49 49
 knows your IP address and what you looked for. So, you’re relying on the
50 50
 good faith, honest nature and technical capability of the destination
51 51
 server to not mess with you. I don’t trust Cloudflare or Google and am
52 52
 witholding judgement on Quad9 either way (they’ve been doing good things
53 53
 and are less “look at how cool we are” than CF is).
54 54
 
55
-Also “faux” in that you’re going to be using a standard port (853) and a
56
-TLS session for the queries so your internet provider will know you’re
57
-doing *something* and the current, sorry state of SSL certificates,
58
-certificate authorities, and authoritarian companies and regimes
59
-combined means confidentiality and integrity are always kinda in
55
+Also “faux” in that you’re going to be using (for DoT) a standard port
56
+(853) and a TLS session for the queries so your internet provider will
57
+know you’re doing *something* and the current, sorry state of SSL
58
+certificates, certificate authorities, and authoritarian companies and
59
+regimes combined means confidentiality and integrity are always kinda in
60 60
 question unless done super-well.
61 61
 
62 62
 ## What’s Different About This vs Regular DNS?
63 63
 
64 64
 Well, if we lookup the addresses for `yahoo.com` the old-fashioned way
65
-it’s cleartext UDP on the
66
-    wire:
65
+it’s cleartext UDP on the wire:
67 66
 
68 67
     1   0.000000   10.1.10.57 → 10.1.10.200  DNS 80 Standard query 0x8af8 A yahoo.com OPT
69 68
     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
@@ -76,8 +75,7 @@ server forwards all queries to a custom DNS over TLS server since I
76 75
 really don’t trust any of the providers when it comes down to it. So, in
77 76
 reality for me, it’s even slower than the below — at least initially).
78 77
 
79
-This is the same query via DNS over
80
-TLS
78
+This is the same query via DNS over TLS
81 79
 
82 80
 ``` 
83 81
  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
@@ -111,6 +109,13 @@ to work pretty hard to try to figure out what you’re looking for.
111 109
 
112 110
 The following functions are implemented:
113 111
 
112
+### DNS over HTTPS
113
+
114
+  - `doh_post`: Make a DoH Request (POST/wireformat)
115
+  - `doh_servers`: Built-in list of DoH servers.
116
+
117
+### DNS over TLS
118
+
114 119
   - `gdns_context`: Create a gdns DNS over TLS context and populate it
115 120
     with a resolver for use in resolution functions
116 121
   - `gdns_get_address`: Resolve a host to an addrss
@@ -146,7 +151,9 @@ The following functions are implemented:
146 151
 ## Installation
147 152
 
148 153
 ``` r
149
-devtools::install_git("https://gitlab.com/hrbrmstr/clandnstine.git")
154
+devtools::install_git("https://git.sr.ht/~hrbrmstr/clandnstine")
155
+# or 
156
+devtools::install_gitlab("hrbrmstr/clandnstine.git")
150 157
 # or
151 158
 devtools::install_github("hrbrmstr/clandnstine")
152 159
 ```
@@ -158,7 +165,7 @@ library(clandnstine)
158 165
 
159 166
 # current version
160 167
 packageVersion("clandnstine")
161
-## [1] '0.1.0'
168
+## [1] '0.2.0'
162 169
 ```
163 170
 
164 171
 ### Get an address(es) from a name:
@@ -186,7 +193,7 @@ gdns_lib_version()
186 193
 ## <gdns v1.5.1 resolver context; resolvers: [1.1.1.1]; timeout: 2,000 ms; lookup transport(s): [udp, tls, tcp]; resolution type: stub>
187 194
 
188 195
 (gdns_get_address(x, "rud.is"))
189
-## [1] "2604:a880:800:10::6bc:2001" "104.236.112.222"
196
+## [1] "2602:ff16:3::4dfb:9ac5" "172.93.49.183"
190 197
 
191 198
 (gdns_get_address(x, "yahoo.com"))
192 199
 ##  [1] "2001:4998:58:1836::10" "2001:4998:58:1836::11" "2001:4998:c:1023::4"   "2001:4998:c:1023::5"  
@@ -204,32 +211,48 @@ str(leno <- gdns_query(x, "lenovo.com", "txt"), 1)
204 211
 ## List of 5
205 212
 ##  $ answer_type   : int 800
206 213
 ##  $ canonical_name: chr "lenovo.com."
207
-##  $ replies_full  : int [1, 1:600] 165 144 129 128 0 1 0 8 0 0 ...
214
+##  $ replies_full  : int [1, 1:762] 34 114 129 128 0 1 0 10 0 0 ...
208 215
 ##  $ replies_tree  :'data.frame':  1 obs. of  7 variables:
209 216
 ##  $ status        : int 900
210 217
 ##  - attr(*, "class")= chr [1:2] "gdns_response" "list"
211 218
 
212 219
 sort(unlist(leno$replies_tree$answer[[1]]$rdata$txt_strings))
213
-## [1] "a82c74b37aa84e7c8580f0e32f4d795d"                                                        
214
-## [2] "ece42d7743c84d6889abda7011fe6f53"                                                        
215
-## [3] "facebook-domain-verification=1r2am7c2bhzrxpqyt0mda0djoquqsi"                             
216
-## [4] "google-site-verification=VxW_e6r_Ka7A518qfX2MmIMHGnkpGbnACsjSxKFCBw0"                    
217
-## [5] "iHzQJvsKnyGP2Nm2qBgL3fyBJ0CC9z4GkY/flfk4EzLP8lPxWHDDPKqZWm1TkeF5kEIL+NotYOF1wo7JtUDXXw=="
218
-## [6] "qh7hdmqm4lzs85p704d6wsybgrpsly0j"                                                        
219
-## [7] "v=spf1 include:spf.messagelabs.com include:_netblocks.eloqua.com ~all"                   
220
-## [8] "Visit www.lenovo.com/think for information about Lenovo products and services"
220
+##  [1] "a82c74b37aa84e7c8580f0e32f4d795d"                                                        
221
+##  [2] "ece42d7743c84d6889abda7011fe6f53"                                                        
222
+##  [3] "facebook-domain-verification=1r2am7c2bhzrxpqyt0mda0djoquqsi"                             
223
+##  [4] "google-site-verification=nGgukcp60rC-gFxMOJw1NHH0B4VnSchRrlfWV-He_tE"                    
224
+##  [5] "google-site-verification=sHIlSlj0U6UnCDkfHp1AolWgVEvDjWvc0TR4KaysD2c"                    
225
+##  [6] "google-site-verification=VxW_e6r_Ka7A518qfX2MmIMHGnkpGbnACsjSxKFCBw0"                    
226
+##  [7] "iHzQJvsKnyGP2Nm2qBgL3fyBJ0CC9z4GkY/flfk4EzLP8lPxWHDDPKqZWm1TkeF5kEIL+NotYOF1wo7JtUDXXw=="
227
+##  [8] "qh7hdmqm4lzs85p704d6wsybgrpsly0j"                                                        
228
+##  [9] "v=spf1 include:spf.messagelabs.com include:_netblocks.eloqua.com ~all"                   
229
+## [10] "Visit www.lenovo.com/think for information about Lenovo products and services"
221 230
 ```
222 231
 
223
-Yep. Advertising even in DNS `TXT` records (see item number
224
-8).
232
+Yep. Advertising even in DNS `TXT` records (see item number 8).
233
+
234
+### DOH
235
+
236
+``` r
237
+str(doh_post("rud.is")$answer)
238
+## 'data.frame':    1 obs. of  5 variables:
239
+##  $ class: int 1
240
+##  $ name : chr "rud.is."
241
+##  $ rdata:'data.frame':   1 obs. of  2 variables:
242
+##   ..$ ipv4_address: chr "172.93.49.183"
243
+##   ..$ rdata_raw   :List of 1
244
+##   .. ..$ : int  172 93 49 183
245
+##  $ ttl  : int 3600
246
+##  $ type : int 1
247
+```
225 248
 
226 249
 ## clandnstine Metrics
227 250
 
228 251
 | Lang | \# Files |  (%) | LoC |  (%) | Blank lines |  (%) | \# Lines |  (%) |
229 252
 | :--- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
230
-| C++  |        3 | 0.21 | 608 | 0.65 |         196 | 0.62 |      138 | 0.27 |
231
-| R    |       10 | 0.71 | 306 | 0.33 |          68 | 0.22 |      280 | 0.54 |
232
-| Rmd  |        1 | 0.07 |  19 | 0.02 |          51 | 0.16 |       97 | 0.19 |
253
+| C++  |        4 | 0.17 | 681 | 0.51 |         220 | 0.49 |      163 | 0.26 |
254
+| R    |       19 | 0.79 | 635 | 0.47 |         170 | 0.38 |      355 | 0.57 |
255
+| Rmd  |        1 | 0.04 |  21 | 0.02 |          56 | 0.13 |      105 | 0.17 |
233 256
 
234 257
 ## Code of Conduct
235 258
 

+ 1
- 1
man/clandnstine.Rd Näytä tiedosto

@@ -4,7 +4,7 @@
4 4
 \name{clandnstine}
5 5
 \alias{clandnstine}
6 6
 \alias{clandnstine-package}
7
-\title{Perform Secure-by-default 'DNS' Queries}
7
+\title{Perform Secure-by-Default 'DNS' Queries}
8 8
 \description{
9 9
 Something something 'DNS. Something something 'TLS'.
10 10
 Something something 'getdns API/library'.

+ 29
- 0
man/doh_post.Rd Näytä tiedosto

@@ -0,0 +1,29 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/doh-query.R
3
+\name{doh_post}
4
+\alias{doh_post}
5
+\title{Make a DoH Request (POST/wireformat)}
6
+\usage{
7
+doh_post(name, type = "A",
8
+  server_path = "https://dns.quad9.net/dns-query")
9
+}
10
+\arguments{
11
+\item{name}{name to query for}
12
+
13
+\item{type}{DNS query type (defaults to "\code{A}")}
14
+
15
+\item{server_path}{full URL path to the DoH server quer endpoint (defaults to Quad9).}
16
+}
17
+\value{
18
+\code{NULL} (if the query failed) or a \code{data.frame} (tibble)
19
+}
20
+\description{
21
+Issue a \code{POST} wireformat query of type \code{type} for \code{name} to
22
+the DoH endpoint specified at \code{server_path}.
23
+}
24
+\examples{
25
+doh_post("rud.is", "A")
26
+}
27
+\references{
28
+\url{https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-05.html}
29
+}

+ 32
- 0
man/doh_servers.Rd Näytä tiedosto

@@ -0,0 +1,32 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/globals.R
3
+\docType{data}
4
+\name{doh_servers}
5
+\alias{doh_servers}
6
+\title{Built-in list of DoH Servers}
7
+\format{An object of class \code{list} of length 11.}
8
+\usage{
9
+doh_servers
10
+}
11
+\description{
12
+The \code{url} element has the URL for \code{GET}/\code{POST} requests and
13
+the \code{extra_params} element has any needed query parameters
14
+for \code{GET} requests.
15
+}
16
+\details{
17
+The list so far.
18
+\itemize{
19
+\item \code{google}: \url{https://dns.google.com/experimental}
20
+\item \code{cloudflare}: \url{https://cloudflare-dns.com/dns-query}
21
+\item \code{quad9}: \url{https://dns.quad9.net/dns-query}
22
+\item \code{securedns_eu}: \url{https://doh.securedns.eu/dns-query}
23
+\item \code{dnswarden_adblock}: \url{https://doh.dnswarden.com/adblock}
24
+\item \code{dnswarden_uncensored}: \url{https://doh.dnswarden.com/uncensored}
25
+\item \code{cleanbrowsing_security}: \url{https://doh.cleanbrowsing.org/doh/security-filter/}
26
+\item \code{cleanbrowsing_family}: \url{https://doh.cleanbrowsing.org/doh/family-filter/}
27
+\item \code{cleanbrowsing_adult}: \url{https://doh.cleanbrowsing.org/doh/adult-filter/}
28
+\item \code{power_dns}: \url{https://doh.powerdns.org}
29
+\item \code{appliedprivacy}: \url{https://doh.appliedprivacy.net/query}
30
+}
31
+}
32
+\keyword{datasets}

BIN
src/.vscode/ipch/fbe8796a0b446fa3/mmap_address.bin Näytä tiedosto


BIN
src/.vscode/ipch/fbe8796a0b446fa3/resolver.ipch Näytä tiedosto


+ 12
- 0
src/RcppExports.cpp Näytä tiedosto

@@ -188,6 +188,17 @@ BEGIN_RCPP
188 188
     return rcpp_result_gen;
189 189
 END_RCPP
190 190
 }
191
+// int_dns_wire_to_list
192
+CharacterVector int_dns_wire_to_list(SEXP buf);
193
+RcppExport SEXP _clandnstine_int_dns_wire_to_list(SEXP bufSEXP) {
194
+BEGIN_RCPP
195
+    Rcpp::RObject rcpp_result_gen;
196
+    Rcpp::RNGScope rcpp_rngScope_gen;
197
+    Rcpp::traits::input_parameter< SEXP >::type buf(bufSEXP);
198
+    rcpp_result_gen = Rcpp::wrap(int_dns_wire_to_list(buf));
199
+    return rcpp_result_gen;
200
+END_RCPP
201
+}
191 202
 // check_is_xptr
192 203
 void check_is_xptr(SEXP s);
193 204
 RcppExport SEXP _clandnstine_check_is_xptr(SEXP sSEXP) {
@@ -286,6 +297,7 @@ static const R_CallMethodDef CallEntries[] = {
286 297
     {"_clandnstine_gdns_set_tls_ca_path", (DL_FUNC) &_clandnstine_gdns_set_tls_ca_path, 2},
287 298
     {"_clandnstine_gdns_set_tls_ca_file", (DL_FUNC) &_clandnstine_gdns_set_tls_ca_file, 2},
288 299
     {"_clandnstine_int_gdns_get_root_servers", (DL_FUNC) &_clandnstine_int_gdns_get_root_servers, 1},
300
+    {"_clandnstine_int_dns_wire_to_list", (DL_FUNC) &_clandnstine_int_dns_wire_to_list, 1},
289 301
     {"_clandnstine_check_is_xptr", (DL_FUNC) &_clandnstine_check_is_xptr, 1},
290 302
     {"_clandnstine_is_null_xptr_", (DL_FUNC) &_clandnstine_is_null_xptr_, 1},
291 303
     {"_clandnstine_int_gdns_context", (DL_FUNC) &_clandnstine_int_gdns_context, 1},

+ 45
- 0
src/from-wire.cpp Näytä tiedosto

@@ -0,0 +1,45 @@
1
+#include <Rcpp.h>
2
+
3
+#include <getdns/getdns.h>
4
+#include <getdns/getdns_extra.h>
5
+
6
+#include <arpa/inet.h>
7
+
8
+using namespace Rcpp;
9
+
10
+// [[Rcpp::export]]
11
+CharacterVector int_dns_wire_to_list(SEXP buf) {
12
+
13
+  getdns_return_t r;
14
+  bool ok = true;
15
+
16
+  getdns_dict *resp;
17
+  std::string out;
18
+
19
+  r = getdns_wire2msg_dict(RAW(buf), LENGTH(buf), &resp);
20
+
21
+  if (r == GETDNS_RETURN_GOOD) {
22
+
23
+    char *charout = getdns_print_json_dict(resp, 0);
24
+
25
+    if (charout) {
26
+      out = std::string(charout);
27
+      free(charout);
28
+    } else {
29
+      ok = false;
30
+    }
31
+
32
+  } else {
33
+    ok = false;
34
+  }
35
+
36
+  if (resp) getdns_dict_destroy(resp);
37
+
38
+  if (ok) return(wrap(out)); else return(CharacterVector());
39
+
40
+}
41
+
42
+// getdns_wire2rr_dict 	(	const uint8_t * 	wire,
43
+//                        size_t 	wire_sz,
44
+//                        getdns_dict ** 	rr_dict
45
+// )

Loading…
Peruuta
Tallenna