Add question parser
This commit is contained in:
commit
d80a398e67
|
@ -0,0 +1,2 @@
|
||||||
|
server
|
||||||
|
.idea
|
|
@ -0,0 +1,96 @@
|
||||||
|
from std/strutils import join
|
||||||
|
import utils
|
||||||
|
|
||||||
|
type
|
||||||
|
Opcode* = enum
|
||||||
|
QUERY = 0, IQUERY = 1, STATUS = 2
|
||||||
|
|
||||||
|
type
|
||||||
|
Rcode* = enum
|
||||||
|
NO_ERROR = 0, FORMAT_ERROR = 1, SERVER_FAULURE = 2, NAME_ERROR = 3,
|
||||||
|
NOT_IMPLEMENTED = 4, REFUSED = 5
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsHeader* = object
|
||||||
|
id*: uint16
|
||||||
|
qr*: bool
|
||||||
|
opcode*: Opcode
|
||||||
|
aa*: bool
|
||||||
|
tc*: bool
|
||||||
|
rd*: bool
|
||||||
|
ra*: bool
|
||||||
|
z*: uint8
|
||||||
|
rcode*: Rcode
|
||||||
|
qdcount*: uint16
|
||||||
|
ancount*: uint16
|
||||||
|
nscount*: uint16
|
||||||
|
arcount*: uint16
|
||||||
|
|
||||||
|
proc parseHeader*(data: string): DnsHeader =
|
||||||
|
assert len(data) >= 12
|
||||||
|
|
||||||
|
return DnsHeader(
|
||||||
|
id: toUInt16(data[1], data[0]),
|
||||||
|
qr: sliceBit(data[2], 0),
|
||||||
|
opcode: Opcode((toUint8(data[2]) shr 3) and 0b00001111),
|
||||||
|
aa: sliceBit(data[2], 5),
|
||||||
|
tc: sliceBit(data[2], 6),
|
||||||
|
rd: sliceBit(data[2], 7),
|
||||||
|
ra: sliceBit(data[3], 0),
|
||||||
|
z: (toUint8(data[3]) shr 4) and 0b00000111,
|
||||||
|
rcode: Rcode(toUint8(data[3]) and 0b00001111),
|
||||||
|
qdcount: toUint16(data[5], data[4]),
|
||||||
|
ancount: toUint16(data[7], data[6]),
|
||||||
|
nscount: toUint16(data[9], data[8]),
|
||||||
|
arcount: toUint16(data[11], data[10])
|
||||||
|
)
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsType* = enum
|
||||||
|
A = 1, NS = 2, MD =3, MF =4, CNAME = 5, SOA = 6, MB = 7, MG = 8,
|
||||||
|
MR = 9, NULL = 10, WKS = 11, PTR = 12, HINFO = 13, MINFO = 14, MX = 15,
|
||||||
|
TXT = 16, AXFR = 252, MAILB = 253, MAILA = 254, ANY = 255
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsClass* = enum
|
||||||
|
IN = 1, CS = 2, CH = 3, HS = 4
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsQuestion* = object
|
||||||
|
qname*: string
|
||||||
|
qtype*: DnsType
|
||||||
|
qclass*: DnsClass
|
||||||
|
|
||||||
|
proc parseQuestion*(data: string): (DnsQuestion, uint16) =
|
||||||
|
var qname: seq[string] = @[]
|
||||||
|
var len = toUint8(data[0])
|
||||||
|
var offset: uint16 = 1
|
||||||
|
|
||||||
|
while len > 0:
|
||||||
|
qname.add(data[offset .. offset + len - 1])
|
||||||
|
|
||||||
|
offset += len + 1
|
||||||
|
len = toUint8(data[offset - 1])
|
||||||
|
|
||||||
|
return (DnsQuestion(
|
||||||
|
qname: qname.join("."),
|
||||||
|
qtype: DnsType(toUint16(data[offset + 1], data[offset])),
|
||||||
|
qclass: DnsClass(toUint16(data[offset + 3], data[offset + 2]))
|
||||||
|
), offset + 4)
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsRecord* = object
|
||||||
|
name*: string
|
||||||
|
rtype*: DnsType
|
||||||
|
class*: DnsClass
|
||||||
|
ttl*: uint32
|
||||||
|
rdlength*: uint16
|
||||||
|
rdata: string
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsMessage* = object
|
||||||
|
header*: DnsHeader
|
||||||
|
questions*: seq[DnsQuestion]
|
||||||
|
answer*: seq[DnsRecord]
|
||||||
|
authroity*: seq[DnsRecord]
|
||||||
|
additional*: seq[DnsRecord]
|
|
@ -0,0 +1,9 @@
|
||||||
|
proc toUint8*(l: char): uint8 =
|
||||||
|
return ord(l).uint8
|
||||||
|
|
||||||
|
proc toUint16*(l: char, h: char): uint16 =
|
||||||
|
return ord(l).uint16 or (ord(h).uint16 shl 8);
|
||||||
|
|
||||||
|
proc sliceBit*(s: char, i: uint8): bool =
|
||||||
|
assert i < 8
|
||||||
|
return ((toUint8(s) shr (8 - i)) and 1) == 1
|
|
@ -0,0 +1,31 @@
|
||||||
|
import asyncnet, asyncdispatch, nativesockets, strutils, lib/dns
|
||||||
|
|
||||||
|
proc handleDnsRequest(data: string) =
|
||||||
|
let header = parseHeader(data[0 .. 11])
|
||||||
|
var questions: seq[DnsQuestion] = @[]
|
||||||
|
var offset = 12
|
||||||
|
|
||||||
|
for i in (1.uint32)..header.qdcount:
|
||||||
|
let (question, read) = parseQuestion(data[offset .. len(data) - 1])
|
||||||
|
questions.add(question)
|
||||||
|
offset += read.int
|
||||||
|
|
||||||
|
let msg = DnsMessage(header: header, questions: questions)
|
||||||
|
echo msg
|
||||||
|
|
||||||
|
proc serve() {.async.} =
|
||||||
|
let server = newAsyncSocket(sockType=SockType.SOCK_DGRAM, protocol=Protocol.IPPROTO_UDP, buffered = false)
|
||||||
|
server.setSockOpt(OptReuseAddr, true)
|
||||||
|
server.bindAddr(Port(12345))
|
||||||
|
|
||||||
|
while true:
|
||||||
|
echo "start loop"
|
||||||
|
let request = await server.recvFrom(size=512)
|
||||||
|
echo "received"
|
||||||
|
handleDnsRequest(request.data)
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
asyncCheck serve()
|
||||||
|
runForever()
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in New Issue