1 extern crate dns_parser;
2
3 use std::env;
4 use std::error::Error;
5 use std::io::{Read, Write};
6 use std::net::TcpStream;
7 use std::process;
8
9
10 use dns_parser::{Builder, Packet, RData, ResponseCode};
11 use dns_parser::rdata::a::Record;
12 use dns_parser::{QueryType, QueryClass};
13
14
main()15 fn main() {
16 let mut code = 0;
17 for name in env::args().skip(1) {
18 match resolve(&name) {
19 Ok(()) => {},
20 Err(e) => {
21 eprintln!("Error resolving {:?}: {}", name, e);
22 code = 1;
23 }
24 }
25 }
26 process::exit(code);
27 }
28
resolve(name: &str) -> Result<(), Box<Error>>29 fn resolve(name: &str) -> Result<(), Box<Error>> {
30 let mut conn = TcpStream::connect("127.0.0.1:53")?;
31 let mut builder = Builder::new_query(1, true);
32 builder.add_question(name, false, QueryType::A, QueryClass::IN);
33 let packet = builder.build().map_err(|_| "truncated packet")?;
34 let psize = [((packet.len() >> 8) & 0xFF) as u8,
35 (packet.len() & 0xFF) as u8];
36 conn.write_all(&psize[..])?;
37 conn.write_all(&packet)?;
38 let mut buf = vec![0u8; 4096];
39 let mut off = 0;
40 let pkt = loop {
41 if buf.len() - off < 4096 {
42 buf.extend(&[0u8; 4096][..]);
43 }
44 match conn.read(&mut buf[off..]) {
45 Ok(num) => {
46 off += num;
47 if off < 2 { continue; }
48 let bytes = ((buf[0] as usize) << 8) | buf[1] as usize;
49 if off < bytes + 2 {
50 continue;
51 }
52 if num == 0 {
53 return Err("Partial packet received".into());
54 }
55 break Packet::parse(&buf[2..off])?;
56 }
57 Err(e) => {
58 return Err(Box::new(e));
59 }
60 }
61 };
62 if pkt.header.response_code != ResponseCode::NoError {
63 return Err(pkt.header.response_code.into());
64 }
65 if pkt.answers.len() == 0 {
66 return Err("No records received".into());
67 }
68 for ans in pkt.answers {
69 match ans.data {
70 RData::A(Record(ip)) => {
71 println!("{}", ip);
72 }
73 _ => {} // ignore
74 }
75 }
76 Ok(())
77 }
78