Bob Rudis 3 years ago
parent
commit
2072f5245d
15 changed files with 523 additions and 34 deletions
  1. 5
    3
      DESCRIPTION
  2. 16
    0
      NAMESPACE
  3. 6
    2
      R/gdns-package.r
  4. 30
    7
      R/gdns.r
  5. 108
    0
      R/spf.r
  6. 24
    3
      README.Rmd
  7. 233
    12
      README.md
  8. 8
    1
      man/bulk_query.Rd
  9. 3
    1
      man/gdns.Rd
  10. 15
    0
      man/has_spf.Rd
  11. 21
    0
      man/is_soft_fail.Rd
  12. 11
    4
      man/query.Rd
  13. 24
    0
      man/spf_ipv4s.Rd
  14. 18
    0
      man/split_spf.Rd
  15. 1
    1
      tests/testthat/test-gdns.R

+ 5
- 3
DESCRIPTION View File

@@ -1,6 +1,6 @@
1 1
 Package: gdns
2 2
 Title: Tools to Work with Google DNS Over HTTPS API
3
-Version: 0.1.0.9000
3
+Version: 0.2.0.9000
4 4
 Authors@R: c(person("Bob", "Rudis", email = "bob@rudis.net", role = c("aut", "cre")))
5 5
 Maintainer: Bob Rudis <bob@rudis.net>
6 6
 Description: To address the problem of insecurity of UDP-based DNS requests,
@@ -9,7 +9,8 @@ Description: To address the problem of insecurity of UDP-based DNS requests,
9 9
     between a client and a recursive resolver, and complements DNSSEC
10 10
     to provide end-to-end authenticated DNS lookups. Functions that enable
11 11
     querying individual requests that bulk requests that return detailed
12
-    responses and bulk requests are both provided.
12
+    responses and bulk requests are both provided. Support for reverse
13
+    lookups is also provided.
13 14
 License: AGPL + file LICENSE
14 15
 LazyData: true
15 16
 Encoding: UTF-8
@@ -20,5 +21,6 @@ Suggests:
20 21
 Imports:
21 22
     httr,
22 23
     jsonlite,
23
-    purrr
24
+    purrr,
25
+    stringi
24 26
 RoxygenNote: 5.0.1

+ 16
- 0
NAMESPACE View File

@@ -1,9 +1,25 @@
1 1
 # Generated by roxygen2: do not edit by hand
2 2
 
3 3
 export(bulk_query)
4
+export(has_spf)
5
+export(is_hard_fail)
6
+export(is_soft_fail)
7
+export(passes_all)
4 8
 export(query)
9
+export(spf_exists)
10
+export(spf_includes)
11
+export(spf_ipv4s)
12
+export(spf_ipv6s)
13
+export(spf_ptrs)
14
+export(split_spf)
5 15
 import(httr)
6 16
 importFrom(jsonlite,fromJSON)
17
+importFrom(purrr,"%||%")
7 18
 importFrom(purrr,map)
8 19
 importFrom(purrr,map_df)
9 20
 importFrom(purrr,safely)
21
+importFrom(stringi,stri_enc_toutf8)
22
+importFrom(stringi,stri_replace_all_regex)
23
+importFrom(stringi,stri_split_fixed)
24
+importFrom(stringi,stri_split_regex)
25
+importFrom(stringi,stri_trim)

+ 6
- 2
R/gdns-package.r View File

@@ -10,12 +10,16 @@
10 10
 #' To address this problem, Google Public DNS offers DNS resolution over an
11 11
 #' encrypted HTTPS connection. DNS-over-HTTPS greatly enhances privacy and
12 12
 #' security between a client and a recursive resolver, and complements DNSSEC
13
-#' to provide end-to-end authenticated DNS lookups.#'
13
+#' to provide end-to-end authenticated DNS lookups.\cr
14
+#' \cr
15
+#' Support for reverse lookups is also provided.
14 16
 #'
15 17
 #' @name gdns
16 18
 #' @docType package
17 19
 #' @author Bob Rudis (@@hrbrmstr)
18 20
 #' @import httr
21
+#' @importFrom stringi stri_split_fixed stri_split_regex stri_trim
22
+#'                     stri_replace_all_regex stri_enc_toutf8
19 23
 #' @importFrom jsonlite fromJSON
20
-#' @importFrom purrr safely map map_df
24
+#' @importFrom purrr safely map map_df %||%
21 25
 NULL

+ 30
- 7
R/gdns.r View File

@@ -1,3 +1,6 @@
1
+ipv4_regex <-
2
+  "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
3
+
1 4
 S_GET <- purrr::safely(GET)
2 5
 
3 6
 #' Perform DNS over HTTPS queries using Google
@@ -20,9 +23,12 @@ S_GET <- purrr::safely(GET)
20 23
 #' @param name item to lookup. Valid characters are numbers, letters, hyphen, and dot. Length
21 24
 #'        must be between 1 and 255. Names with escaped or non-ASCII characters
22 25
 #'        are not supported. Internationalized domain names must use the
23
-#'        punycode format (e.g. "\code{xn--qxam}").
26
+#'        punycode format (e.g. "\code{xn--qxam}").\cr
27
+#'        \cr If an IPv4 string is input, it will be transformed into
28
+#'        a proper format for reverse lookups.
24 29
 #' @param type RR type can be represented as a number in [1, 65535] or canonical
25
-#'        string (A, aaaa, etc.)
30
+#'        string (A, aaaa, etc). More information on RR types can be
31
+#'        found \href{http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4}{here}.
26 32
 #' @param edns_client_subnet The edns0-client-subnet option. Format is an IP
27 33
 #'        address with a subnet mask. Examples: \code{1.2.3.4/24},
28 34
 #'        \code{2001:700:300::/48}.\cr
@@ -31,13 +37,23 @@ S_GET <- purrr::safely(GET)
31 37
 #'        nameservers for geographic location accuracy, use
32 38
 #'        \code{edns_client_subnet=0.0.0.0/0}. Google Public DNS normally sends
33 39
 #'        approximate network information (usually replacing the last part of
34
-#'        your IPv4 address with zeroes).
40
+#'        your IPv4 address with zeroes). \code{0.0.0.0/0} is the default.
35 41
 #' @return a \code{list} with the query result or \code{NULL} if an error occurred
36 42
 #' @references \url{https://developers.google.com/speed/public-dns/docs/dns-over-https}
37 43
 #' @export
38 44
 #' @examples
39 45
 #' query("rud.is")
40
-query <- function(name, type="1", edns_client_subnet=NULL) {
46
+#' query("microsoft.com", "MX")
47
+#' query("google-public-dns-a.google.com", "TXT")
48
+#' query("apple.com")
49
+#' query("17.142.160.59", "PTR")
50
+query <- function(name, type="1", edns_client_subnet="0.0.0.0/0") {
51
+
52
+  if (grepl(ipv4_regex, name)) {
53
+    name <- paste0(c(rev(unlist(stringi::stri_split_fixed(name, ".", 4))),
54
+                     "in-addr.arpa."),
55
+                   sep="", collapse=".")
56
+  }
41 57
 
42 58
   res <- S_GET("https://dns.google.com/resolve",
43 59
                query=list(name=name,
@@ -46,7 +62,10 @@ query <- function(name, type="1", edns_client_subnet=NULL) {
46 62
 
47 63
   if (!is.null(res$result)) {
48 64
     stop_for_status(res$result)
49
-    jsonlite::fromJSON(httr::content(res$result, as="text"))
65
+    txt <- httr::content(res$result, as="text")
66
+    txt <- stringi::stri_enc_toascii(txt)
67
+    txt <- stringi::stri_replace_all_regex(txt, "[[:cntrl:][:blank:]\\n ]+", " ")
68
+    jsonlite::fromJSON(txt)
50 69
   } else {
51 70
     NULL
52 71
   }
@@ -56,13 +75,17 @@ query <- function(name, type="1", edns_client_subnet=NULL) {
56 75
 #' Vectorized query, returning only answers in a data frame
57 76
 #'
58 77
 #' @param hosts character vector of hosts to query
78
+#' @param type RR type (see \code{type} in \code{query()}).
59 79
 #' @return \code{data.frame} of only answers (use \code{query()} for detailed responses)
60 80
 #' @references \url{https://developers.google.com/speed/public-dns/docs/dns-over-https}
61 81
 #' @export
82
+#' @note this is a fairly naive function. It expects \code{Answer} to be one of the
83
+#'       return value list slots. The intent for it was to make it easier
84
+#'       to do bulk forward queries. It will get smarter in future versions.
62 85
 #' @examples
63 86
 #' hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
64 87
 #' gdns::bulk_query(hosts)
65
-bulk_query <- function(hosts) {
66
-  results <- map(hosts, gdns::query)
88
+bulk_query <- function(hosts, type=1) {
89
+  results <- map(hosts, gdns::query, type=type)
67 90
   map_df(results, "Answer")
68 91
 }

+ 108
- 0
R/spf.r View File

@@ -0,0 +1,108 @@
1
+#' Split out all SPF records in a domain's TXT record
2
+#'
3
+#' Given a vector of TXT records, this function will return a list of vectors
4
+#' of all the SPF records for each. If the given TXT record is not an SPF
5
+#' record, \code{NULL} is returned (which makes it easy to skip with \code{purrr}
6
+#' functions).
7
+#'
8
+#' @param spf_rec a character vector of DNS TXT records
9
+#' @export
10
+split_spf <- function(spf_rec) {
11
+  purrr::map(spf_rec, .split_spf)
12
+}
13
+
14
+.split_spf <- function(spf_rec) {
15
+
16
+  if (has_spf(spf_rec)) {
17
+    spf_rec <- stringi::stri_trim(stringi::stri_replace_all_regex(spf_rec, '"', ""))
18
+    recs <- stri_trim(unlist(stringi::stri_split_regex(spf_rec, "\ +")))
19
+    grep("v=spf1", recs, invert=TRUE, value=TRUE)
20
+  } else {
21
+    NA_character_
22
+  }
23
+
24
+}
25
+
26
+#' Test for whether a DNS TXT record is an SPF record
27
+#'
28
+#' @param spf_rec a character vector of DNS TXT records
29
+#' @export
30
+has_spf <- function(spf_rec) {
31
+  grepl("v=spf1", spf_rec)
32
+}
33
+
34
+#' SPF "all" type test
35
+#'
36
+#' @param spf_rec a character vector of DNS TXT records
37
+#' @export
38
+is_soft_fail <- function(spf_rec) {
39
+  ret <- vector("logical", length(spf_rec))
40
+  spf_rec <- stringi::stri_trim(stringi::stri_replace_all_regex(spf_rec, '"', ""))
41
+  SPF <- which(has_spf(spf_rec))
42
+  ret[SPF] <- grepl("~all$", stringi::stri_trim(spf_rec[SPF]))
43
+  ret[!SPF] <- NA
44
+  ret
45
+}
46
+
47
+#' @rdname is_soft_fail
48
+#' @export
49
+is_hard_fail <- function(spf_rec) {
50
+  ret <- vector("logical", length(spf_rec))
51
+  spf_rec <- stringi::stri_trim(stringi::stri_replace_all_regex(spf_rec, '"', ""))
52
+  SPF <- which(has_spf(spf_rec))
53
+  ret[SPF] <- grepl("\\-all$", stringi::stri_trim(spf_rec[SPF]))
54
+  ret[!SPF] <- NA
55
+  ret
56
+}
57
+
58
+#' @rdname is_soft_fail
59
+#' @export
60
+passes_all <- function(spf_rec) {
61
+  ret <- vector("logical", length(spf_rec))
62
+  spf_rec <- stringi::stri_trim(stringi::stri_replace_all_regex(spf_rec, '"', ""))
63
+  SPF <- which(has_spf(spf_rec))
64
+  ret[SPF] <- grepl("\\+all$", stringi::stri_trim(spf_rec[SPF]))
65
+  ret[!SPF] <- NA
66
+  ret
67
+}
68
+
69
+#' SPF field extraction functions
70
+#'
71
+#' @export
72
+spf_ipv4s <- function(spf_rec) {
73
+  purrr::map(split_spf(spf_rec), function(x) {
74
+    stringi::stri_replace_all_regex(grep("ip4", x, value=TRUE), "^ip4:", "")
75
+  })
76
+}
77
+
78
+#' @rdname spf_ipv4s
79
+#' @export
80
+spf_ipv6s <- function(spf_rec) {
81
+  purrr::map(split_spf(spf_rec), function(x) {
82
+    stringi::stri_replace_all_regex(grep("ip6", x, value=TRUE), "^ip6:", "")
83
+  })
84
+}
85
+
86
+#' @rdname spf_ipv4s
87
+#' @export
88
+spf_includes <- function(spf_rec) {
89
+  purrr::map(split_spf(spf_rec), function(x) {
90
+    stringi::stri_replace_all_regex(grep("include", x, value=TRUE), "^include:", "")
91
+  })
92
+}
93
+
94
+#' @rdname spf_ipv4s
95
+#' @export
96
+spf_ptrs <- function(spf_rec) {
97
+  purrr::map(split_spf(spf_rec), function(x) {
98
+    stringi::stri_replace_all_regex(grep("ptr", x, value=TRUE), "^ptr[:]", "")
99
+  })
100
+}
101
+
102
+#' @rdname spf_ipv4s
103
+#' @export
104
+spf_exists <- function(spf_rec) {
105
+  purrr::map(split_spf(spf_rec), function(x) {
106
+    stringi::stri_replace_all_regex(grep("exists", x, value=TRUE), "^exists:", "")
107
+  })
108
+}

+ 24
- 3
README.Rmd View File

@@ -23,11 +23,22 @@ More info at <https://developers.google.com/speed/public-dns/docs/dns-over-https
23 23
 
24 24
 The following functions are implemented:
25 25
 
26
-- `query` : perform Google DNS query for a single host (retreives metadata & answer)
27
-- `bulk_query` : perform bulk host queries, returning a \code{data.frame} of only answers (no metadata)
26
+- `bulk_query`:	Vectorized query, returning only answers in a data frame
27
+- `has_spf`:	Test for whether a DNS TXT record is an SPF record
28
+- `is_hard_fail`:	SPF "all" type test
29
+- `is_soft_fail`:	SPF "all" type test
30
+- `passes_all`:	SPF "all" type test
31
+- `query`:	Perform DNS over HTTPS queries using Google
32
+- `spf_exists`:	SPF field extraction functions
33
+- `spf_includes`:	SPF field extraction functions
34
+- `spf_ipv4s`:	SPF field extraction functions
35
+- `spf_ipv6s`:	SPF field extraction functions
36
+- `spf_ptrs`:	SPF field extraction functions
37
+- `split_spf`:	Split out all SPF records in a domain's TXT record
28 38
 
29 39
 ### News
30 40
 
41
+- Version 0.2.0.9000 SPF stuff
31 42
 - Version 0.1.0.9000 released
32 43
 
33 44
 ### Installation
@@ -60,9 +71,19 @@ date()
60 71
 
61 72
 test_dir("tests/")
62 73
 
63
-hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
74
+query("rud.is")
75
+
76
+query("microsoft.com", "MX")
77
+
78
+query("google-public-dns-a.google.com", "TXT")
79
+
80
+query("apple.com")
64 81
 
82
+query("17.142.160.59", "PTR")
83
+
84
+hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
65 85
 gdns::bulk_query(hosts)
86
+
66 87
 ```
67 88
 
68 89
 ### Code of Conduct

+ 233
- 12
README.md View File

@@ -12,11 +12,22 @@ More info at <https://developers.google.com/speed/public-dns/docs/dns-over-https
12 12
 
13 13
 The following functions are implemented:
14 14
 
15
--   `query` : perform Google DNS query for a single host (retreives metadata & answer)
16
--   `bulk_query` : perform bulk host queries, returning a of only answers (no metadata)
15
+-   `bulk_query`: Vectorized query, returning only answers in a data frame
16
+-   `has_spf`: Test for whether a DNS TXT record is an SPF record
17
+-   `is_hard_fail`: SPF "all" type test
18
+-   `is_soft_fail`: SPF "all" type test
19
+-   `passes_all`: SPF "all" type test
20
+-   `query`: Perform DNS over HTTPS queries using Google
21
+-   `spf_exists`: SPF field extraction functions
22
+-   `spf_includes`: SPF field extraction functions
23
+-   `spf_ipv4s`: SPF field extraction functions
24
+-   `spf_ipv6s`: SPF field extraction functions
25
+-   `spf_ptrs`: SPF field extraction functions
26
+-   `split_spf`: Split out all SPF records in a domain's TXT record
17 27
 
18 28
 ### News
19 29
 
30
+-   Version 0.2.0.9000 SPF stuff
20 31
 -   Version 0.1.0.9000 released
21 32
 
22 33
 ### Installation
@@ -32,7 +43,7 @@ library(gdns)
32 43
 
33 44
 # current verison
34 45
 packageVersion("gdns")
35
-#> [1] '0.1.0.9000'
46
+#> [1] '0.2.0.9000'
36 47
 ```
37 48
 
38 49
 ### Test Results
@@ -42,26 +53,236 @@ library(gdns)
42 53
 library(testthat)
43 54
 
44 55
 date()
45
-#> [1] "Sat Apr  9 21:17:02 2016"
56
+#> [1] "Sun Apr 10 14:51:46 2016"
46 57
 
47 58
 test_dir("tests/")
48 59
 #> testthat results ========================================================================================================
49 60
 #> OK: 2 SKIPPED: 0 FAILED: 0
50 61
 
51
-hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
62
+query("rud.is")
63
+#> $Status
64
+#> [1] 0
65
+#> 
66
+#> $TC
67
+#> [1] FALSE
68
+#> 
69
+#> $RD
70
+#> [1] TRUE
71
+#> 
72
+#> $RA
73
+#> [1] TRUE
74
+#> 
75
+#> $AD
76
+#> [1] FALSE
77
+#> 
78
+#> $CD
79
+#> [1] FALSE
80
+#> 
81
+#> $Question
82
+#>      name type
83
+#> 1 rud.is.    1
84
+#> 
85
+#> $Answer
86
+#>      name type  TTL            data
87
+#> 1 rud.is.    1 3599 104.236.112.222
88
+#> 
89
+#> $Additional
90
+#> list()
91
+#> 
92
+#> $edns_client_subnet
93
+#> [1] "0.0.0.0/0"
94
+#> 
95
+#> $Comment
96
+#> [1] "Response from dns.mwebdns.net.(84.246.121.10)"
52 97
 
98
+query("microsoft.com", "MX")
99
+#> $Status
100
+#> [1] 0
101
+#> 
102
+#> $TC
103
+#> [1] FALSE
104
+#> 
105
+#> $RD
106
+#> [1] TRUE
107
+#> 
108
+#> $RA
109
+#> [1] TRUE
110
+#> 
111
+#> $AD
112
+#> [1] FALSE
113
+#> 
114
+#> $CD
115
+#> [1] FALSE
116
+#> 
117
+#> $Question
118
+#>             name type
119
+#> 1 microsoft.com.   15
120
+#> 
121
+#> $Answer
122
+#>             name type  TTL                                          data
123
+#> 1 microsoft.com.   15 2054 10 microsoft-com.mail.protection.outlook.com.
124
+#> 
125
+#> $Additional
126
+#> list()
127
+#> 
128
+#> $edns_client_subnet
129
+#> [1] "0.0.0.0/0"
130
+
131
+query("google-public-dns-a.google.com", "TXT")
132
+#> $Status
133
+#> [1] 0
134
+#> 
135
+#> $TC
136
+#> [1] FALSE
137
+#> 
138
+#> $RD
139
+#> [1] TRUE
140
+#> 
141
+#> $RA
142
+#> [1] TRUE
143
+#> 
144
+#> $AD
145
+#> [1] FALSE
146
+#> 
147
+#> $CD
148
+#> [1] FALSE
149
+#> 
150
+#> $Question
151
+#>                              name type
152
+#> 1 google-public-dns-a.google.com.   16
153
+#> 
154
+#> $Answer
155
+#>                              name type   TTL                    data
156
+#> 1 google-public-dns-a.google.com.   16 21599 "http://xkcd.com/1361/"
157
+#> 
158
+#> $Additional
159
+#> list()
160
+#> 
161
+#> $edns_client_subnet
162
+#> [1] "0.0.0.0/0"
163
+#> 
164
+#> $Comment
165
+#> [1] "Response from 216.239.38.10"
166
+
167
+query("apple.com")
168
+#> $Status
169
+#> [1] 0
170
+#> 
171
+#> $TC
172
+#> [1] FALSE
173
+#> 
174
+#> $RD
175
+#> [1] TRUE
176
+#> 
177
+#> $RA
178
+#> [1] TRUE
179
+#> 
180
+#> $AD
181
+#> [1] FALSE
182
+#> 
183
+#> $CD
184
+#> [1] FALSE
185
+#> 
186
+#> $Question
187
+#>         name type
188
+#> 1 apple.com.    1
189
+#> 
190
+#> $Answer
191
+#>         name type  TTL          data
192
+#> 1 apple.com.    1 1119 17.172.224.47
193
+#> 2 apple.com.    1 1119  17.178.96.59
194
+#> 3 apple.com.    1 1119 17.142.160.59
195
+#> 
196
+#> $Additional
197
+#> list()
198
+#> 
199
+#> $edns_client_subnet
200
+#> [1] "0.0.0.0/0"
201
+
202
+query("17.142.160.59", "PTR")
203
+#> $Status
204
+#> [1] 0
205
+#> 
206
+#> $TC
207
+#> [1] FALSE
208
+#> 
209
+#> $RD
210
+#> [1] TRUE
211
+#> 
212
+#> $RA
213
+#> [1] TRUE
214
+#> 
215
+#> $AD
216
+#> [1] FALSE
217
+#> 
218
+#> $CD
219
+#> [1] FALSE
220
+#> 
221
+#> $Question
222
+#>                          name type
223
+#> 1 59.160.142.17.in-addr.arpa.   12
224
+#> 
225
+#> $Answer
226
+#>                           name type  TTL                           data
227
+#> 1  59.160.142.17.in-addr.arpa.   12 1134              alchemysynth.com.
228
+#> 2  59.160.142.17.in-addr.arpa.   12 1134                    openni.org.
229
+#> 3  59.160.142.17.in-addr.arpa.   12 1134                      swell.am.
230
+#> 4  59.160.142.17.in-addr.arpa.   12 1134                  appleweb.net.
231
+#> 5  59.160.142.17.in-addr.arpa.   12 1134                     apple.com.
232
+#> 6  59.160.142.17.in-addr.arpa.   12 1134        pv-apple-com.apple.com.
233
+#> 7  59.160.142.17.in-addr.arpa.   12 1134                      apple.by.
234
+#> 8  59.160.142.17.in-addr.arpa.   12 1134                 airtunes.info.
235
+#> 9  59.160.142.17.in-addr.arpa.   12 1134              applecentre.info.
236
+#> 10 59.160.142.17.in-addr.arpa.   12 1134         applecomputerinc.info.
237
+#> 11 59.160.142.17.in-addr.arpa.   12 1134                appleexpo.info.
238
+#> 12 59.160.142.17.in-addr.arpa.   12 1134             applemasters.info.
239
+#> 13 59.160.142.17.in-addr.arpa.   12 1134                 applepay.info.
240
+#> 14 59.160.142.17.in-addr.arpa.   12 1134 applepaymerchantsupplies.info.
241
+#> 15 59.160.142.17.in-addr.arpa.   12 1134         applepaysupplies.info.
242
+#> 16 59.160.142.17.in-addr.arpa.   12 1134              applescript.info.
243
+#> 17 59.160.142.17.in-addr.arpa.   12 1134               appleshare.info.
244
+#> 18 59.160.142.17.in-addr.arpa.   12 1134                   macosx.info.
245
+#> 19 59.160.142.17.in-addr.arpa.   12 1134                powerbook.info.
246
+#> 20 59.160.142.17.in-addr.arpa.   12 1134                 powermac.info.
247
+#> 21 59.160.142.17.in-addr.arpa.   12 1134            quicktimelive.info.
248
+#> 22 59.160.142.17.in-addr.arpa.   12 1134              quicktimetv.info.
249
+#> 23 59.160.142.17.in-addr.arpa.   12 1134                 sherlock.info.
250
+#> 24 59.160.142.17.in-addr.arpa.   12 1134            shopdifferent.info.
251
+#> 25 59.160.142.17.in-addr.arpa.   12 1134                 skyvines.info.
252
+#> 26 59.160.142.17.in-addr.arpa.   12 1134                     ubnw.info.
253
+#> 27 59.160.142.17.in-addr.arpa.   12 1134               webobjects.info.
254
+#> 28 59.160.142.17.in-addr.arpa.   12 1134                   yessql.info.
255
+#> 29 59.160.142.17.in-addr.arpa.   12 1134                ripmixburn.com.
256
+#> 30 59.160.142.17.in-addr.arpa.   12 1134                 apples-msk.ru.
257
+#> 31 59.160.142.17.in-addr.arpa.   12 1134                     icloud.se.
258
+#> 32 59.160.142.17.in-addr.arpa.   12 1134                     icloud.es.
259
+#> 33 59.160.142.17.in-addr.arpa.   12 1134                     icloud.om.
260
+#> 34 59.160.142.17.in-addr.arpa.   12 1134                   icloudo.com.
261
+#> 35 59.160.142.17.in-addr.arpa.   12 1134                     icloud.ch.
262
+#> 36 59.160.142.17.in-addr.arpa.   12 1134                     icloud.fr.
263
+#> 37 59.160.142.17.in-addr.arpa.   12 1134                   icloude.com.
264
+#> 38 59.160.142.17.in-addr.arpa.   12 1134          camelspaceeffect.com.
265
+#> 39 59.160.142.17.in-addr.arpa.   12 1134                 camelphat.com.
266
+#> 
267
+#> $Additional
268
+#> list()
269
+#> 
270
+#> $edns_client_subnet
271
+#> [1] "0.0.0.0/0"
272
+
273
+hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
53 274
 gdns::bulk_query(hosts)
54 275
 #> Source: local data frame [7 x 4]
55 276
 #> 
56 277
 #>             name  type   TTL            data
57 278
 #>            (chr) (int) (int)           (chr)
58
-#> 1        rud.is.     1   710 104.236.112.222
59
-#> 2        dds.ec.     1   280   162.243.111.4
60
-#> 3 r-project.org.     1  6410   137.208.57.37
61
-#> 4   rstudio.com.     1    71    45.79.156.36
62
-#> 5     apple.com.     1  3290   17.172.224.47
63
-#> 6     apple.com.     1  3290    17.178.96.59
64
-#> 7     apple.com.     1  3290   17.142.160.59
279
+#> 1        rud.is.     1  3598 104.236.112.222
280
+#> 2        dds.ec.     1   299   162.243.111.4
281
+#> 3 r-project.org.     1  7177   137.208.57.37
282
+#> 4   rstudio.com.     1  3599    45.79.156.36
283
+#> 5     apple.com.     1  1102   17.172.224.47
284
+#> 6     apple.com.     1  1102    17.178.96.59
285
+#> 7     apple.com.     1  1102   17.142.160.59
65 286
 ```
66 287
 
67 288
 ### Code of Conduct

+ 8
- 1
man/bulk_query.Rd View File

@@ -4,10 +4,12 @@
4 4
 \alias{bulk_query}
5 5
 \title{Vectorized query, returning only answers in a data frame}
6 6
 \usage{
7
-bulk_query(hosts)
7
+bulk_query(hosts, type = 1)
8 8
 }
9 9
 \arguments{
10 10
 \item{hosts}{character vector of hosts to query}
11
+
12
+\item{type}{RR type (see \code{type} in \code{query()}).}
11 13
 }
12 14
 \value{
13 15
 \code{data.frame} of only answers (use \code{query()} for detailed responses)
@@ -15,6 +17,11 @@ bulk_query(hosts)
15 17
 \description{
16 18
 Vectorized query, returning only answers in a data frame
17 19
 }
20
+\note{
21
+this is a fairly naive function. It expects \code{Answer} to be one of the
22
+      return value list slots. The intent for it was to make it easier
23
+      to do bulk forward queries. It will get smarter in future versions.
24
+}
18 25
 \examples{
19 26
 hosts <- c("rud.is", "dds.ec", "r-project.org", "rstudio.com", "apple.com")
20 27
 gdns::bulk_query(hosts)

+ 3
- 1
man/gdns.Rd View File

@@ -16,7 +16,9 @@ often incorporate additional protection.\cr
16 16
 To address this problem, Google Public DNS offers DNS resolution over an
17 17
 encrypted HTTPS connection. DNS-over-HTTPS greatly enhances privacy and
18 18
 security between a client and a recursive resolver, and complements DNSSEC
19
-to provide end-to-end authenticated DNS lookups.#'
19
+to provide end-to-end authenticated DNS lookups.\cr
20
+\cr
21
+Support for reverse lookups is also provided.
20 22
 }
21 23
 \author{
22 24
 Bob Rudis (@hrbrmstr)

+ 15
- 0
man/has_spf.Rd View File

@@ -0,0 +1,15 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/spf.r
3
+\name{has_spf}
4
+\alias{has_spf}
5
+\title{Test for whether a DNS TXT record is an SPF record}
6
+\usage{
7
+has_spf(spf_rec)
8
+}
9
+\arguments{
10
+\item{spf_rec}{a character vector of DNS TXT records}
11
+}
12
+\description{
13
+Test for whether a DNS TXT record is an SPF record
14
+}
15
+

+ 21
- 0
man/is_soft_fail.Rd View File

@@ -0,0 +1,21 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/spf.r
3
+\name{is_soft_fail}
4
+\alias{is_hard_fail}
5
+\alias{is_soft_fail}
6
+\alias{passes_all}
7
+\title{SPF "all" type test}
8
+\usage{
9
+is_soft_fail(spf_rec)
10
+
11
+is_hard_fail(spf_rec)
12
+
13
+passes_all(spf_rec)
14
+}
15
+\arguments{
16
+\item{spf_rec}{a character vector of DNS TXT records}
17
+}
18
+\description{
19
+SPF "all" type test
20
+}
21
+

+ 11
- 4
man/query.Rd View File

@@ -4,16 +4,19 @@
4 4
 \alias{query}
5 5
 \title{Perform DNS over HTTPS queries using Google}
6 6
 \usage{
7
-query(name, type = "1", edns_client_subnet = NULL)
7
+query(name, type = "1", edns_client_subnet = "0.0.0.0/0")
8 8
 }
9 9
 \arguments{
10 10
 \item{name}{item to lookup. Valid characters are numbers, letters, hyphen, and dot. Length
11 11
 must be between 1 and 255. Names with escaped or non-ASCII characters
12 12
 are not supported. Internationalized domain names must use the
13
-punycode format (e.g. "\code{xn--qxam}").}
13
+punycode format (e.g. "\code{xn--qxam}").\cr
14
+\cr If an IPv4 string is input, it will be transformed into
15
+a proper format for reverse lookups.}
14 16
 
15 17
 \item{type}{RR type can be represented as a number in [1, 65535] or canonical
16
-string (A, aaaa, etc.)}
18
+string (A, aaaa, etc). More information on RR types can be
19
+found \href{http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4}{here}.}
17 20
 
18 21
 \item{edns_client_subnet}{The edns0-client-subnet option. Format is an IP
19 22
 address with a subnet mask. Examples: \code{1.2.3.4/24},
@@ -23,7 +26,7 @@ not want any part of your IP address to be sent to authoritative
23 26
 nameservers for geographic location accuracy, use
24 27
 \code{edns_client_subnet=0.0.0.0/0}. Google Public DNS normally sends
25 28
 approximate network information (usually replacing the last part of
26
-your IPv4 address with zeroes).}
29
+your IPv4 address with zeroes). \code{0.0.0.0/0} is the default.}
27 30
 }
28 31
 \value{
29 32
 a \code{list} with the query result or \code{NULL} if an error occurred
@@ -47,6 +50,10 @@ To perform vectorized queries with only answers (and no metadata) use
47 50
 }
48 51
 \examples{
49 52
 query("rud.is")
53
+query("microsoft.com", "MX")
54
+query("google-public-dns-a.google.com", "TXT")
55
+query("apple.com")
56
+query("17.142.160.59", "PTR")
50 57
 }
51 58
 \references{
52 59
 \url{https://developers.google.com/speed/public-dns/docs/dns-over-https}

+ 24
- 0
man/spf_ipv4s.Rd View File

@@ -0,0 +1,24 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/spf.r
3
+\name{spf_ipv4s}
4
+\alias{spf_exists}
5
+\alias{spf_includes}
6
+\alias{spf_ipv4s}
7
+\alias{spf_ipv6s}
8
+\alias{spf_ptrs}
9
+\title{SPF field extraction functions}
10
+\usage{
11
+spf_ipv4s(spf_rec)
12
+
13
+spf_ipv6s(spf_rec)
14
+
15
+spf_includes(spf_rec)
16
+
17
+spf_ptrs(spf_rec)
18
+
19
+spf_exists(spf_rec)
20
+}
21
+\description{
22
+SPF field extraction functions
23
+}
24
+

+ 18
- 0
man/split_spf.Rd View File

@@ -0,0 +1,18 @@
1
+% Generated by roxygen2: do not edit by hand
2
+% Please edit documentation in R/spf.r
3
+\name{split_spf}
4
+\alias{split_spf}
5
+\title{Split out all SPF records in a domain's TXT record}
6
+\usage{
7
+split_spf(spf_rec)
8
+}
9
+\arguments{
10
+\item{spf_rec}{a character vector of DNS TXT records}
11
+}
12
+\description{
13
+Given a vector of TXT records, this function will return a list of vectors
14
+of all the SPF records for each. If the given TXT record is not an SPF
15
+record, \code{NULL} is returned (which makes it easy to skip with \code{purrr}
16
+functions).
17
+}
18
+

+ 1
- 1
tests/testthat/test-gdns.R View File

@@ -1,7 +1,7 @@
1 1
 context("basic functionality")
2 2
 test_that("we can do something", {
3 3
 
4
-  expect_that(length(gdns::query("example.com")), equals(8))
4
+  expect_that(length(gdns::query("example.com")), equals(10))
5 5
 
6 6
   doms <- c("example.com", "example.org", "example.net")
7 7
   qry <- gdns::bulk_query(doms)

Loading…
Cancel
Save