Skip to content

Commit

Permalink
Fixed DNS::Compress decoding 0xc1 error problem.
Browse files Browse the repository at this point in the history
  • Loading branch information
636f7374 committed Oct 11, 2023
1 parent 7c83191 commit e7b2c82
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 30 deletions.
12 changes: 6 additions & 6 deletions examples/concurrent_custom_resolve.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ reply_packets = Set(Tuple(String, Time::Span, Tuple(DNS::FetchType, Array(DNS::P
main_concurrent_fibers = spawn do
google_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "8.8.8.8.in-addr.arpa", record_type: DNS::Packet::RecordFlag::PTR, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "8.8.8.8.in-addr.arpa", record_type: DNS::Packet::RecordFlag::PTR, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "8.8.8.8.in-addr.arpa", record_type: DNS::Packet::RecordFlag::PTR, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "8.8.8.8.in-addr.arpa", (after - before), packets }
Expand All @@ -28,7 +28,7 @@ main_concurrent_fibers = spawn do

cloudflare_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "cloudflare.com", record_type: DNS::Packet::RecordFlag::SOA, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "cloudflare.com", record_type: DNS::Packet::RecordFlag::SOA, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "cloudflare.com", record_type: DNS::Packet::RecordFlag::SOA, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "cloudflare.com", (after - before), packets }
Expand All @@ -38,7 +38,7 @@ main_concurrent_fibers = spawn do

spotify_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "spotify.com", record_type: DNS::Packet::RecordFlag::CNAME, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "spotify.com", record_type: DNS::Packet::RecordFlag::CNAME, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "spotify.com", record_type: DNS::Packet::RecordFlag::CNAME, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "spotify.com", (after - before), packets }
Expand All @@ -48,7 +48,7 @@ main_concurrent_fibers = spawn do

github_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "github.com", record_type: DNS::Packet::RecordFlag::MX, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "github.com", record_type: DNS::Packet::RecordFlag::MX, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "github.com", record_type: DNS::Packet::RecordFlag::MX, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "github.com", (after - before), packets }
Expand All @@ -58,7 +58,7 @@ main_concurrent_fibers = spawn do

medium_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "medium.com", record_type: DNS::Packet::RecordFlag::TXT, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "medium.com", record_type: DNS::Packet::RecordFlag::TXT, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "medium.com", record_type: DNS::Packet::RecordFlag::TXT, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "medium.com", (after - before), packets }
Expand All @@ -68,7 +68,7 @@ main_concurrent_fibers = spawn do

another_github_query_fiber = spawn do
before = Time.local
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "github.com", record_type: DNS::Packet::RecordFlag::MX, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "github.com", record_type: DNS::Packet::RecordFlag::MX, class_type: DNS::Packet::ClassFlag::Internet
packets = dns_resolver.resolve host: "github.com", record_type: DNS::Packet::RecordFlag::MX, ask_packet: ask_packet
after = Time.local
reply_mutex.synchronize { reply_packets << Tuple.new "github.com", (after - before), packets }
Expand Down
2 changes: 1 addition & 1 deletion examples/parse_udp_packet.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../src/dns.cr"

buffer = uninitialized UInt8[4096_i32]
ask_packet = DNS::Packet.create_getaddrinfo_ask protocol_type: DNS::ProtocolType::UDP, name: "8.8.8.8.in-addr.arpa", record_type: DNS::Packet::RecordFlag::PTR, class_type: DNS::Packet::ClassFlag::Internet
ask_packet = DNS::Packet.create_query_packet protocol_type: DNS::ProtocolType::UDP, name: "8.8.8.8.in-addr.arpa", record_type: DNS::Packet::RecordFlag::PTR, class_type: DNS::Packet::ClassFlag::Internet
ask_packet.transmissionId = Random.new.rand UInt16

udp_socket = UDPSocket.new
Expand Down
42 changes: 42 additions & 0 deletions examples/spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require "../src/dns.cr"

# Oct, 11, 2023
# Fixed DNS::Compress decoding 0xc1 error problem.
# Before: (((pointer_value - 0b11000000).to_u8 << 8_u8) | pointer_slice[0_u8]).to_u16
# After: (((pointer_value & 0b00000011_u8).to_u16 << 8_u8) | pointer_slice[0_u8])

buffer = "\xd3\xf5\x81\x80\x00\x01\x00\x01\x00\x08\x00\x09\x03\x72\x61\x77" \
"\x11\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65" \
"\x6e\x74\x03\x63\x6f\x6d\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00" \
"\x01\x00\x00\x00\x99\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\xc0\x10\x00\x02\x00\x01\x00\x01\x32" \
"\xcf\x00\x14\x04\x64\x6e\x73\x32\x03\x70\x30\x31\x05\x6e\x73\x6f" \
"\x6e\x65\x03\x6e\x65\x74\x00\xc0\x10\x00\x02\x00\x01\x00\x01\x32" \
"\xcf\x00\x13\x06\x6e\x73\x2d\x31\x38\x31\x09\x61\x77\x73\x64\x6e" \
"\x73\x2d\x32\x32\xc0\x22\xc0\x10\x00\x02\x00\x01\x00\x01\x32\xcf" \
"\x00\x19\x07\x6e\x73\x2d\x31\x38\x36\x37\x09\x61\x77\x73\x64\x6e" \
"\x73\x2d\x34\x31\x02\x63\x6f\x02\x75\x6b\x00\xc0\x10\x00\x02\x00" \
"\x01\x00\x01\x32\xcf\x00\x13\x06\x6e\x73\x2d\x35\x39\x36\x09\x61" \
"\x77\x73\x64\x6e\x73\x2d\x31\x30\xc0\x62\xc0\x10\x00\x02\x00\x01" \
"\x00\x01\x32\xcf\x00\x07\x04\x64\x6e\x73\x33\xc0\x58\xc0\x10\x00" \
"\x02\x00\x01\x00\x01\x32\xcf\x00\x07\x04\x64\x6e\x73\x34\xc0\x58" \
"\xc0\x10\x00\x02\x00\x01\x00\x01\x32\xcf\x00\x07\x04\x64\x6e\x73" \
"\x31\xc0\x58\xc0\x10\x00\x02\x00\x01\x00\x01\x32\xcf\x00\x17\x07" \
"\x6e\x73\x2d\x31\x34\x31\x31\x09\x61\x77\x73\x64\x6e\x73\x2d\x34" \
"\x38\x03\x6f\x72\x67\x00\xc0\x73\x00\x1c\x00\x01\x00\x01\x31\xf8" \
"\x00\x10\x26\x00\x90\x00\x53\x00\xb5\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x01\xc0\xb7\x00\x1c\x00\x01\x00\x01\x34\x09\x00\x10\x26\x00" \
"\x90\x00\x53\x02\x54\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\x92" \
"\x00\x01\x00\x01\x00\x00\x04\x4c\x00\x04\xcd\xfb\xc7\x4b\xc0\x92" \
"\x00\x1c\x00\x01\x00\x00\x05\xcd\x00\x10\x26\x00\x90\x00\x53\x07" \
"\x4b\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc1\x0f\x00\x01\x00\x01" \
"\x00\x00\x06\xeb\x00\x04\xcd\xfb\xc5\x83\xc0\xfc\x00\x01\x00\x01" \
"\x00\x01\x1b\x9b\x00\x04\xc6\x33\x2c\x01\xc0\xfc\x00\x1c\x00\x01" \
"\x00\x02\x4a\x57\x00\x10\x26\x20\x00\x4d\x40\x00\x62\x59\x00\x07" \
"\x00\x01\x00\x00\x00\x01\xc0\x53\x00\x01\x00\x01\x00\x00\x04\xd0" \
"\x00\x04\xc6\x33\x2d\x01\xc0\x53\x00\x1c\x00\x01\x00\x02\x8c\x99" \
"\x00\x10\x2a\x00\xed\xc0\x62\x59\x00\x07\x00\x01\x00\x00\x00\x00" \
"\x00\x02".to_slice

reply = DNS::Packet.from_io protocol_type: DNS::ProtocolType::UDP, io: IO::Memory.new(buffer)
STDOUT.puts [reply]
6 changes: 4 additions & 2 deletions src/dns/compress.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ module DNS::Compress
read_length = io.read slice: pointer_buffer.to_slice
raise Exception.new "Compress.decode: (Pointer) Failed to read 1 Bytes from IO!" unless 1_i32 == read_length
pointer_slice = pointer_buffer.to_slice
pointer_value = (((pointer_value - 0b11000000).to_u8 << 8_u8) | pointer_slice[0_u8]).to_u16
pointer_value = (((pointer_value & 0b00000011_u8).to_u16 << 8_u8) | pointer_slice[0_u8])
pointer_value += 2_i32 if protocol_type.tcp? || protocol_type.tls?
buffer.write slice: pointer_slice

before_buffer_position = buffer.pos
Expand All @@ -38,7 +39,8 @@ module DNS::Compress
if pointer_value >= 0b11000000
read_length = buffer.read_fully slice: pointer_buffer.to_slice
pointer_slice = pointer_buffer.to_slice
pointer_value = (((pointer_value - 0b11000000).to_u8 << 8_u8) | pointer_slice[0_u8]).to_u16
pointer_value = (((pointer_value & 0b00000011_u8).to_u16 << 8_u8) | pointer_slice[0_u8])
pointer_value += 2_i32 if protocol_type.tcp? || protocol_type.tls?

buffer.pos = pointer_value
else
Expand Down
5 changes: 5 additions & 0 deletions src/dns/packet.cr
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,12 @@ struct DNS::Packet
true
end

@[Deprecated]
def self.create_getaddrinfo_ask(protocol_type : ProtocolType, name : String, record_type : RecordFlag, class_type : ClassFlag = ClassFlag::Internet)
create_query_packet protocol_type: protocol_type, name: name, record_type: record_type, class_type: class_type
end

def self.create_query_packet(protocol_type : ProtocolType, name : String, record_type : RecordFlag, class_type : ClassFlag = ClassFlag::Internet)
packet = new arType: ARType::Ask, protocolType: protocol_type

{% begin %}
Expand Down
42 changes: 21 additions & 21 deletions src/dns/resolver.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class DNS::Resolver
dns_servers = nil if dns_servers.try &.empty?
dns_servers = dnsServers unless dns_servers

packets = getaddrinfo_query_ip_records dns_servers: dns_servers, host: host, class_type: Packet::ClassFlag::Internet
packets = query_ip_records dns_servers: dns_servers, host: host, class_type: Packet::ClassFlag::Internet
ip_addresses = select_packet_answers_records_ip_addresses host: host, packets: packets, options: options

caching_entry = ipAddressCaching.set host: host, ipv4_addresses: ip_addresses.first, ipv6_addresses: ip_addresses.last
Expand Down Expand Up @@ -201,12 +201,12 @@ class DNS::Resolver
value.to_set
end

private def getaddrinfo_query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
return concurrent_getaddrinfo_query_ip_records dns_servers: dns_servers, host: host, class_type: class_type if options.addrinfo.concurrentQuery
regular_getaddrinfo_query_ip_records dns_servers: dns_servers, host: host, class_type: class_type
private def query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
return concurrent_query_ip_records dns_servers: dns_servers, host: host, class_type: class_type if options.addrinfo.concurrentQuery
regular_query_ip_records dns_servers: dns_servers, host: host, class_type: class_type
end

private def concurrent_getaddrinfo_query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
private def concurrent_query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
concurrent_mutex = Mutex.new :unchecked
concurrent_fibers = Set(Fiber).new
reply_mutex = Mutex.new :unchecked
Expand All @@ -216,28 +216,28 @@ class DNS::Resolver
case options.addrinfo.queryType
in .ipv4_only?
ipv4_query_fiber = spawn do
ipv4_packets = getaddrinfo_query_a_records dns_servers: dns_servers, host: host, class_type: class_type
ipv4_packets = query_a_records dns_servers: dns_servers, host: host, class_type: class_type
reply_mutex.synchronize { reply_packets << ipv4_packets }
end

concurrent_mutex.synchronize { concurrent_fibers << ipv4_query_fiber }
in .ipv6_only?
ipv6_query_fiber = spawn do
ipv6_packets = getaddrinfo_query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
ipv6_packets = query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
reply_mutex.synchronize { reply_packets << ipv6_packets }
end

concurrent_mutex.synchronize { concurrent_fibers << ipv6_query_fiber }
in .both?
ipv4_query_fiber = spawn do
ipv4_packets = getaddrinfo_query_a_records dns_servers: dns_servers, host: host, class_type: class_type
ipv4_packets = query_a_records dns_servers: dns_servers, host: host, class_type: class_type
reply_mutex.synchronize { reply_packets << ipv4_packets }
end

concurrent_mutex.synchronize { concurrent_fibers << ipv4_query_fiber }

ipv6_query_fiber = spawn do
ipv6_packets = getaddrinfo_query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
ipv6_packets = query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
reply_mutex.synchronize { reply_packets << ipv6_packets }
end

Expand All @@ -254,43 +254,43 @@ class DNS::Resolver
end
end

private def regular_getaddrinfo_query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
private def regular_query_ip_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
case options.addrinfo.queryType
in .ipv4_only?
getaddrinfo_query_a_records dns_servers: dns_servers, host: host, class_type: class_type
query_a_records dns_servers: dns_servers, host: host, class_type: class_type
in .ipv6_only?
ipv6_packets = getaddrinfo_query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
ipv6_packets = query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
in .both?
packets = getaddrinfo_query_a_records dns_servers: dns_servers, host: host, class_type: class_type
packets = query_a_records dns_servers: dns_servers, host: host, class_type: class_type

ipv6_packets = getaddrinfo_query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
ipv6_packets = query_aaaa_records dns_servers: dns_servers, host: host, class_type: class_type
ipv6_packets.each { |packet| packets << packet }

packets
end
end

{% for record_type in ["a", "aaaa"] %}
private def getaddrinfo_query_{{record_type.id}}_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
getaddrinfo_query! dns_servers: dns_servers, host: host, record_type: Packet::RecordFlag::{{record_type.upcase.id}}, class_type: class_type
private def query_{{record_type.id}}_records(dns_servers : Set(Address), host : String, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
resolve dns_servers: dns_servers, host: host, record_type: Packet::RecordFlag::{{record_type.upcase.id}}, class_type: class_type
end
{% end %}

private def getaddrinfo_query!(dns_servers : Set(Address), host : String, record_type : Packet::RecordFlag, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
ask_packet = Packet.create_getaddrinfo_ask protocol_type: ProtocolType::UDP, name: host, record_type: record_type, class_type: class_type
resolve! dns_servers: dns_servers, ask_packet: ask_packet
private def resolve(dns_servers : Set(Address), host : String, record_type : Packet::RecordFlag, class_type : Packet::ClassFlag = Packet::ClassFlag::Internet) : Array(Packet)
ask_packet = Packet.create_query_packet protocol_type: ProtocolType::UDP, name: host, record_type: record_type, class_type: class_type
resolve dns_servers: dns_servers, ask_packet: ask_packet
end

def resolve(host : String, record_type : Packet::RecordFlag, ask_packet : Packet) : Tuple(FetchType, Array(Packet))
packetCaching.get?(host: host, record_type: record_type).try { |packets| return Tuple.new FetchType::Caching, packets }

packets = resolve! dns_servers: dnsServers, ask_packet: ask_packet
packets = resolve dns_servers: dnsServers, ask_packet: ask_packet
packetCaching.set host: host, record_type: record_type, packets: packets

Tuple.new FetchType::Remote, packets
end

private def resolve!(dns_servers : Set(Address), ask_packet : Packet) : Array(Packet)
private def resolve(dns_servers : Set(Address), ask_packet : Packet) : Array(Packet)
return concurrent_resolve dns_servers: dns_servers, ask_packet: ask_packet if options.addrinfo.concurrentQuery
regular_resolve dns_servers: dns_servers, ask_packet: ask_packet
end
Expand Down

0 comments on commit e7b2c82

Please sign in to comment.