cdns_rs/lib.rs
1/*-
2 * cdns-rs - a simple sync/async DNS query library
3 *
4 * Copyright (C) 2020 Aleksandr Morozov
5 *
6 * Copyright 2025 Aleksandr Morozov
7 *
8 * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
9 * the European Commission - subsequent versions of the EUPL (the "Licence").
10 *
11 * You may not use this work except in compliance with the Licence.
12 *
13 * You may obtain a copy of the Licence at:
14 *
15 * https://joinup.ec.europa.eu/software/page/eupl
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
20 * Licence for the specific language governing permissions and limitations
21 * under the Licence.
22 */
23
24/*! cdns-rs
25 # CDns-rs
26
27 v 1.0.0
28
29 An implementation of client side DNS query library which also is able to look for host name in `/etc/hosts`.
30 Also it is able to `/etc/resolv.conf` and uses options from this file to configure itself. So it acts like libc's `gethostbyname(3)` or `gethostbyaddr(3)`. The configuration can be overriden.
31
32 This library supports both async and sync code. At the moment async part is not available because:
33 - it is based on the sync realization because async code is based on sync code and sync code is unstable at the moment
34 - it requires proper porting from sync, because sync uses `poll(2)` to achieve the parallel name resolution
35
36 ## Supported
37
38 - Sending and receiving responses via TCP/UDP
39 - Reacting on the message truncated event by trying TCP
40 - Parsing /etc/hosts (all options)
41 - Partial parsing /etc/resolve.conf (all options)
42 - Async and Sync code (separate implementations)
43 - Sequential and pipelined requests.
44 - DNS-over-TLS
45
46 ## ToDo
47 - DNS-over-HTTPS
48 - Parse /etc/nsswitch.conf
49 - DNSSEC
50 - OPT_NO_CHECK_NAMES
51 - resolv.conf (search, domain, sortlist)
52
53
54 Usage:
55
56 - see ./examples/
57
58 Simple Example:
59
60 ```rust
61 use cdns_rs::sync::{QDns, QuerySetup, QType, request};
62
63 fn main()
64 {
65 // a, aaaa
66 let res_a = request::resolve_fqdn("protonmail.com", None).unwrap();
67
68 println!("A/AAAA:");
69 for a in res_a
70 {
71 println!("\t{}", a);
72 }
73 }
74 ```
75
76 Custom query:
77
78 ```rust
79 use cdns_rs::sync::{QDns, QuerySetup, QType, request, caches::CACHE};
80
81 fn main()
82 {
83 // soa
84 let mut dns_req =
85 QDns::make_empty(None, QuerySetup::default()).unwrap();
86
87 dns_req.add_request(QType::SOA, "protonmail.com");
88
89 // sending request and receiving results
90 let res = dns_req.query();
91
92
93 println!("SOA:");
94 let soa_res = res.get_result();
95
96 if soa_res.is_err() == true
97 {
98 println!("{}", soa_res.err().unwrap());
99 }
100 else
101 {
102 let soa = soa_res.unwrap();
103
104 if soa.is_empty() == true
105 {
106 println!("\tNo SOA found!")
107 }
108 else
109 {
110 for s in soa
111 {
112 for i in s.resp
113 {
114 println!("\t{}", i)
115 }
116 }
117 }
118
119 }
120 }
121 ```
122
123 ### Custom resolv.conf use TCP:
124 ```rust
125 use std::{net::{IpAddr, SocketAddr}, sync::Arc, time::Instant};
126
127 use cdns_rs::{cfg_resolv_parser::{OptionFlags, ResolveConfEntry}, common::bind_all, sync::{request, ResolveConfig}};
128
129 fn main()
130 {
131 let now = Instant::now();
132
133 let cfg =
134 "nameserver 8.8.8.8 \n\
135 options use-vc";
136
137 // -- or --
138 let resolver_ip: IpAddr = "8.8.8.8".parse().unwrap();
139
140 let mut resolve = ResolveConfig::default();
141
142 resolve.nameservers.push(Arc::new(ResolveConfEntry::new(SocketAddr::new(resolver_ip, 53), None, bind_all(resolver_ip)).unwrap()));
143 resolve.option_flags = OptionFlags::OPT_USE_VC;
144
145 let cust_parsed = Arc::new(ResolveConfig::custom_config(cfg).unwrap());
146 let cust_manual = Arc::new(resolve);
147
148 assert_eq!(cust_parsed, cust_manual);
149
150 // a, aaaa
151 let res_a = request::resolve_fqdn("protonmail.com", Some(cust_parsed)).unwrap();
152
153 let elapsed = now.elapsed();
154 println!("Elapsed: {:.2?}", elapsed);
155
156 println!("A/AAAA:");
157 for a in res_a
158 {
159 println!("\t{}", a);
160 }
161
162 return;
163 }
164 ```
165
166 ### Custom resolv.conf use TLS:
167 ```rust
168 use std::{sync::Arc, time::Instant};
169
170 use cdns_rs::sync::{request, ResolveConfig};
171
172 fn main()
173 {
174 let now = Instant::now();
175
176 let cfg = "nameserver 1.1.1.1#@853#cloudflare-dns.com \n\
177 options use-vc single-request";
178
179 let cust = Arc::new(ResolveConfig::custom_config(cfg).unwrap());
180
181 // a, aaaa
182 let res_a = request::resolve_fqdn("google.com", Some(cust.clone())).unwrap();
183
184
185 let elapsed = now.elapsed();
186 println!("Elapsed: {:.2?}", elapsed);
187
188 println!("A/AAAA:");
189 for a in res_a
190 {
191 println!("\t{}", a);
192 }
193
194 return;
195 }
196
197 ```
198
199 ToSockAddress
200
201 ```rust
202 use std::net::UdpSocket;
203
204 use cdns_rs::sync::query::QDnsSockerAddr;
205
206
207
208 // run in shell `nc -u -l 44444` a "test" should be received
209 fn main()
210 {
211 let udp = UdpSocket::bind("127.0.0.1:33333").unwrap();
212 udp.connect(QDnsSockerAddr::resolve("localhost:44444").unwrap()).unwrap();
213
214 udp.send("test".as_bytes()).unwrap();
215
216 return;
217 }
218 ```
219 */
220
221
222
223extern crate rand;
224#[macro_use] extern crate bitflags;
225extern crate nix;
226
227#[cfg(feature = "use_sync")]
228extern crate rustls;
229
230#[cfg(feature = "use_async")]
231extern crate tokio_rustls;
232
233#[cfg(any(feature = "use_sync", feature = "use_async"))]
234extern crate webpki;
235#[cfg(any(feature = "use_sync", feature = "use_async"))]
236extern crate webpki_roots;
237//extern crate webrtc_dtls;
238
239
240extern crate httparse;
241
242#[cfg(feature = "use_sync")]
243extern crate byteorder;
244#[cfg(feature = "use_sync")]
245extern crate crossbeam_utils;
246
247
248#[cfg(feature = "use_async")]
249extern crate async_recursion;
250#[cfg(feature = "use_async")]
251extern crate tokio;
252#[cfg(feature = "use_async")]
253extern crate tokio_byteorder;
254#[cfg(feature = "use_async")]
255extern crate async_trait;
256
257
258#[cfg(feature = "use_async")]
259pub mod a_sync;
260
261#[cfg(feature = "use_sync")]
262pub mod sync;
263
264pub mod cfg_host_parser;
265pub mod cfg_resolv_parser;
266mod network_common;
267
268
269mod query_private;
270
271pub mod query;
272pub mod common;
273mod portable;
274#[macro_use] pub mod error;
275mod tokenizer;
276
277pub use error::*;
278pub use common::{QType, DnsResponsePayload, DnsRdata};
279pub use query::{QDnsQueryResult, QDnsQuery, QuerySetup, QDnsQueryRec};
280
281
282
283
284