Skip to content

Commit d2abbe7

Browse files
committed
fixing warning messages when compiling; adding tests for parse; and now requires Nim 1.6.0 or higher
1 parent d449aa0 commit d2abbe7

File tree

3 files changed

+92
-74
lines changed

3 files changed

+92
-74
lines changed

dnsprotocol.nimble

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Package
22

3-
version = "0.2.0"
3+
version = "0.2.1"
44
author = "rockcavera"
55
description = "Domain Name System (DNS) protocol for Nim programming language"
66
license = "MIT"
@@ -10,4 +10,4 @@ srcDir = "src"
1010

1111
# Dependencies
1212

13-
requires "nim >= 1.4.0", "stew"
13+
requires "nim >= 1.6.0", "stew"

src/dnsprotocol.nim

Lines changed: 54 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,11 @@ proc initHeader*(id: uint16 = 0'u16, qr: QR = QR.Query,
131131
## create a `ResourceRecord` of type `Type.OPT`. This will be done
132132
## automatically if a `Message` object is initialized with the
133133
## `initMessage()` procedure.
134-
result.id = id
134+
let flags = Flags(qr: qr, opcode: opcode, aa: aa, tc: tc, rd: rd, ra: ra,
135+
rcode: rcode)
135136

136-
result.flags.qr = qr
137-
result.flags.opcode = opcode
138-
result.flags.aa = aa
139-
result.flags.tc = tc
140-
result.flags.rd = rd
141-
result.flags.ra = ra
142-
result.flags.rcode = rcode
143-
144-
result.qdcount = qdcount
145-
result.ancount = ancount
146-
result.nscount = nscount
147-
result.arcount = arcount
137+
Header(id: id, flags: flags, qdcount: qdcount, ancount: ancount,
138+
nscount: nscount, arcount: arcount)
148139

149140
proc initQuestion*(qname: string, qtype: QType, qclass: QClass = QClass.IN):
150141
Question =
@@ -162,13 +153,12 @@ proc initQuestion*(qname: string, qtype: QType, qclass: QClass = QClass.IN):
162153
## **Note**
163154
## - The last character of `qname` must always be a `'.'`. If not, it will be
164155
## added automatically.
165-
result.qname = qname
156+
var qname = qname
166157

167-
if 0 == len(result.qname) or '.' != result.qname[^1]:
168-
add(result.qname, '.')
158+
if 0 == len(qname) or '.' != qname[^1]:
159+
add(qname, '.')
169160

170-
result.qtype = qtype
171-
result.qclass = qclass
161+
Question(qname: qname, qtype: qtype, qclass: qclass)
172162

173163
proc initResourceRecord*(name: string, `type`: Type, class: Class, ttl: int32,
174164
rdlength: uint16, rdata: RDatas): ResourceRecord =
@@ -198,18 +188,16 @@ proc initResourceRecord*(name: string, `type`: Type, class: Class, ttl: int32,
198188
## - `rdata` can be initialized as `nil`, but it is not recommended.
199189
## - It must not be used to initialize a `ResourceRecord` of type `Type.OPT`.
200190
## To do this, use `initOptRR()<#initOptRR%2Cuint16%2Cuint8%2Cuint8%2Cbool%2Cuint16%2CRDataOPT>`_.
201-
doAssert(`type` != Type.OPT, "Use `initOptRR()` for `type` == `Type.OPT`")
191+
assert(`type` != Type.OPT, "Use `initOptRR()` for `type` == `Type.OPT`")
202192

203-
result.name = name
193+
var name = name
204194

205-
if 0 == len(result.name) or '.' != result.name[^1]:
206-
add(result.name, '.')
195+
if 0 == len(name) or '.' != name[^1]:
196+
add(name, '.')
207197

208-
result.`type` = `type`
209-
result.class = class
210-
result.ttl = ttl
211-
result.rdlength = rdlength
212-
result.rdata = rdata
198+
{.cast(uncheckedAssign).}:
199+
ResourceRecord(name: name, `type`: `type`, class: class, ttl: ttl,
200+
rdlength: rdlength, rdata: rdata)
213201

214202
proc initOptRR*(udpSize: uint16, extRCode: uint8, version: uint8, `do`: bool,
215203
rdlength: uint16, rdata: RDataOPT): ResourceRecord =
@@ -239,17 +227,9 @@ proc initOptRR*(udpSize: uint16, extRCode: uint8, version: uint8, `do`: bool,
239227
## - For more information about OPT RR visit `RFC-6891<https://www.rfc-editor.org/rfc/rfc6891>`_.
240228
## - `ResourceRecord.extRCode` can be changed if `Header.flags.rcode` passed
241229
## in `initMessage()` has its enumerator with different upper 8 bits.
242-
ResourceRecord(
243-
name: ".",
244-
`type`: Type.OPT,
245-
udpSize: udpSize,
246-
extRCode: extRCode,
247-
version: version,
248-
`do`: `do`,
249-
z: 0'u16,
250-
rdlength: rdlength,
251-
rdata: new(RDataOPT)
252-
)
230+
ResourceRecord(name: ".", `type`: Type.OPT, udpSize: udpSize,
231+
extRCode: extRCode, version: version, `do`: `do`, z: 0'u16,
232+
rdlength: rdlength, rdata: new(RDataOPT))
253233

254234
proc initMessage*(header: Header, questions: Questions = @[],
255235
answers: Answers = @[], authorities: Authorities = @[],
@@ -280,11 +260,8 @@ proc initMessage*(header: Header, questions: Questions = @[],
280260
## bits will be passed through a `ResourceRecord` of type `Type.OPT`. When
281261
## the `ResourceRecord` of type `Type.OPT` is not passed in `additionals`,
282262
## it will be created automatically.
283-
result.header = header
284-
result.questions = questions
285-
result.answers = answers
286-
result.authorities = authorities
287-
result.additionals = additionals
263+
result = Message(header: header, questions: questions, answers: answers,
264+
authorities: authorities, additionals: additionals)
288265

289266
let extRCode = uint8(uint16(result.header.flags.rcode) shr 4) # Will I need an OPT RR?
290267

@@ -446,7 +423,7 @@ proc toBinMsg*(msg: Message, isTcp: bool = false): BinMsg =
446423

447424
close(ss)
448425

449-
#{.push warning[HoleEnumConv]: off.} # supported as of Nim 1.6.0
426+
{.push warning[HoleEnumConv]: off.} # supported as of Nim 1.6.0
450427
proc parseHeader(header: var Header, ss: StringStream) =
451428
## Parses a header contained in `ss` and stores into `header`.
452429
header.id = readUInt16E(ss)
@@ -480,38 +457,39 @@ proc parseQuestion(question: var Question, ss: StringStream) =
480457

481458
question.qtype = QType(readUInt16E(ss)) # ignore compiler warning
482459
question.qclass = QClass(readUInt16E(ss)) # ignore compiler warning
483-
#{.pop.}
460+
{.pop.}
484461

485-
proc parseResourceRecord(rr: var ResourceRecord, ss: StringStream) =
462+
proc parseResourceRecord(ss: StringStream): ResourceRecord =
486463
## Parses a resource record contained in `ss` and stores into `rr`.
487-
parseDomainName(rr.name, ss)
464+
var name: string
465+
466+
parseDomainName(name, ss)
488467

489468
let `type` = cast[Type](readInt16E(ss)) # Prevents execution errors when certain Type are not implemented
490469

491470
case `type`
492471
of Type.OPT: # Parses an OPT RR
493-
rr = ResourceRecord(name: move rr.name,
494-
`type`: `type`,
495-
udpSize: readUInt16E(ss),
496-
extRCode: readUint8(ss),
497-
version: readUint8(ss),
498-
`do`: false,
499-
z: readUInt16E(ss),
500-
rdata: new(RDataOPT))
501-
rr.`do` = bool((rr.z and 0b1000000000000000) shr 15)
502-
rr.z = rr.z and 0b0111111111111111
472+
result = ResourceRecord(name: move name, `type`: `type`,
473+
udpSize: readUInt16E(ss), extRCode: readUint8(ss),
474+
version: readUint8(ss), `do`: false,
475+
z: readUInt16E(ss), rdlength: readUInt16E(ss),
476+
rdata: new(RDataOPT))
477+
result.`do` = bool((result.z and 0b1000000000000000) shr 15)
478+
result.z = result.z and 0b0111111111111111
503479
else:
504-
rr.`type` = `type`
505-
rr.class = cast[Class](readInt16E(ss)) # Prevents execution errors when certain Class are not implemented or when the RR is used differently from the ideal
506-
rr.ttl = readInt32E(ss)
480+
# {.cast(uncheckedAssign).}: # there was no need here
481+
# `class: cast[Class](readInt16E(ss)` is used to prevent execution errors when certain Classes are not implemented or when the RR is used in a way other than ideal
482+
result = ResourceRecord(name: move name, `type`: `type`,
483+
class: cast[Class](readInt16E(ss)),
484+
ttl: readInt32E(ss), rdlength: readUInt16E(ss),
485+
rdata: nil)
507486

508-
newRData(rr)
487+
newRData(result)
509488

510-
rr.rdlength = readUInt16E(ss)
511-
512-
if rr.rdlength > 0:
513-
parseRData(rr.rdata, rr, ss)
489+
if result.rdlength > 0:
490+
parseRData(result.rdata, result, ss)
514491

492+
{.push warning[HoleEnumConv]: off.}
515493
proc parseMessage*(bmsg: BinMsg): Message =
516494
## Parses a binary DNS protocol message contained in `bmsg`.
517495
var ss = newStringStream(bmsg)
@@ -523,22 +501,26 @@ proc parseMessage*(bmsg: BinMsg): Message =
523501
for i in 0'u16 ..< result.header.qdcount:
524502
parseQuestion(result.questions[i], ss)
525503

526-
setLen(result.answers, result.header.ancount)
504+
result.answers = newSeqOfCap[ResourceRecord](result.header.ancount)
527505

528506
for i in 0'u16 ..< result.header.ancount:
529-
parseResourceRecord(result.answers[i], ss)
507+
add(result.answers, parseResourceRecord(ss))
530508

531-
setLen(result.authorities, result.header.nscount)
509+
result.authorities = newSeqOfCap[ResourceRecord](result.header.nscount)
532510

533511
for i in 0'u16 ..< result.header.nscount:
534-
parseResourceRecord(result.authorities[i], ss)
512+
add(result.authorities, parseResourceRecord(ss))
535513

536-
setLen(result.additionals, result.header.arcount)
514+
result.additionals = newSeqOfCap[ResourceRecord](result.header.arcount)
537515

538516
for i in 0'u16 ..< result.header.arcount:
539-
parseResourceRecord(result.additionals[i], ss)
517+
add(result.additionals, parseResourceRecord(ss))
540518

541519
if result.additionals[i].`type` == Type.OPT:
542-
result.header.flags.rcode = RCode(int(result.additionals[i].extRCode shl 4) or ord(result.header.flags.rcode))
520+
let rcode = RCode(int(result.additionals[i].extRCode shl 4) or
521+
ord(result.header.flags.rcode)) # ignore compiler warning
522+
523+
result.header.flags.rcode = rcode
543524

544525
close(ss)
526+
{.pop.}

tests/tdnsprotocol.nim

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ const
99
strRResourceRecord1 = "\xc0\x0c\x00\x01\x00\x01\x00\x00\x01\x2c\x00\x04\xac\x43\x84\xf2"
1010
strRResourceRecord2 = "\xc0\x0c\x00\x01\x00\x01\x00\x00\x01\x2c\x00\x04\x68\x15\x05\x2a"
1111

12+
proc `==`(a, b: ResourceRecord): bool =
13+
if a.`type` == b.`type` and a.name == b.name and a.rdlength == b.rdlength and
14+
cmpMem(addr a.rdata[], addr b.rdata[], a.rdlength) == 0:
15+
case a.`type`
16+
of Type.OPT:
17+
result = a.udpSize == b.udpSize and a.extRCode == b.extRCode and
18+
a.version == b.version and a.`do` == b.`do` and a.z == b.z
19+
else:
20+
result = a.class == b.class and a.ttl == b.ttl
21+
1222
suite "Query A IN":
1323
let
1424
header = initHeader(1'u16, QR.Query, OpCode.Query, false, false, true, false, RCode.NoError, 1'u16, 0'u16, 0'u16, 0'u16)
@@ -40,6 +50,18 @@ suite "Query A IN":
4050

4151
check(bmsg == ("\x00\x1E" & strQHeader & strQuestion))
4252

53+
test "Parse to Message":
54+
let
55+
msg = parseMessage(strQHeader & strQuestion)
56+
tmsg = initMessage(header, @[question])
57+
58+
check(msg.header == tmsg.header)
59+
check(len(msg.questions) == 1)
60+
check(msg.questions[0] == tmsg.questions[0])
61+
check(len(msg.answers) == 0)
62+
check(len(msg.authorities) == 0)
63+
check(len(msg.additionals) == 0)
64+
4365
suite "Query Response A IN":
4466
let
4567
header = initHeader(1'u16, QR.Response, OpCode.Query, false, false, true, true, RCode.NoError, 1'u16, 2'u16, 0'u16, 0'u16)
@@ -75,3 +97,17 @@ suite "Query Response A IN":
7597
let bmsg = toBinMsg(initMessage(header, @[question], @[rr1, rr2]), true)
7698

7799
check(bmsg == ("\x00\x3E" & strRHeader & strQuestion & strRResourceRecord1 & strRResourceRecord2))
100+
101+
test "Parse to Message":
102+
let
103+
msg = parseMessage(strRHeader & strQuestion & strRResourceRecord1 & strRResourceRecord2)
104+
tmsg = initMessage(header, @[question], @[rr1, rr2])
105+
106+
check(msg.header == tmsg.header)
107+
check(len(msg.questions) == 1)
108+
check(msg.questions[0] == tmsg.questions[0])
109+
check(len(msg.answers) == 2)
110+
check(msg.answers[0] == tmsg.answers[0])
111+
check(msg.answers[1] == tmsg.answers[1])
112+
check(len(msg.authorities) == 0)
113+
check(len(msg.additionals) == 0)

0 commit comments

Comments
 (0)