Overview
Comment: | Initial support for sending the query |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
b6cfd2fe242cd0cd48950c53d6ef2f48 |
User & Date: | js on 2021-03-05 00:59:15 |
Other Links: | manifest | tags |
Context
2021-03-05
| ||
01:34 | Use IO::Memory to build the raw data check-in: af207d1100 user: js tags: trunk | |
00:59 | Initial support for sending the query check-in: b6cfd2fe24 user: js tags: trunk | |
2021-03-04
| ||
02:09 | Some cleanups check-in: c210ddc089 user: js tags: trunk | |
Changes
Modified src/query.cr from [67a7ba4afc] to [8a39ec595d].
1 2 3 4 5 | require "./dns_class" require "./rr_type" module AsyncDNS class Query | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | require "./dns_class" require "./rr_type" module AsyncDNS class Query getter domain : String getter dns_class : DNSClass getter rr_type : RRType def initialize(@domain : String, @dns_class : DNSClass, @rr_type : RRType) end end end |
Modified src/resolver.cr from [389b0620fd] to [d8a14eee35].
|
| | > | > > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | > > | > > > > > > | > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | require "socket" require "./query" require "./response" require "./rr" require "./settings" module AsyncDNS class Resolver @v6_sock : UDPSocket? @v4_sock : UDPSocket? getter settings : Settings enum Error NO_NAME_SERVER end private class Context getter query : Query getter id : UInt16 getter settings : Settings getter block : Response | Error -> property ns_index : Int32 property attempt : Int32 property used_ns : Socket::IPAddress | Nil 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 @raw_data[i] = (@id & 0xFF).to_u8; i += 1 # RD @raw_data[i] = 1; i += 1 i += 1 # QDCOUNT i += 1 @raw_data[i] = 1; i += 1 # ANCOUNT, NSCOUNT and ARCOUNT i += 6 # Question # QNAME @query.domain.split('.').each do |component| if component.bytesize > 63 || i + 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 end # QTYPE qtype = @query.rr_type.to_i @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 end end def initialize @settings = Settings.new @queries = Hash(UInt16, Context).new @tcp_queries = Hash(Socket, Context).new end def resolve(query : Query, &block : Response | Error ->) : Nil id : UInt16 while true id = Random::Secure.rand(UInt16::MIN..UInt16::MAX) break unless @queries.has_key?(id) end if query.domain.bytesize > 253 raise ArgumentError.new("Queried domain is too long") end if @settings.nameservers.empty? block.call(Error::NO_NAME_SERVER) return end send(Context.new(query.dup, id, settings.dup, block)) end private def send(context : Context) : Nil @queries[context.id] = context ns = context.settings.nameservers[context.ns_index] context.used_ns = used_ns = Socket::IPAddress.new(ns, 53) sock : UDPSocket case used_ns.family when Socket::Family::INET6 if @v6_sock.nil? @v6_sock = s = UDPSocket.new s.bind "::", 0 end sock = @v6_sock.not_nil! when Socket::Family::INET if @v4_sock.nil? @v4_sock = s = UDPSocket.new s.bind "0.0.0.0", 0 end sock = @v4_sock.not_nil! else raise ArgumentError.new("Nameserver must be INET or INET6") end sock.send(context.raw_data, used_ns) end def stop : Nil # TODO end end end |
Modified src/response.cr from [05324bedeb] to [d2b49f7ae9].
1 2 3 4 | require "./rr" module AsyncDNS class Response | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | require "./rr" module AsyncDNS class Response property domain : String property answer : Array(RR) property authority : Array(RR) property additional : Array(RR) def initialize(@domain : String, @answer : Array(RR), @authority : Array(RR), @additional : Array(RR)) end end end |
Modified src/rr.cr from [2fc5a6484f] to [6005816ddc].
1 2 3 4 5 | require "socket" module AsyncDNS abstract struct RR property name : String | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | require "socket" module AsyncDNS abstract struct RR property name : String property dns_class : DNSClass property type : RRType property ttl : UInt32 def initialize(@name : String, @dns_class : DNSClass, @type : RRType, @ttl : UInt32) end struct A < RR property address : Socket::IPAddress def initialize(name : String, @address : Socket::IPAddress, ttl : UInt32) |
︙ | ︙ |