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
71
72
73
74
75
76
77
78
79
|
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
|
-
-
-
+
+
-
-
-
+
-
-
+
-
+
-
+
-
-
-
-
+
-
+
-
-
-
-
-
-
+
+
+
|
getter raw_data : Bytes
def initialize(@query : Query, @id : UInt16, @settings : Settings,
@block : Response | Error ->)
@ns_index = 0
@attempt = 0
@used_ns = nil
@raw_data = Bytes.new(512)
# Header
i = 0
@raw_data[i] = (@id >> 8).to_u8; i += 1
io = IO::Memory.new(512)
io.write_bytes(@id, IO::ByteFormat::BigEndian)
@raw_data[i] = (@id & 0xFF).to_u8; i += 1
# RD
@raw_data[i] = 1; i += 1
i += 1
io.write_bytes(0x100_u16, IO::ByteFormat::BigEndian)
# QDCOUNT
i += 1
@raw_data[i] = 1; i += 1
io.write_bytes(1_u16, IO::ByteFormat::BigEndian)
# ANCOUNT, NSCOUNT and ARCOUNT
i += 6
3.times { io.write_bytes(0_u16) }
# Question
# QNAME
@query.domain.split('.').each do |component|
if component.bytesize > 63 || i + component.bytesize > 512
if component.bytesize > 63 || io.size + component.bytesize > 512
raise ArgumentError.new("Domain component too long")
end
raw_component = component.to_slice
@raw_data[i] = raw_component.bytesize.to_u8; i += 1
@raw_data[i, raw_component.bytesize].copy_from(raw_component)
i += raw_component.bytesize
io << component
end
# QTYPE
qtype = @query.rr_type.to_i
io.write_bytes(@query.rr_type.to_u16, IO::ByteFormat::BigEndian)
@raw_data[i] = (qtype >> 8).to_u8; i += 1
@raw_data[i] = (qtype & 0xFF).to_u8; i+= 1
# QCLASS
qclass = @query.dns_class.to_i
@raw_data[i] = (qclass >> 8).to_u8; i += 1
@raw_data[i] = (qclass & 0xFF).to_u8; i += 1
io.write_bytes(@query.dns_class.to_u16, IO::ByteFormat::BigEndian)
@raw_data = io.to_slice
end
end
def initialize
@settings = Settings.new
@queries = Hash(UInt16, Context).new
@tcp_queries = Hash(Socket, Context).new
|