diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 70615203..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "src/omg-dns"]
- path = src/omg-dns
- url = https://github.com/DNS-OARC/omg-dns.git
diff --git a/README.md b/README.md
index 918625d2..1c510039 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,6 @@ OpenBSD: `pkg_add luajit` + manual install of libpcap, liblmdb and libck
```shell
git clone https://github.com/DNS-OARC/dnsjit
cd dnsjit
-git submodule update --init
sh autogen.sh
./configure
make
@@ -98,6 +97,7 @@ Following example display the DNS ID found in queries.
require("dnsjit.core.objects")
local input = require("dnsjit.input.pcap").new()
local layer = require("dnsjit.filter.layer").new()
+local dns = require("dnsjit.core.object.dns").new()
input:open_offline(arg[2])
layer:producer(input)
@@ -107,8 +107,8 @@ while true do
local object = producer(ctx)
if object == nil then break end
if object:type() == "payload" then
- local dns = require("dnsjit.core.object.dns").new(object)
- if dns and dns:parse() == 0 then
+ dns.obj_prev = object
+ if dns:parse_header() == 0 then
print(dns.id)
end
end
diff --git a/configure.ac b/configure.ac
index 34342556..bfd1c05d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,7 +51,7 @@ AC_HEADER_TIME
AX_PTHREAD
AC_CHECK_LIB([pcap], [pcap_open_live], [], [AC_MSG_ERROR([libpcap not found])])
AC_CHECK_HEADER([pcap/pcap.h], [], [AC_MSG_ERROR([libpcap header not found])])
-AC_CHECK_HEADERS([endian.h sys/endian.h machine/endian.h sys/time.h])
+AC_CHECK_HEADERS([endian.h sys/endian.h machine/endian.h sys/time.h byteswap.h])
AC_CHECK_FUNCS([pcap_create pcap_set_tstamp_precision pcap_set_immediate_mode])
AC_CHECK_FUNCS([pcap_set_tstamp_type pcap_setdirection sched_yield])
AC_CHECK_FUNCS([pcap_open_offline_with_tstamp_precision pcap_activate])
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 15e2937d..a91ea3fa 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -16,5 +16,5 @@
# You should have received a copy of the GNU General Public License
# along with dnsjit. If not, see .
-dist_doc_DATA = dumpdns.lua dumpdns-qr.lua filter_rcode.lua playqr.lua \
+dist_doc_DATA = dumpdns.lua dumpdns-qr.lua filter_rcode.lua respdiff.lua \
readme.lua replay.lua test_pcap_read.lua test_throughput.lua
diff --git a/examples/dumpdns-qr.lua b/examples/dumpdns-qr.lua
index 4af05de6..e2fe52ec 100755
--- a/examples/dumpdns-qr.lua
+++ b/examples/dumpdns-qr.lua
@@ -9,6 +9,12 @@ end
local object = require("dnsjit.core.objects")
local input = require("dnsjit.input.pcap").new()
local layer = require("dnsjit.filter.layer").new()
+local dns = require("dnsjit.core.object.dns").new()
+local label = require("dnsjit.core.object.dns.label")
+
+local ffi = require("ffi")
+local labels = require("dnsjit.core.object.dns.label").new(16)
+local q = require("dnsjit.core.object.dns.q").new()
input:open_offline(pcap)
layer:producer(input)
@@ -20,24 +26,25 @@ local responses = {}
while true do
local obj = producer(ctx)
if obj == nil then break end
- if obj:type() == "payload" then
+ local pl = obj:cast()
+ if obj:type() == "payload" and pl.len > 0 then
local transport = obj.obj_prev
while transport do
- if transport.obj_type == object.CORE_OBJECT_IP or transport.obj_type == object.CORE_OBJECT_IP6 then
+ if transport.obj_type == object.IP or transport.obj_type == object.IP6 then
break
end
transport = transport.obj_prev
end
local protocol = obj.obj_prev
while protocol do
- if protocol.obj_type == object.CORE_OBJECT_UDP or protocol.obj_type == object.CORE_OBJECT_TCP then
+ if protocol.obj_type == object.UDP or protocol.obj_type == object.TCP then
break
end
protocol = protocol.obj_prev
end
- local dns = require("dnsjit.core.object.dns").new(obj)
- if transport and protocol and dns and dns:parse() == 0 then
+ dns.obj_prev = obj
+ if transport and protocol and dns:parse_header() == 0 then
transport = transport:cast()
protocol = protocol:cast()
@@ -48,18 +55,18 @@ while true do
dst = transport:destination(),
dport = protocol.dport,
id = dns.id,
- rcode = dns.rcode,
+ rcode = dns.rcode_tostring(dns.rcode),
})
else
- if dns.questions > 0 and dns:rr_next() == 0 and dns:rr_ok() then
+ if dns.qdcount > 0 and dns:parse_q(q, labels, 16) == 0 then
table.insert(queries, {
src = transport:source(),
sport = protocol.sport,
dst = transport:destination(),
dport = protocol.dport,
id = dns.id,
- qname = dns:rr_label(),
- qtype = dns:rr_type(),
+ qname = label.tooffstr(dns, labels, 16),
+ qtype = dns.type_tostring(q.type)
})
end
end
diff --git a/examples/dumpdns.lua b/examples/dumpdns.lua
index 965d9634..3092eb9f 100755
--- a/examples/dumpdns.lua
+++ b/examples/dumpdns.lua
@@ -9,6 +9,7 @@ end
local object = require("dnsjit.core.objects")
local input = require("dnsjit.input.pcap").new()
local layer = require("dnsjit.filter.layer").new()
+local dns = require("dnsjit.core.object.dns").new()
input:open_offline(pcap)
layer:producer(input)
@@ -17,24 +18,25 @@ local producer, ctx = layer:produce()
while true do
local obj = producer(ctx)
if obj == nil then break end
- if obj:type() == "payload" then
+ local pl = obj:cast()
+ if obj:type() == "payload" and pl.len > 0 then
local transport = obj.obj_prev
while transport do
- if transport.obj_type == object.CORE_OBJECT_IP or transport.obj_type == object.CORE_OBJECT_IP6 then
+ if transport.obj_type == object.IP or transport.obj_type == object.IP6 then
break
end
transport = transport.obj_prev
end
local protocol = obj.obj_prev
while protocol do
- if protocol.obj_type == object.CORE_OBJECT_UDP or protocol.obj_type == object.CORE_OBJECT_TCP then
+ if protocol.obj_type == object.UDP or protocol.obj_type == object.TCP then
break
end
protocol = protocol.obj_prev
end
- local dns = require("dnsjit.core.object.dns").new(obj)
- if transport and protocol and dns and dns:parse() == 0 then
+ dns.obj_prev = obj
+ if transport and protocol then
transport = transport:cast()
protocol = protocol:cast()
print(protocol:type().." "..transport:source()..":"..tonumber(protocol.sport).." -> "..transport:destination()..":"..tonumber(protocol.dport))
diff --git a/examples/filter_rcode.lua b/examples/filter_rcode.lua
index 56803abc..eafe725d 100755
--- a/examples/filter_rcode.lua
+++ b/examples/filter_rcode.lua
@@ -10,6 +10,7 @@ end
local object = require("dnsjit.core.objects")
local input = require("dnsjit.input.pcap").new()
local layer = require("dnsjit.filter.layer").new()
+local dns = require("dnsjit.core.object.dns").new()
input:open_offline(pcap)
layer:producer(input)
@@ -18,17 +19,18 @@ local producer, ctx = layer:produce()
while true do
local obj = producer(ctx)
if obj == nil then break end
- if obj:type() == "payload" then
+ local pl = obj:cast()
+ if obj:type() == "payload" and pl.len > 0 then
local transport = obj.obj_prev
while transport do
- if transport.obj_type == object.CORE_OBJECT_IP or transport.obj_type == object.CORE_OBJECT_IP6 then
+ if transport.obj_type == object.IP or transport.obj_type == object.IP6 then
break
end
transport = transport.obj_prev
end
- local dns = require("dnsjit.core.object.dns").new(obj)
- if transport and dns and dns:parse() == 0 and dns.have_rcode == 1 and dns.rcode == rcode then
+ dns.obj_prev = obj
+ if transport and dns and dns:parse_header() == 0 and dns.have_rcode == 1 and dns.rcode == rcode then
transport = transport:cast()
print(dns.id, transport:source().." -> "..transport:destination())
end
diff --git a/examples/playqr.lua b/examples/playqr.lua
deleted file mode 100755
index 1693b9b9..00000000
--- a/examples/playqr.lua
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/env dnsjit
-local ffi = require("ffi")
-local clock = require("dnsjit.lib.clock")
-local log = require("dnsjit.core.log")
-log.display_file_line(true)
-local getopt = require("dnsjit.lib.getopt").new({
- { "v", "verbose", 0, "Enable and increase verbosity for each time given", "?+" },
- { "m", "match", false, "Group query with response from the PCAP and match it against the received response", "?" },
- { nil, "respdiff", "", "Use output.respdiff to write out query, original and received response to the specified LMDB path", "?" },
- { nil, "respdiff-origname", "", "The name of the server in respdiff.cfg for the original responses", "?" },
- { nil, "respdiff-recvname", "", "The name of the server in respdiff.cfg for the received responses", "?" },
-})
-local pcap, host, port = unpack(getopt:parse())
-if getopt:val("help") then
- getopt:usage()
- return
-end
-local v = getopt:val("v")
-if v > 0 then
- log.enable("warning")
-end
-if v > 1 then
- log.enable("notice")
-end
-if v > 2 then
- log.enable("info")
-end
-if v > 3 then
- log.enable("debug")
-end
-
-if pcap == nil or host == nil or port == nil then
- print("usage: "..arg[1].." ")
- return
-end
-
-local object = require("dnsjit.core.objects")
-
-local matchcfg = {
- opcode = 1,
- qtype = 1,
- qname = 1,
- qcase = 1,
- flags = 1,
- rcode = 1,
- question = 1,
- answer = 1,
- ttl = 1,
- answertypes = 1,
- answerrrsigs = 1,
- authority = 1,
- additional = 1,
- edns = 1,
- nsid = 1,
-}
-
-function tohex(p, l)
- local o, n = "", 0
- for n = 0, l do
- o = o .. string.format("%02x", p[n])
- end
- return o
-end
-
-function extract(dns)
- local data = {
- flags = {},
- flags_str = "",
- questions = {},
- answers = {},
- authorities = {},
- additionals = {}
- }
-
- if dns.have_aa and dns.aa == 1 then
- table.insert(data.flags, "AA")
- end
- if dns.have_tc and dns.tc == 1 then
- table.insert(data.flags, "TC")
- end
- if dns.have_rd and dns.rd == 1 then
- table.insert(data.flags, "RD")
- end
- if dns.have_ra and dns.ra == 1 then
- table.insert(data.flags, "RA")
- end
- if dns.have_z and dns.z == 1 then
- table.insert(data.flags, "Z")
- end
- if dns.have_ad and dns.ad == 1 then
- table.insert(data.flags, "AD")
- end
- if dns.have_cd and dns.cd == 1 then
- table.insert(data.flags, "CD")
- end
- data.flags_str = table.concat(data.flags, " ")
-
- local n = dns.questions
- while n > 0 and dns:rr_next() == 0 do
- if dns:rr_ok() == 1 then
- table.insert(data.questions, {
- class = dns:rr_class(),
- type = dns:rr_type(),
- label = dns:rr_label()
- })
- end
- n = n - 1
- end
- n = dns.answers
- while n > 0 and dns:rr_next() == 0 do
- if dns:rr_ok() == 1 then
- table.insert(data.answers, {
- class = dns:rr_class(),
- type = dns:rr_type(),
- ttl = dns:rr_ttl(),
- label = dns:rr_label()
- })
- end
- n = n - 1
- end
- n = dns.authorities
- while n > 0 and dns:rr_next() == 0 do
- if dns:rr_ok() == 1 then
- table.insert(data.authorities, {
- class = dns:rr_class(),
- type = dns:rr_type(),
- ttl = dns:rr_ttl(),
- label = dns:rr_label()
- })
- end
- n = n - 1
- end
- n = dns.additionals
- while n > 0 and dns:rr_next() == 0 do
- if dns:rr_ok() == 1 then
- table.insert(data.additionals, {
- class = dns:rr_class(),
- type = dns:rr_type(),
- ttl = dns:rr_ttl(),
- label = dns:rr_label()
- })
- end
- n = n - 1
- end
-
- return data
-end
-
-function compare_val(name, exp, got)
- if exp == nil or got == nil or exp ~= got then
- return name.." missmatch, exp != got: " .. string.format("%s != %s", exp, got)
- end
-end
-
-function compare_rrs_label(name, exp, got)
- local e, g
- if exp == nil then
- return { name.." missmatch, exp != got: exp is nil" }
- end
- if got == nil then
- return { name.." missmatch, exp != got: got is nil" }
- end
- local results = {}
- for _, e in pairs(exp) do
- local found = false
- for _, g in pairs(got) do
- if g.label == e.label then
- found = true
- break
- end
- end
- if not found then
- results[e.label] = name.." missmatch, exp != got: missing label " .. e.label
- end
- end
- for _, g in pairs(got) do
- local found = false
- for _, e in pairs(exp) do
- if e.label == g.label then
- found = true
- break
- end
- end
- if not found then
- results[g.label] = name.." missmatch, exp != got: got extra label " .. g.label
- end
- end
- return results
-end
-
-function compare_rrs_type(name, exp, got)
- local e, g
- if exp == nil then
- return { name.." missmatch, exp != got: exp is nil" }
- end
- if got == nil then
- return { name.." missmatch, exp != got: got is nil" }
- end
- local results = {}
- for _, e in pairs(exp) do
- local found = false
- for _, g in pairs(got) do
- if g.type == e.type then
- found = true
- break
- end
- end
- if not found then
- results[e.type] = name.." missmatch, exp != got: missing type " .. e.type
- end
- end
- for _, g in pairs(got) do
- local found = false
- for _, e in pairs(exp) do
- if e.type == g.type then
- found = true
- break
- end
- end
- if not found then
- results[g.type] = name.." missmatch, exp != got: got extra type " .. g.type
- end
- end
- return results
-end
-
-function match(orig, resp)
- local results = {}
- local orig_data = extract(orig)
- local resp_data = extract(resp)
-
- if matchcfg.opcode == 1 then
- local result = compare_val("opcode", orig.opcode, resp.opcode)
- if result then
- table.insert(results, result)
- end
- end
- if matchcfg.qtype == 1 then
- local orig_val, resp_val
- if orig_data and orig_data.questions[1] then
- orig_val = orig_data.questions[1].type
- end
- if resp_data and resp_data.questions[1] then
- resp_val = resp_data.questions[1].type
- end
- local result = compare_val("qtype", orig_val, resp_val)
- if result then
- table.insert(results, result)
- end
- end
- if matchcfg.qname == 1 then
- local orig_val, resp_val
- if orig_data and orig_data.questions[1] then
- orig_val = orig_data.questions[1].label
- end
- if resp_data and resp_data.questions[1] then
- resp_val = resp_data.questions[1].label
- end
- local result = compare_val("qname", orig_val, resp_val)
- if result then
- table.insert(results, result)
- end
- end
- -- TODO qcase
- if matchcfg.flags == 1 then
- local result = compare_val("flags", orig_data.flags_str, resp_data.flags_str)
- if result then
- table.insert(results, result)
- end
- end
- if matchcfg.rcode == 1 then
- local result = compare_val("rcode", orig.rcode, resp.rcode)
- if result then
- table.insert(results, result)
- end
- end
- if matchcfg.question == 1 then
- local results2 = compare_rrs_label("question", orig_data.questions, resp_data.questions)
- local result
- for _, result in pairs(results2) do
- table.insert(results, result)
- end
- end
- if matchcfg.answer == 1 or matchcfg.ttl == 1 then
- local results2 = compare_rrs_label("answer", orig_data.answers, resp_data.answers)
- local result
- for _, result in pairs(results2) do
- table.insert(results, result)
- end
- end
- if matchcfg.answertypes == 1 or matchcfg.ttl == 1 then
- local results2 = compare_rrs_type("answertypes", orig_data.answers, resp_data.answers)
- local result
- for _, result in pairs(results2) do
- table.insert(results, result)
- end
- end
- -- TODO answerrrsigs
- if matchcfg.authority == 1 then
- local results2 = compare_rrs_label("authority", orig_data.authorities, resp_data.authorities)
- local result
- for _, result in pairs(results2) do
- table.insert(results, result)
- end
- end
- if matchcfg.additional == 1 then
- local results2 = compare_rrs_label("additional", orig_data.additionals, resp_data.additionals)
- local result
- for _, result in pairs(results2) do
- table.insert(results, result)
- end
- end
- -- TODO edns
- -- TODO nsid
-
- return results
-end
-
-local input = require("dnsjit.input.mmpcap").new()
-input:open(pcap)
-local layer = require("dnsjit.filter.layer").new()
-layer:producer(input)
-
-local udpcli, tcpcli
-local udprecv, udpctx, tcprecv, tcpctx
-local udpprod, tcpprod
-
-local prod, pctx = layer:produce()
-local queries = {}
-local clipayload = ffi.new("core_object_payload_t")
-clipayload.obj_type = object.CORE_OBJECT_PAYLOAD
-local cliobject = ffi.cast("core_object_t*", clipayload)
-
-local respdiff, resprecv, respctx, query_payload, original_payload, response_payload, query_payload_obj
-if getopt:val("respdiff") > "" then
- if getopt:val("respdiff-origname") == "" or getopt:val("respdiff-recvname") == "" then
- print("To use respdiff both server names for original (--respdiff-origname) and")
- print("received responses (--respdiff-recvname) must be specified!")
- os.exit(1)
- end
- respdiff = require("dnsjit.output.respdiff").new(getopt:val("respdiff"), getopt:val("respdiff-origname"), getopt:val("respdiff-recvname"))
- resprecv, respctx = respdiff:receive()
- query_payload, original_payload, response_payload = ffi.new("core_object_payload_t"), ffi.new("core_object_payload_t"), ffi.new("core_object_payload_t")
- query_payload.obj_type = object.CORE_OBJECT_PAYLOAD
- original_payload.obj_type = object.CORE_OBJECT_PAYLOAD
- response_payload.obj_type = object.CORE_OBJECT_PAYLOAD
- query_payload_obj = ffi.cast("core_object_t*", query_payload)
- query_payload.obj_prev = ffi.cast("core_object_t*", original_payload)
- original_payload.obj_prev = ffi.cast("core_object_t*", response_payload)
-end
-
-if getopt:val("m") then
- print("id", "qname", "qclass", "qtype", "result")
-end
-
-local start_sec, start_nsec = clock:realtime()
-while true do
- local obj = prod(pctx)
- if obj == nil then
- break
- end
- if obj:type() == "payload" then
- local dns = require("dnsjit.core.object.dns").new(obj)
- if dns and dns:parse() == 0 then
- local ip, proto, payload = obj, obj, obj:cast()
- while ip ~= nil and ip:type() ~= "ip" and ip:type() ~= "ip6" do
- ip = ip.obj_prev
- end
- while proto ~= nil and proto:type() ~= "udp" and proto:type() ~= "tcp" do
- proto = proto.obj_prev
- end
- if ip ~= nil and proto ~= nil then
- ip = ip:cast()
- proto = proto:cast()
- if dns.qr == 0 then
- local k = string.format("%s %d %s %d", ip:source(), proto.sport, ip:destination(), proto.dport)
- local qname, qtype, qclass
- local n = dns.questions
- if n > 0 and dns:rr_next() == 0 then
- if dns:rr_ok() == 1 then
- qname = dns:rr_label()
- qtype = dns:rr_type()
- qclass = dns:rr_class()
- end
- end
- if qname and qtype and qclass then
- local q = {
- id = dns.id,
- qname = qname,
- qtype = qtype,
- qclass = qclass,
- proto = proto:type(),
- payload = ffi.new("uint8_t[?]", payload.len),
- len = tonumber(payload.len)
- }
- ffi.copy(q.payload, payload.payload, payload.len)
- queries[k] = q
- end
- else
- local k = string.format("%s %d %s %d", ip:destination(), proto.dport, ip:source(), proto.sport)
- local q = queries[k]
- if q then
- queries[k] = nil
- clipayload.payload = q.payload
- clipayload.len = q.len
-
- local responses, response = {}, nil
- if q.proto == "udp" then
- if not udpcli then
- udpcli = require("dnsjit.output.udpcli").new()
- udpcli:connect(host, port)
- udprecv, udpctx = udpcli:receive()
- udpprod, _ = udpcli:produce()
- end
- udprecv(udpctx, cliobject)
- while response == nil do
- response = udpprod(udpctx)
- end
- while response ~= nil do
- table.insert(responses, response)
- response = udpprod(udpctx)
- end
- elseif q.proto == "tcp" then
- if not tcpcli then
- tcpcli = require("dnsjit.output.tcpcli").new()
- tcpcli:connect(host, port)
- tcprecv, tcpctx = tcpcli:receive()
- tcpprod, _ = tcpcli:produce()
- end
- tcprecv(tcpctx, cliobject)
- while response == nil do
- response = tcpprod(tcpctx)
- end
- while response ~= nil do
- table.insert(responses, response)
- response = tcpprod(tcpctx)
- end
- end
-
- local results, dns_response
- for _, response in pairs(responses) do
- dns_response = require("dnsjit.core.object.dns").new(response)
- if dns_response and dns_response:parse() == 0 and dns_response.id == q.id then
- if getopt:val("m") then
- results = match(dns, dns_response)
- end
-
- if respdiff then
- query_payload.payload = q.payload
- query_payload.len = q.len
- original_payload.payload = payload.payload
- original_payload.len = payload.len
- response = response:cast()
- response_payload.payload = response.payload
- response_payload.len = response.len
-
- resprecv(respctx, query_payload_obj)
- end
-
- break
- end
- end
- if getopt:val("m") then
- if results[1] then
- print(dns.id, q.qname, q.qclass, q.qtype, "failed")
- for _, v in pairs(results) do
- print("", v)
- end
- else
- print(dns.id, q.qname, q.qclass, q.qtype, "ok")
- end
- end
- end
- end
- end
- end
- end
-end
-local end_sec, end_nsec = clock:realtime()
-if respdiff then
- respdiff:commit(start_sec, end_sec)
-end
diff --git a/examples/readme.lua b/examples/readme.lua
index bb50503d..dc6de890 100755
--- a/examples/readme.lua
+++ b/examples/readme.lua
@@ -2,6 +2,7 @@
require("dnsjit.core.objects")
local input = require("dnsjit.input.pcap").new()
local layer = require("dnsjit.filter.layer").new()
+local dns = require("dnsjit.core.object.dns").new()
input:open_offline(arg[2])
layer:producer(input)
@@ -11,8 +12,8 @@ while true do
local object = producer(ctx)
if object == nil then break end
if object:type() == "payload" then
- local dns = require("dnsjit.core.object.dns").new(object)
- if dns and dns:parse() == 0 then
+ dns.obj_prev = object
+ if dns:parse_header() == 0 then
print(dns.id)
end
end
diff --git a/examples/replay.lua b/examples/replay.lua
index 382a1301..f78a77ef 100755
--- a/examples/replay.lua
+++ b/examples/replay.lua
@@ -38,6 +38,8 @@ local output = require("dnsjit.output.udpcli").new()
if getopt:val("t") then
output = require("dnsjit.output.tcpcli").new()
end
+require("dnsjit.core.objects")
+local dns = require("dnsjit.core.object.dns").new()
input:open(pcap)
layer:producer(input)
@@ -56,9 +58,10 @@ if printdns then
while true do
local obj = prod(pctx)
if obj == nil then break end
- if obj:type() == "payload" then
- local dns = require("dnsjit.core.object.dns").new(obj)
- if dns and dns:parse_header() == 0 and dns.qr == 0 and dns:parse() == 0 then
+ local pl = obj:cast()
+ if obj:type() == "payload" and pl.len > 0 then
+ dns.obj_prev = obj
+ if dns:parse_header() == 0 and dns.qr == 0 then
print("query:")
dns:print()
@@ -69,11 +72,9 @@ if printdns then
resp = oprod(opctx)
end
while resp ~= nil do
- local dns = require("dnsjit.core.object.dns").new(resp)
- if dns and dns:parse() == 0 then
- print("response:")
- dns:print()
- end
+ dns.obj_prev = resp
+ print("response:")
+ dns:print()
resp = oprod(opctx)
end
end
@@ -83,9 +84,10 @@ else
while true do
local obj = prod(pctx)
if obj == nil then break end
- if obj:type() == "payload" then
- local dns = require("dnsjit.core.object.dns").new(obj)
- if dns and dns:parse_header() == 0 and dns.qr == 0 then
+ local pl = obj:cast()
+ if obj:type() == "payload" and pl.len > 0 then
+ dns.obj_prev = obj
+ if dns:parse_header() == 0 and dns.qr == 0 then
recv(rctx, obj)
end
end
diff --git a/examples/respdiff.lua b/examples/respdiff.lua
new file mode 100755
index 00000000..509730c2
--- /dev/null
+++ b/examples/respdiff.lua
@@ -0,0 +1,160 @@
+#!/usr/bin/env dnsjit
+local ffi = require("ffi")
+local clock = require("dnsjit.lib.clock")
+local log = require("dnsjit.core.log")
+log.display_file_line(true)
+local getopt = require("dnsjit.lib.getopt").new({
+ { "v", "verbose", 0, "Enable and increase verbosity for each time given", "?+" },
+})
+local pcap, host, port, path, origname, recvname = unpack(getopt:parse())
+if getopt:val("help") then
+ getopt:usage()
+ return
+end
+local v = getopt:val("v")
+if v > 0 then
+ log.enable("warning")
+end
+if v > 1 then
+ log.enable("notice")
+end
+if v > 2 then
+ log.enable("info")
+end
+if v > 3 then
+ log.enable("debug")
+end
+
+if pcap == nil or host == nil or port == nil or path == nil or origname == nil or recvname == nil then
+ print("usage: "..arg[1].." ")
+ return
+end
+
+local object = require("dnsjit.core.objects")
+local dns = require("dnsjit.core.object.dns").new()
+local input = require("dnsjit.input.mmpcap").new()
+input:open(pcap)
+local layer = require("dnsjit.filter.layer").new()
+layer:producer(input)
+
+local udpcli, tcpcli
+local udprecv, udpctx, tcprecv, tcpctx
+local udpprod, tcpprod
+
+local prod, pctx = layer:produce()
+local queries = {}
+local clipayload = ffi.new("core_object_payload_t")
+clipayload.obj_type = object.PAYLOAD
+local cliobject = ffi.cast("core_object_t*", clipayload)
+
+local respdiff = require("dnsjit.output.respdiff").new(path, origname, recvname)
+local resprecv, respctx = respdiff:receive()
+local query_payload, original_payload, response_payload = ffi.new("core_object_payload_t"), ffi.new("core_object_payload_t"), ffi.new("core_object_payload_t")
+query_payload.obj_type = object.PAYLOAD
+original_payload.obj_type = object.PAYLOAD
+response_payload.obj_type = object.PAYLOAD
+local query_payload_obj = ffi.cast("core_object_t*", query_payload)
+query_payload.obj_prev = ffi.cast("core_object_t*", original_payload)
+original_payload.obj_prev = ffi.cast("core_object_t*", response_payload)
+
+local start_sec, start_nsec = clock:realtime()
+while true do
+ local obj = prod(pctx)
+ if obj == nil then break end
+ local payload = obj:cast()
+ if obj:type() == "payload" and payload.len > 0 then
+ dns.obj_prev = obj
+ if dns:parse_header() == 0 then
+ local transport = obj.obj_prev
+ while transport do
+ if transport.obj_type == object.IP or transport.obj_type == object.IP6 then
+ break
+ end
+ transport = transport.obj_prev
+ end
+ local protocol = obj.obj_prev
+ while protocol do
+ if protocol.obj_type == object.UDP or protocol.obj_type == object.TCP then
+ break
+ end
+ protocol = protocol.obj_prev
+ end
+
+ if transport and protocol then
+ transport = transport:cast()
+ protocol = protocol:cast()
+
+ if dns.qr == 0 then
+ local k = string.format("%s %d %s %d", transport:source(), protocol.sport, transport:destination(), protocol.dport)
+ local q = {
+ id = dns.id,
+ proto = protocol:type(),
+ payload = ffi.new("uint8_t[?]", payload.len),
+ len = tonumber(payload.len)
+ }
+ ffi.copy(q.payload, payload.payload, payload.len)
+ queries[k] = q
+ else
+ local k = string.format("%s %d %s %d", transport:destination(), protocol.dport, transport:source(), protocol.sport)
+ local q = queries[k]
+ if q then
+ queries[k] = nil
+ clipayload.payload = q.payload
+ clipayload.len = q.len
+
+ local responses, response = {}, nil
+ if q.proto == "udp" then
+ if not udpcli then
+ udpcli = require("dnsjit.output.udpcli").new()
+ udpcli:connect(host, port)
+ udprecv, udpctx = udpcli:receive()
+ udpprod, _ = udpcli:produce()
+ end
+ udprecv(udpctx, cliobject)
+ while response == nil do
+ response = udpprod(udpctx)
+ end
+ while response ~= nil do
+ table.insert(responses, response)
+ response = udpprod(udpctx)
+ end
+ elseif q.proto == "tcp" then
+ if not tcpcli then
+ tcpcli = require("dnsjit.output.tcpcli").new()
+ tcpcli:connect(host, port)
+ tcprecv, tcpctx = tcpcli:receive()
+ tcpprod, _ = tcpcli:produce()
+ end
+ tcprecv(tcpctx, cliobject)
+ while response == nil do
+ response = tcpprod(tcpctx)
+ end
+ while response ~= nil do
+ table.insert(responses, response)
+ response = tcpprod(tcpctx)
+ end
+ end
+
+ for _, response in pairs(responses) do
+ dns.obj_prev = response
+ if dns:parse_header() == 0 and dns.id == q.id then
+ query_payload.payload = q.payload
+ query_payload.len = q.len
+ original_payload.payload = payload.payload
+ original_payload.len = payload.len
+ response = response:cast()
+ response_payload.payload = response.payload
+ response_payload.len = response.len
+
+ resprecv(respctx, query_payload_obj)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+local end_sec, end_nsec = clock:realtime()
+
+respdiff:commit(start_sec, end_sec)
diff --git a/examples/test_throughput.lua b/examples/test_throughput.lua
index c336f971..b05c9837 100755
--- a/examples/test_throughput.lua
+++ b/examples/test_throughput.lua
@@ -66,7 +66,7 @@ for run = 1, runs do
local o = require("dnsjit.output.null").new()
local recv, rctx = o:receive()
local pkt = ffi.new("core_object_null_t")
- pkt.obj_type = object.CORE_OBJECT_NULL
+ pkt.obj_type = object.NULL
local obj = ffi.cast("core_object_t*", pkt)
local start_sec, start_nsec = clock:monotonic()
diff --git a/src/Makefile.am b/src/Makefile.am
index 430d7ba6..1fe45380 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,10 +33,9 @@ BUILT_SOURCES = core/compat.hh core/log_errstr.c
bin_PROGRAMS = dnsjit
-dnsjit_SOURCES = dnsjit.c globals.c \
- omg-dns/omg_dns.c
-dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h output.lua \
- omg-dns/omg_dns.h
+dnsjit_SOURCES = dnsjit.c globals.c
+dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h \
+ output.lua
lua_hobjects = core/compat.luaho
lua_objects = core.luao lib.luao input.luao filter.luao output.luao
dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS)
@@ -50,8 +49,8 @@ dist_dnsjit_SOURCES += core/channel.hh core/timespec.hh core/thread.hh core/obje
lua_hobjects += core/channel.luaho core/timespec.luaho core/thread.luaho core/object/loop.luaho core/object/gre.luaho core/object/linuxsll.luaho core/object/tcp.luaho core/object/ether.luaho core/object/icmp.luaho core/object/ieee802.luaho core/object/ip6.luaho core/object/udp.luaho core/object/dns.luaho core/object/pcap.luaho core/object/payload.luaho core/object/icmp6.luaho core/object/ip.luaho core/object/null.luaho core/producer.luaho core/receiver.luaho core/object.luaho core/log.luaho lib/clock.luaho input/zero.luaho input/mmpcap.luaho input/pcap.luaho input/fpcap.luaho filter/layer.luaho filter/timing.luaho filter/split.luaho output/udpcli.luaho output/respdiff.luaho output/tcpcli.luaho output/null.luaho
# Lua sources
-dist_dnsjit_SOURCES += core/channel.lua core/log.lua core/timespec.lua core/compat.lua core/producer.lua core/objects.lua core/thread.lua core/object/pcap.lua core/object/icmp6.lua core/object/gre.lua core/object/ether.lua core/object/ip.lua core/object/ieee802.lua core/object/tcp.lua core/object/payload.lua core/object/ip6.lua core/object/linuxsll.lua core/object/null.lua core/object/loop.lua core/object/icmp.lua core/object/dns.lua core/object/udp.lua core/receiver.lua core/object.lua lib/getopt.lua lib/clock.lua lib/parseconf.lua input/fpcap.lua input/pcap.lua input/zero.lua input/mmpcap.lua filter/timing.lua filter/split.lua filter/layer.lua output/tcpcli.lua output/respdiff.lua output/null.lua output/udpcli.lua
-lua_objects += core/channel.luao core/log.luao core/timespec.luao core/compat.luao core/producer.luao core/objects.luao core/thread.luao core/object/pcap.luao core/object/icmp6.luao core/object/gre.luao core/object/ether.luao core/object/ip.luao core/object/ieee802.luao core/object/tcp.luao core/object/payload.luao core/object/ip6.luao core/object/linuxsll.luao core/object/null.luao core/object/loop.luao core/object/icmp.luao core/object/dns.luao core/object/udp.luao core/receiver.luao core/object.luao lib/getopt.luao lib/clock.luao lib/parseconf.luao input/fpcap.luao input/pcap.luao input/zero.luao input/mmpcap.luao filter/timing.luao filter/split.luao filter/layer.luao output/tcpcli.luao output/respdiff.luao output/null.luao output/udpcli.luao
+dist_dnsjit_SOURCES += core/channel.lua core/log.lua core/timespec.lua core/compat.lua core/producer.lua core/objects.lua core/thread.lua core/object/pcap.lua core/object/icmp6.lua core/object/gre.lua core/object/ether.lua core/object/dns/q.lua core/object/dns/label.lua core/object/dns/rr.lua core/object/ip.lua core/object/ieee802.lua core/object/tcp.lua core/object/payload.lua core/object/ip6.lua core/object/linuxsll.lua core/object/null.lua core/object/loop.lua core/object/icmp.lua core/object/dns.lua core/object/udp.lua core/receiver.lua core/object.lua lib/getopt.lua lib/clock.lua lib/parseconf.lua input/fpcap.lua input/pcap.lua input/zero.lua input/mmpcap.lua filter/timing.lua filter/split.lua filter/layer.lua output/tcpcli.lua output/respdiff.lua output/null.lua output/udpcli.lua
+lua_objects += core/channel.luao core/log.luao core/timespec.luao core/compat.luao core/producer.luao core/objects.luao core/thread.luao core/object/pcap.luao core/object/icmp6.luao core/object/gre.luao core/object/ether.luao core/object/dns/q.luao core/object/dns/label.luao core/object/dns/rr.luao core/object/ip.luao core/object/ieee802.luao core/object/tcp.luao core/object/payload.luao core/object/ip6.luao core/object/linuxsll.luao core/object/null.luao core/object/loop.luao core/object/icmp.luao core/object/dns.luao core/object/udp.luao core/receiver.luao core/object.luao lib/getopt.luao lib/clock.luao lib/parseconf.luao input/fpcap.luao input/pcap.luao input/zero.luao input/mmpcap.luao filter/timing.luao filter/split.luao filter/layer.luao output/tcpcli.luao output/respdiff.luao output/null.luao output/udpcli.luao
dnsjit_LDFLAGS = -Wl,-E
dnsjit_LDADD += $(lua_hobjects) $(lua_objects)
@@ -61,7 +60,7 @@ man1_MANS = dnsjit.1
CLEANFILES += $(man1_MANS)
man3_MANS = dnsjit.core.3 dnsjit.lib.3 dnsjit.input.3 dnsjit.filter.3 dnsjit.output.3
-man3_MANS += dnsjit.core.channel.3 dnsjit.core.log.3 dnsjit.core.timespec.3 dnsjit.core.compat.3 dnsjit.core.producer.3 dnsjit.core.objects.3 dnsjit.core.thread.3 dnsjit.core.object.pcap.3 dnsjit.core.object.icmp6.3 dnsjit.core.object.gre.3 dnsjit.core.object.ether.3 dnsjit.core.object.ip.3 dnsjit.core.object.ieee802.3 dnsjit.core.object.tcp.3 dnsjit.core.object.payload.3 dnsjit.core.object.ip6.3 dnsjit.core.object.linuxsll.3 dnsjit.core.object.null.3 dnsjit.core.object.loop.3 dnsjit.core.object.icmp.3 dnsjit.core.object.dns.3 dnsjit.core.object.udp.3 dnsjit.core.receiver.3 dnsjit.core.object.3 dnsjit.lib.getopt.3 dnsjit.lib.clock.3 dnsjit.lib.parseconf.3 dnsjit.input.fpcap.3 dnsjit.input.pcap.3 dnsjit.input.zero.3 dnsjit.input.mmpcap.3 dnsjit.filter.timing.3 dnsjit.filter.split.3 dnsjit.filter.layer.3 dnsjit.output.tcpcli.3 dnsjit.output.respdiff.3 dnsjit.output.null.3 dnsjit.output.udpcli.3
+man3_MANS += dnsjit.core.channel.3 dnsjit.core.log.3 dnsjit.core.timespec.3 dnsjit.core.compat.3 dnsjit.core.producer.3 dnsjit.core.objects.3 dnsjit.core.thread.3 dnsjit.core.object.pcap.3 dnsjit.core.object.icmp6.3 dnsjit.core.object.gre.3 dnsjit.core.object.ether.3 dnsjit.core.object.dns.q.3 dnsjit.core.object.dns.label.3 dnsjit.core.object.dns.rr.3 dnsjit.core.object.ip.3 dnsjit.core.object.ieee802.3 dnsjit.core.object.tcp.3 dnsjit.core.object.payload.3 dnsjit.core.object.ip6.3 dnsjit.core.object.linuxsll.3 dnsjit.core.object.null.3 dnsjit.core.object.loop.3 dnsjit.core.object.icmp.3 dnsjit.core.object.dns.3 dnsjit.core.object.udp.3 dnsjit.core.receiver.3 dnsjit.core.object.3 dnsjit.lib.getopt.3 dnsjit.lib.clock.3 dnsjit.lib.parseconf.3 dnsjit.input.fpcap.3 dnsjit.input.pcap.3 dnsjit.input.zero.3 dnsjit.input.mmpcap.3 dnsjit.filter.timing.3 dnsjit.filter.split.3 dnsjit.filter.layer.3 dnsjit.output.tcpcli.3 dnsjit.output.respdiff.3 dnsjit.output.null.3 dnsjit.output.udpcli.3
CLEANFILES += *.3in $(man3_MANS)
.lua.luao:
@@ -147,6 +146,15 @@ dnsjit.core.object.gre.3in: core/object/gre.lua gen-manpage.lua
dnsjit.core.object.ether.3in: core/object/ether.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ether.lua" > "$@"
+dnsjit.core.object.dns.q.3in: core/object/dns/q.lua gen-manpage.lua
+ $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/q.lua" > "$@"
+
+dnsjit.core.object.dns.label.3in: core/object/dns/label.lua gen-manpage.lua
+ $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/label.lua" > "$@"
+
+dnsjit.core.object.dns.rr.3in: core/object/dns/rr.lua gen-manpage.lua
+ $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/rr.lua" > "$@"
+
dnsjit.core.object.ip.3in: core/object/ip.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ip.lua" > "$@"
diff --git a/src/core/object.lua b/src/core/object.lua
index dd668bd0..cda76609 100644
--- a/src/core/object.lua
+++ b/src/core/object.lua
@@ -57,42 +57,42 @@ local C = ffi.C
local t_name = "core_object_t"
local core_object_t
local Object = {
- CORE_OBJECT_NONE = 0,
- CORE_OBJECT_PCAP = 1,
- CORE_OBJECT_ETHER = 10,
- CORE_OBJECT_NULL = 11,
- CORE_OBJECT_LOOP = 12,
- CORE_OBJECT_LINUXSLL = 13,
- CORE_OBJECT_IEEE802 = 14,
- CORE_OBJECT_GRE = 15,
- CORE_OBJECT_IP = 20,
- CORE_OBJECT_IP6 = 21,
- CORE_OBJECT_ICMP = 22,
- CORE_OBJECT_ICMP6 = 23,
- CORE_OBJECT_UDP = 30,
- CORE_OBJECT_TCP = 31,
- CORE_OBJECT_PAYLOAD = 40,
- CORE_OBJECT_DNS = 50
+ NONE = 0,
+ PCAP = 1,
+ ETHER = 10,
+ NULL = 11,
+ LOOP = 12,
+ LINUXSLL = 13,
+ IEEE802 = 14,
+ GRE = 15,
+ IP = 20,
+ IP6 = 21,
+ ICMP = 22,
+ ICMP6 = 23,
+ UDP = 30,
+ TCP = 31,
+ PAYLOAD = 40,
+ DNS = 50
}
local _type = {}
-_type[Object.CORE_OBJECT_PCAP] = "pcap"
-_type[Object.CORE_OBJECT_ETHER] = "ether"
-_type[Object.CORE_OBJECT_NULL] = "null"
-_type[Object.CORE_OBJECT_LOOP] = "loop"
-_type[Object.CORE_OBJECT_LINUXSLL] = "linuxsll"
-_type[Object.CORE_OBJECT_IEEE802] = "ieee802"
-_type[Object.CORE_OBJECT_GRE] = "gre"
-_type[Object.CORE_OBJECT_IP] = "ip"
-_type[Object.CORE_OBJECT_IP6] = "ip6"
-_type[Object.CORE_OBJECT_ICMP] = "icmp"
-_type[Object.CORE_OBJECT_ICMP6] = "icmp6"
-_type[Object.CORE_OBJECT_UDP] = "udp"
-_type[Object.CORE_OBJECT_TCP] = "tcp"
-_type[Object.CORE_OBJECT_PAYLOAD] = "payload"
-_type[Object.CORE_OBJECT_DNS] = "dns"
+_type[Object.PCAP] = "pcap"
+_type[Object.ETHER] = "ether"
+_type[Object.NULL] = "null"
+_type[Object.LOOP] = "loop"
+_type[Object.LINUXSLL] = "linuxsll"
+_type[Object.IEEE802] = "ieee802"
+_type[Object.GRE] = "gre"
+_type[Object.IP] = "ip"
+_type[Object.IP6] = "ip6"
+_type[Object.ICMP] = "icmp"
+_type[Object.ICMP6] = "icmp6"
+_type[Object.UDP] = "udp"
+_type[Object.TCP] = "tcp"
+_type[Object.PAYLOAD] = "payload"
+_type[Object.DNS] = "dns"
-_type[Object.CORE_OBJECT_NONE] = "none"
+_type[Object.NONE] = "none"
-- Return the textual type of the object.
function Object:type()
@@ -105,21 +105,21 @@ function Object:prev()
end
local _cast = {}
-_cast[Object.CORE_OBJECT_PCAP] = "core_object_pcap_t*"
-_cast[Object.CORE_OBJECT_ETHER] = "core_object_ether_t*"
-_cast[Object.CORE_OBJECT_NULL] = "core_object_null_t*"
-_cast[Object.CORE_OBJECT_LOOP] = "core_object_loop_t*"
-_cast[Object.CORE_OBJECT_LINUXSLL] = "core_object_linuxsll_t*"
-_cast[Object.CORE_OBJECT_IEEE802] = "core_object_ieee802_t*"
-_cast[Object.CORE_OBJECT_GRE] = "core_object_gre_t*"
-_cast[Object.CORE_OBJECT_IP] = "core_object_ip_t*"
-_cast[Object.CORE_OBJECT_IP6] = "core_object_ip6_t*"
-_cast[Object.CORE_OBJECT_ICMP] = "core_object_icmp_t*"
-_cast[Object.CORE_OBJECT_ICMP6] = "core_object_icmp6_t*"
-_cast[Object.CORE_OBJECT_UDP] = "core_object_udp_t*"
-_cast[Object.CORE_OBJECT_TCP] = "core_object_tcp_t*"
-_cast[Object.CORE_OBJECT_PAYLOAD] = "core_object_payload_t*"
-_cast[Object.CORE_OBJECT_DNS] = "core_object_dns_t*"
+_cast[Object.PCAP] = "core_object_pcap_t*"
+_cast[Object.ETHER] = "core_object_ether_t*"
+_cast[Object.NULL] = "core_object_null_t*"
+_cast[Object.LOOP] = "core_object_loop_t*"
+_cast[Object.LINUXSLL] = "core_object_linuxsll_t*"
+_cast[Object.IEEE802] = "core_object_ieee802_t*"
+_cast[Object.GRE] = "core_object_gre_t*"
+_cast[Object.IP] = "core_object_ip_t*"
+_cast[Object.IP6] = "core_object_ip6_t*"
+_cast[Object.ICMP] = "core_object_icmp_t*"
+_cast[Object.ICMP6] = "core_object_icmp6_t*"
+_cast[Object.UDP] = "core_object_udp_t*"
+_cast[Object.TCP] = "core_object_tcp_t*"
+_cast[Object.PAYLOAD] = "core_object_payload_t*"
+_cast[Object.DNS] = "core_object_dns_t*"
-- Cast the object to the underlining object module and return it.
function Object:cast()
diff --git a/src/core/object/dns.c b/src/core/object/dns.c
index 200e2162..6c1996a2 100644
--- a/src/core/object/dns.c
+++ b/src/core/object/dns.c
@@ -22,102 +22,69 @@
#include "core/object/dns.h"
#include "core/object/payload.h"
-#include "omg-dns/omg_dns.h"
#include "core/assert.h"
#include
#include
-
-#define NUM_LABELS 256
-#define NUM_RRS 128
-
-typedef struct _parse {
- size_t rr_idx;
- omg_dns_rr_t rr[NUM_RRS];
- int rr_ret[NUM_RRS];
- size_t rr_label_idx[NUM_RRS];
- size_t label_idx;
- omg_dns_label_t label[NUM_LABELS];
- int at_rr;
- char label_buf[512];
-} _parse_t;
-
-typedef struct _query {
- core_object_dns_t pub;
- omg_dns_t dns;
- _parse_t* parsed;
-} _query_t;
-
-static core_log_t _log = LOG_T_INIT("core.object.dns");
-static _query_t _defaults = {
- CORE_OBJECT_DNS_INIT(0),
- OMG_DNS_T_INIT,
- 0
-};
-
-#define _self ((_query_t*)self)
+#ifdef HAVE_ENDIAN_H
+#include
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include
+#endif
+#endif
+#endif
+#ifdef HAVE_BYTESWAP_H
+#include
+#endif
+#ifndef bswap_16
+#ifndef bswap16
+#define bswap_16(x) swap16(x)
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#else
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+#endif
+
+#define _ERR_MALFORMED -2
+#define _ERR_NEEDLABELS -3
+
+static core_log_t _log = LOG_T_INIT("core.object.dns");
+static core_object_dns_t _defaults = CORE_OBJECT_DNS_INIT(0);
+
+static core_object_dns_label_t _defaults_label = { 0 };
+static core_object_dns_rr_t _defaults_rr = { 0 };
+static core_object_dns_q_t _defaults_q = { 0 };
core_log_t* core_object_dns_log()
{
return &_log;
}
-static int _label_callback(const omg_dns_label_t* label, void* self)
-{
- if (!_self || _self->parsed->label_idx == NUM_LABELS)
- return OMG_DNS_ENOMEM;
-
- _self->parsed->label[_self->parsed->label_idx] = *label;
- _self->parsed->label_idx++;
-
- return OMG_DNS_OK;
-}
-
-static int _rr_callback(int ret, const omg_dns_rr_t* rr, void* self)
-{
- if (!_self || _self->parsed->rr_idx == NUM_RRS)
- return OMG_DNS_ENOMEM;
-
- _self->parsed->rr_ret[_self->parsed->rr_idx] = ret;
- if (rr)
- _self->parsed->rr[_self->parsed->rr_idx] = *rr;
- _self->parsed->rr_idx++;
- if (_self->parsed->rr_idx != NUM_RRS)
- _self->parsed->rr_label_idx[_self->parsed->rr_idx] = _self->parsed->label_idx;
-
- return OMG_DNS_OK;
-}
-
-core_object_dns_t* core_object_dns_new(const core_object_t* obj)
+core_object_dns_t* core_object_dns_new()
{
core_object_dns_t* self;
- mlassert(obj, "obj is nil");
-
- switch (obj->obj_type) {
- case CORE_OBJECT_PAYLOAD:
- break;
- default:
- mlfatal("invalid object type %d", obj->obj_type);
- }
-
- mlfatal_oom(self = malloc(sizeof(_query_t)));
- *_self = _defaults;
- self->obj_prev = obj;
+ mlfatal_oom(self = malloc(sizeof(core_object_dns_t)));
+ *self = _defaults;
return self;
}
core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self)
{
- _query_t* copy;
+ core_object_dns_t* copy;
mlassert_self();
- mlfatal_oom(copy = malloc(sizeof(_query_t)));
- *copy = _defaults;
- memcpy(©->pub, self, sizeof(core_object_dns_t));
- copy->pub.obj_prev = 0;
- copy->parsed = 0;
+ mlfatal_oom(copy = malloc(sizeof(core_object_dns_t)));
+ memcpy(copy, self, sizeof(core_object_dns_t));
+ copy->obj_prev = 0;
return (core_object_dns_t*)copy;
}
@@ -125,301 +92,376 @@ core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self)
void core_object_dns_free(core_object_dns_t* self)
{
mlassert_self();
-
- free(_self->parsed);
free(self);
}
-int core_object_dns_parse_header(core_object_dns_t* self)
-{
- const u_char* payload;
- size_t len;
- mlassert_self();
-
- if (!self->obj_prev || _self->dns.have_header) {
- return -1;
- }
+#define need8(v, p, l) \
+ if (l < 1) { \
+ break; \
+ } \
+ v = *p; \
+ p += 1; \
+ l -= 1
- switch (self->obj_prev->obj_type) {
- case CORE_OBJECT_PAYLOAD:
- payload = ((const core_object_payload_t*)self->obj_prev)->payload;
- len = ((const core_object_payload_t*)self->obj_prev)->len;
- break;
- default:
- return -1;
- }
-
- if (omg_dns_parse_header(&_self->dns, payload, len)) {
- return -2;
- }
+static inline uint16_t _need16(const void* ptr)
+{
+ uint16_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be16toh(v);
+}
- self->have_id = _self->dns.have_id;
- self->have_qr = _self->dns.have_qr;
- self->have_opcode = _self->dns.have_opcode;
- self->have_aa = _self->dns.have_aa;
- self->have_tc = _self->dns.have_tc;
- self->have_rd = _self->dns.have_rd;
- self->have_ra = _self->dns.have_ra;
- self->have_z = _self->dns.have_z;
- self->have_ad = _self->dns.have_ad;
- self->have_cd = _self->dns.have_cd;
- self->have_rcode = _self->dns.have_rcode;
- self->have_qdcount = _self->dns.have_qdcount;
- self->have_ancount = _self->dns.have_ancount;
- self->have_nscount = _self->dns.have_nscount;
- self->have_arcount = _self->dns.have_arcount;
- self->id = _self->dns.id;
- self->qr = _self->dns.qr;
- self->opcode = _self->dns.opcode;
- self->aa = _self->dns.aa;
- self->tc = _self->dns.tc;
- self->rd = _self->dns.rd;
- self->ra = _self->dns.ra;
- self->z = _self->dns.z;
- self->ad = _self->dns.ad;
- self->cd = _self->dns.cd;
- self->rcode = _self->dns.rcode;
- self->qdcount = _self->dns.qdcount;
- self->ancount = _self->dns.ancount;
- self->nscount = _self->dns.nscount;
- self->arcount = _self->dns.arcount;
+#define need16(v, p, l) \
+ if (l < 2) { \
+ break; \
+ } \
+ v = _need16(p); \
+ p += 2; \
+ l -= 2
- return 0;
+static inline uint32_t _need32(const void* ptr)
+{
+ uint32_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be32toh(v);
}
-int core_object_dns_parse(core_object_dns_t* self)
+#define need32(v, p, l) \
+ if (l < 4) { \
+ break; \
+ } \
+ v = _need32(p); \
+ p += 4; \
+ l -= 4
+
+#define needxb(b, x, p, l) \
+ if (l < x) { \
+ break; \
+ } \
+ memcpy(b, p, x); \
+ p += x; \
+ l -= x
+
+#define advancexb(x, p, l) \
+ if (l < x) { \
+ break; \
+ } \
+ p += x; \
+ l -= x
+
+int core_object_dns_parse_header(core_object_dns_t* self)
{
- const u_char* payload;
- size_t len;
+ const core_object_payload_t* payload;
+ uint8_t byte;
mlassert_self();
- if (!self->obj_prev || _self->parsed || _self->dns.have_body) {
- return -1;
+ if (!(payload = (core_object_payload_t*)self->obj_prev) || payload->obj_type != CORE_OBJECT_PAYLOAD) {
+ mlfatal("no obj_prev or invalid type");
}
-
- switch (self->obj_prev->obj_type) {
- case CORE_OBJECT_PAYLOAD:
- payload = ((const core_object_payload_t*)self->obj_prev)->payload;
- len = ((const core_object_payload_t*)self->obj_prev)->len;
- break;
- default:
- return -1;
+ if (!payload->payload || !payload->len) {
+ mlfatal("no payload set or zero length");
}
- mlfatal_oom(_self->parsed = calloc(1, sizeof(_parse_t)));
+ self->payload = self->at = payload->payload;
+ self->len = self->left = payload->len;
- _self->parsed->rr_idx = 0;
- _self->parsed->label_idx = 0;
+ for (;;) {
+ need16(self->id, self->at, self->left);
+ self->have_id = 1;
- omg_dns_set_rr_callback(&_self->dns, _rr_callback, (void*)_self);
- omg_dns_set_label_callback(&_self->dns, _label_callback, (void*)_self);
+ need8(byte, self->at, self->left);
+ self->qr = byte & (1 << 7) ? 1 : 0;
+ self->opcode = (byte >> 3) & 0xf;
+ self->aa = byte & (1 << 2) ? 1 : 0;
+ self->tc = byte & (1 << 1) ? 1 : 0;
+ self->rd = byte & (1 << 0) ? 1 : 0;
+ self->have_qr = self->have_opcode = self->have_aa = self->have_tc = self->have_rd = 1;
- if (!_self->dns.have_header) {
- if (omg_dns_parse(&_self->dns, payload, len)) {
- return -2;
- }
+ need8(byte, self->at, self->left);
+ self->ra = byte & (1 << 7) ? 1 : 0;
+ self->z = byte & (1 << 6) ? 1 : 0;
+ self->ad = byte & (1 << 5) ? 1 : 0;
+ self->cd = byte & (1 << 4) ? 1 : 0;
+ self->rcode = byte & 0xf;
+ self->have_ra = self->have_z = self->have_ad = self->have_cd = self->have_rcode = 1;
- self->have_id = _self->dns.have_id;
- self->have_qr = _self->dns.have_qr;
- self->have_opcode = _self->dns.have_opcode;
- self->have_aa = _self->dns.have_aa;
- self->have_tc = _self->dns.have_tc;
- self->have_rd = _self->dns.have_rd;
- self->have_ra = _self->dns.have_ra;
- self->have_z = _self->dns.have_z;
- self->have_ad = _self->dns.have_ad;
- self->have_cd = _self->dns.have_cd;
- self->have_rcode = _self->dns.have_rcode;
- self->have_qdcount = _self->dns.have_qdcount;
- self->have_ancount = _self->dns.have_ancount;
- self->have_nscount = _self->dns.have_nscount;
- self->have_arcount = _self->dns.have_arcount;
- self->id = _self->dns.id;
- self->qr = _self->dns.qr;
- self->opcode = _self->dns.opcode;
- self->aa = _self->dns.aa;
- self->tc = _self->dns.tc;
- self->rd = _self->dns.rd;
- self->ra = _self->dns.ra;
- self->z = _self->dns.z;
- self->ad = _self->dns.ad;
- self->cd = _self->dns.cd;
- self->rcode = _self->dns.rcode;
- self->qdcount = _self->dns.qdcount;
- self->ancount = _self->dns.ancount;
- self->nscount = _self->dns.nscount;
- self->arcount = _self->dns.arcount;
- } else if (len > _self->dns.bytes_parsed) {
- if (omg_dns_parse_body(&_self->dns, payload + _self->dns.bytes_parsed, len - _self->dns.bytes_parsed)) {
- return -2;
- }
- }
- _self->parsed->at_rr = -1;
- _self->parsed->label_buf[0] = 0;
+ need16(self->qdcount, self->at, self->left);
+ self->have_qdcount = 1;
- self->questions = _self->dns.questions;
- self->answers = _self->dns.answers;
- self->authorities = _self->dns.authorities;
- self->additionals = _self->dns.additionals;
+ need16(self->ancount, self->at, self->left);
+ self->have_ancount = 1;
- return 0;
-}
+ need16(self->nscount, self->at, self->left);
+ self->have_nscount = 1;
-int core_object_dns_rr_reset(core_object_dns_t* self)
-{
- mlassert_self();
+ need16(self->arcount, self->at, self->left);
+ self->have_arcount = 1;
- if (!_self->parsed) {
- return -1;
+ return 0;
}
- _self->parsed->at_rr = -1;
- _self->parsed->label_buf[0] = 0;
-
- return 0;
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
}
-int core_object_dns_rr_next(core_object_dns_t* self)
+static inline size_t _rdata_labels(uint16_t type)
{
- mlassert_self();
+ switch (type) {
+ case CORE_OBJECT_DNS_TYPE_NS:
+ case CORE_OBJECT_DNS_TYPE_MD:
+ case CORE_OBJECT_DNS_TYPE_MF:
+ case CORE_OBJECT_DNS_TYPE_CNAME:
+ case CORE_OBJECT_DNS_TYPE_MB:
+ case CORE_OBJECT_DNS_TYPE_MG:
+ case CORE_OBJECT_DNS_TYPE_MR:
+ case CORE_OBJECT_DNS_TYPE_PTR:
+ case CORE_OBJECT_DNS_TYPE_NXT:
+ case CORE_OBJECT_DNS_TYPE_DNAME:
+ case CORE_OBJECT_DNS_TYPE_NSEC:
+ case CORE_OBJECT_DNS_TYPE_TKEY:
+ case CORE_OBJECT_DNS_TYPE_TSIG:
+ return 1;
+
+ case CORE_OBJECT_DNS_TYPE_SOA:
+ case CORE_OBJECT_DNS_TYPE_MINFO:
+ case CORE_OBJECT_DNS_TYPE_RP:
+ case CORE_OBJECT_DNS_TYPE_TALINK:
+ return 2;
+
+ case CORE_OBJECT_DNS_TYPE_MX:
+ case CORE_OBJECT_DNS_TYPE_AFSDB:
+ case CORE_OBJECT_DNS_TYPE_RT:
+ case CORE_OBJECT_DNS_TYPE_KX:
+ case CORE_OBJECT_DNS_TYPE_LP:
+ return 1;
+
+ case CORE_OBJECT_DNS_TYPE_PX:
+ return 2;
+
+ case CORE_OBJECT_DNS_TYPE_SIG:
+ case CORE_OBJECT_DNS_TYPE_RRSIG:
+ return 1;
+
+ case CORE_OBJECT_DNS_TYPE_SRV:
+ return 1;
+
+ case CORE_OBJECT_DNS_TYPE_NAPTR:
+ return 1;
+
+ case CORE_OBJECT_DNS_TYPE_HIP:
+ return 1;
- if (!_self->parsed) {
- return -1;
+ default:
+ break;
}
- if (_self->parsed->at_rr < 0) {
- _self->parsed->at_rr = 0;
- } else if (_self->parsed->at_rr < _self->parsed->rr_idx) {
- _self->parsed->at_rr++;
+ return 0;
+}
+
+static inline size_t _label(core_object_dns_t* self, core_object_dns_label_t* label, size_t labels)
+{
+ size_t n;
+
+ for (n = 0; self->left && n < labels; n++) {
+ core_object_dns_label_t* l = &label[n];
+ *l = _defaults_label;
+
+ need8(l->length, self->at, self->left);
+
+ if ((l->length & 0xc0) == 0xc0) {
+ need8(l->offset, self->at, self->left);
+ l->offset |= (l->length & 0x3f) << 8;
+ l->have_offset = 1;
+ return n;
+ } else if (l->length & 0xc0) {
+ l->extension_bits = l->length >> 6;
+ l->have_extension_bits = 1;
+ return n;
+ } else if (l->length) {
+ l->have_length = 1;
+
+ l->offset = self->at - self->payload - 1;
+ advancexb(l->length, self->at, self->left);
+ l->have_dn = 1;
+ } else {
+ l->is_end = 1;
+ return n;
+ }
}
- return _self->parsed->at_rr < _self->parsed->rr_idx ? 0 : -1;
+ return n;
}
-int core_object_dns_rr_ok(core_object_dns_t* self)
+int core_object_dns_parse_q(core_object_dns_t* self, core_object_dns_q_t* q, core_object_dns_label_t* label, size_t labels)
{
mlassert_self();
+ mlassert(q, "q is nil");
+ mlassert(label, "label is nil");
+ mlassert(labels, "labels is zero");
+ mlassert(self->at, "at is nil");
+
+ for (;;) {
+ *q = _defaults_q;
+ q->labels = _label(self, label, labels);
+ if (q->labels < labels) {
+ core_object_dns_label_t* l = &label[q->labels];
+ if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
+ }
+ } else {
+ mlwarning("need more labels, aborting DNS parsing");
+ return _ERR_NEEDLABELS;
+ }
+ q->labels++;
+
+ need16(q->type, self->at, self->left);
+ q->have_type = 1;
+
+ need16(q->class, self->at, self->left);
+ q->have_class = 1;
- if (!_self->parsed || _self->parsed->at_rr < 0 || _self->parsed->at_rr >= _self->parsed->rr_idx) {
return 0;
}
- return _self->parsed->rr_ret[_self->parsed->at_rr] == OMG_DNS_OK ? 1 : 0;
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
}
-const char* core_object_dns_rr_label(core_object_dns_t* self)
+int core_object_dns_parse_rr(core_object_dns_t* self, core_object_dns_rr_t* rr, core_object_dns_label_t* label, size_t labels)
{
- const u_char* payload;
- char* label;
- size_t left;
+ size_t rdata_label_sets;
mlassert_self();
+ mlassert(rr, "rr is nil");
+ mlassert(label, "label is nil");
+ mlassert(labels, "labels is zero");
+ mlassert(self->at, "at is nil");
+
+ for (;;) {
+ *rr = _defaults_rr;
+ rr->labels = _label(self, label, labels);
+ if (rr->labels < labels) {
+ core_object_dns_label_t* l = &label[rr->labels];
+ if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
+ }
+ } else {
+ mlwarning("need more labels, aborting DNS parsing");
+ return _ERR_NEEDLABELS;
+ }
+ rr->labels++;
- if (!_self->parsed || _self->parsed->at_rr < 0 || _self->parsed->at_rr >= _self->parsed->rr_idx || _self->parsed->rr_ret[_self->parsed->at_rr] != OMG_DNS_OK) {
- return 0;
- }
+ need16(rr->type, self->at, self->left);
+ rr->have_type = 1;
- switch (self->obj_prev->obj_type) {
- case CORE_OBJECT_PAYLOAD:
- payload = ((const core_object_payload_t*)self->obj_prev)->payload;
- break;
- default:
- return 0;
- }
+ need16(rr->class, self->at, self->left);
+ rr->have_class = 1;
- label = _self->parsed->label_buf;
- left = sizeof(_self->parsed->label_buf) - 1;
+ need32(rr->ttl, self->at, self->left);
+ rr->have_ttl = 1;
- if (omg_dns_rr_labels(&_self->parsed->rr[_self->parsed->at_rr])) {
- size_t l = _self->parsed->rr_label_idx[_self->parsed->at_rr];
- size_t loop = 0;
+ need16(rr->rdlength, self->at, self->left);
+ rr->have_rdlength = 1;
- while (!omg_dns_label_is_end(&(_self->parsed->label[l]))) {
- if (!omg_dns_label_is_complete(&(_self->parsed->label[l]))) {
- mldebug("label %lu incomplete", l);
- return 0;
- }
+ rr->rdata_offset = self->at - self->payload;
+ if (!(rdata_label_sets = _rdata_labels(rr->type))) {
+ advancexb(rr->rdlength, self->at, self->left);
+ rr->have_rdata = 1;
+ return 0;
+ }
- if (loop > _self->parsed->label_idx) {
- mldebug("label %lu looped", l);
- return 0;
+ switch (rr->type) {
+ case CORE_OBJECT_DNS_TYPE_MX:
+ case CORE_OBJECT_DNS_TYPE_AFSDB:
+ case CORE_OBJECT_DNS_TYPE_RT:
+ case CORE_OBJECT_DNS_TYPE_KX:
+ case CORE_OBJECT_DNS_TYPE_LP:
+ case CORE_OBJECT_DNS_TYPE_PX:
+ advancexb(2, self->at, self->left);
+ break;
+
+ case CORE_OBJECT_DNS_TYPE_SIG:
+ case CORE_OBJECT_DNS_TYPE_RRSIG:
+ advancexb(18, self->at, self->left);
+ break;
+
+ case CORE_OBJECT_DNS_TYPE_SRV:
+ advancexb(6, self->at, self->left);
+ break;
+
+ case CORE_OBJECT_DNS_TYPE_NAPTR: {
+ uint8_t naptr_length;
+
+ advancexb(4, self->at, self->left);
+ need8(naptr_length, self->at, self->left);
+ advancexb(naptr_length, self->at, self->left);
+ need8(naptr_length, self->at, self->left);
+ advancexb(naptr_length, self->at, self->left);
+ need8(naptr_length, self->at, self->left);
+ advancexb(naptr_length, self->at, self->left);
+ } break;
+
+ case CORE_OBJECT_DNS_TYPE_HIP: {
+ uint8_t hit_length;
+ uint16_t pk_length;
+
+ need8(hit_length, self->at, self->left);
+ advancexb(1, self->at, self->left);
+ need16(pk_length, self->at, self->left);
+ advancexb(hit_length, self->at, self->left);
+ advancexb(pk_length, self->at, self->left);
+
+ if (self->at - self->payload >= rr->rdata_offset + rr->rdlength) {
+ rdata_label_sets = 0;
}
- loop++;
-
- if (omg_dns_label_have_offset(&(_self->parsed->label[l]))) {
- size_t l2;
+ } break;
+ }
- for (l2 = 0; l2 < _self->parsed->label_idx; l2++) {
- if (omg_dns_label_have_dn(&(_self->parsed->label[l2]))
- && omg_dns_label_offset(&(_self->parsed->label[l2])) == omg_dns_label_offset(&(_self->parsed->label[l]))) {
- l = l2;
- break;
- }
+ while (rdata_label_sets) {
+ rr->rdata_labels += _label(self, &label[rr->labels + rr->rdata_labels], labels - rr->labels - rr->rdata_labels);
+ if (rr->labels + rr->rdata_labels < labels) {
+ core_object_dns_label_t* l = &label[rr->labels + rr->rdata_labels];
+ if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
}
- if (l2 < _self->parsed->label_idx) {
- continue;
- }
- mldebug("label %lu offset missing", l);
- return 0;
- } else if (omg_dns_label_have_extension_bits(&(_self->parsed->label[l]))) {
- mldebug("label %lu is an extension", l);
- return 0;
- } else if (omg_dns_label_have_dn(&(_self->parsed->label[l]))) {
- const char* dn = (char*)payload + omg_dns_label_dn_offset(&(_self->parsed->label[l]));
- size_t dnlen = omg_dns_label_length(&(_self->parsed->label[l]));
-
- if ((dnlen + 1) > left) {
- mldebug("label %lu caused buffer overflow", l);
- return 0;
- }
- memcpy(label, dn, dnlen);
- label += dnlen;
- left -= dnlen;
-
- *label = '.';
- label++;
- left--;
-
- l++;
} else {
- mldebug("label %lu invalid", l);
- return 0;
+ mlwarning("need more labels, aborting DNS parsing");
+ return _ERR_NEEDLABELS;
}
- }
- }
-
- *label = 0;
- return _self->parsed->label_buf;
-}
-
-uint16_t core_object_dns_rr_type(core_object_dns_t* self)
-{
- mlassert_self();
-
- if (!_self->parsed || _self->parsed->at_rr < 0 || _self->parsed->at_rr >= _self->parsed->rr_idx || _self->parsed->rr_ret[_self->parsed->at_rr] != OMG_DNS_OK) {
- return 0;
- }
-
- return _self->parsed->rr[_self->parsed->at_rr].type;
-}
-
-uint16_t core_object_dns_rr_class(core_object_dns_t* self)
-{
- mlassert_self();
+ rr->rdata_labels++;
- if (!_self->parsed || _self->parsed->at_rr < 0 || _self->parsed->at_rr >= _self->parsed->rr_idx || _self->parsed->rr_ret[_self->parsed->at_rr] != OMG_DNS_OK) {
- return 0;
- }
+ if (rr->type == CORE_OBJECT_DNS_TYPE_HIP && self->at - self->payload < rr->rdata_offset + rr->rdlength) {
+ continue;
+ }
- return _self->parsed->rr[_self->parsed->at_rr].class;
-}
+ rdata_label_sets--;
+ }
-uint32_t core_object_dns_rr_ttl(core_object_dns_t* self)
-{
- mlassert_self();
+ if (self->at - self->payload < rr->rdata_offset + rr->rdlength) {
+ rr->padding_offset = self->at - self->payload;
+ rr->padding_length = rr->rdlength - (rr->padding_offset - rr->rdata_offset);
+
+ advancexb(rr->padding_length, self->at, self->left);
+
+ /*
+ * TODO:
+ *
+ * This can indicate padding but we do not set that we have padding
+ * yet because we need to fully understand all record types before
+ * that and process valid data after the labels
+ *
+ rr->have_padding = 1;
+ */
+ } else if (self->at - self->payload > rr->rdata_offset + rr->rdlength) {
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
+ }
+ rr->have_rdata = 1;
- if (!_self->parsed || _self->parsed->at_rr < 0 || _self->parsed->at_rr >= _self->parsed->rr_idx || _self->parsed->rr_ret[_self->parsed->at_rr] != OMG_DNS_OK) {
return 0;
}
- return _self->parsed->rr[_self->parsed->at_rr].ttl;
+ // TODO: error here on malformed/truncated? could be quite spammy
+ return _ERR_MALFORMED;
}
diff --git a/src/core/object/dns.h b/src/core/object/dns.h
index 9831a1c8..fe946734 100644
--- a/src/core/object/dns.h
+++ b/src/core/object/dns.h
@@ -33,9 +33,152 @@
{ \
CORE_OBJECT_INIT(CORE_OBJECT_DNS, prev) \
, \
+ 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0 \
}
+/*
+ * 2016-12-09 https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+ */
+
+#define CORE_OBJECT_DNS_CLASS_IN 1
+#define CORE_OBJECT_DNS_CLASS_CH 3
+#define CORE_OBJECT_DNS_CLASS_HS 4
+#define CORE_OBJECT_DNS_CLASS_NONE 254
+#define CORE_OBJECT_DNS_CLASS_ANY 255
+
+#define CORE_OBJECT_DNS_TYPE_A 1
+#define CORE_OBJECT_DNS_TYPE_NS 2
+#define CORE_OBJECT_DNS_TYPE_MD 3
+#define CORE_OBJECT_DNS_TYPE_MF 4
+#define CORE_OBJECT_DNS_TYPE_CNAME 5
+#define CORE_OBJECT_DNS_TYPE_SOA 6
+#define CORE_OBJECT_DNS_TYPE_MB 7
+#define CORE_OBJECT_DNS_TYPE_MG 8
+#define CORE_OBJECT_DNS_TYPE_MR 9
+#define CORE_OBJECT_DNS_TYPE_NULL 10
+#define CORE_OBJECT_DNS_TYPE_WKS 11
+#define CORE_OBJECT_DNS_TYPE_PTR 12
+#define CORE_OBJECT_DNS_TYPE_HINFO 13
+#define CORE_OBJECT_DNS_TYPE_MINFO 14
+#define CORE_OBJECT_DNS_TYPE_MX 15
+#define CORE_OBJECT_DNS_TYPE_TXT 16
+#define CORE_OBJECT_DNS_TYPE_RP 17
+#define CORE_OBJECT_DNS_TYPE_AFSDB 18
+#define CORE_OBJECT_DNS_TYPE_X25 19
+#define CORE_OBJECT_DNS_TYPE_ISDN 20
+#define CORE_OBJECT_DNS_TYPE_RT 21
+#define CORE_OBJECT_DNS_TYPE_NSAP 22
+#define CORE_OBJECT_DNS_TYPE_NSAP_PTR 23
+#define CORE_OBJECT_DNS_TYPE_SIG 24
+#define CORE_OBJECT_DNS_TYPE_KEY 25
+#define CORE_OBJECT_DNS_TYPE_PX 26
+#define CORE_OBJECT_DNS_TYPE_GPOS 27
+#define CORE_OBJECT_DNS_TYPE_AAAA 28
+#define CORE_OBJECT_DNS_TYPE_LOC 29
+#define CORE_OBJECT_DNS_TYPE_NXT 30
+#define CORE_OBJECT_DNS_TYPE_EID 31
+#define CORE_OBJECT_DNS_TYPE_NIMLOC 32
+#define CORE_OBJECT_DNS_TYPE_SRV 33
+#define CORE_OBJECT_DNS_TYPE_ATMA 34
+#define CORE_OBJECT_DNS_TYPE_NAPTR 35
+#define CORE_OBJECT_DNS_TYPE_KX 36
+#define CORE_OBJECT_DNS_TYPE_CERT 37
+#define CORE_OBJECT_DNS_TYPE_A6 38
+#define CORE_OBJECT_DNS_TYPE_DNAME 39
+#define CORE_OBJECT_DNS_TYPE_SINK 40
+#define CORE_OBJECT_DNS_TYPE_OPT 41
+#define CORE_OBJECT_DNS_TYPE_APL 42
+#define CORE_OBJECT_DNS_TYPE_DS 43
+#define CORE_OBJECT_DNS_TYPE_SSHFP 44
+#define CORE_OBJECT_DNS_TYPE_IPSECKEY 45
+#define CORE_OBJECT_DNS_TYPE_RRSIG 46
+#define CORE_OBJECT_DNS_TYPE_NSEC 47
+#define CORE_OBJECT_DNS_TYPE_DNSKEY 48
+#define CORE_OBJECT_DNS_TYPE_DHCID 49
+#define CORE_OBJECT_DNS_TYPE_NSEC3 50
+#define CORE_OBJECT_DNS_TYPE_NSEC3PARAM 51
+#define CORE_OBJECT_DNS_TYPE_TLSA 52
+#define CORE_OBJECT_DNS_TYPE_SMIMEA 53
+#define CORE_OBJECT_DNS_TYPE_HIP 55
+#define CORE_OBJECT_DNS_TYPE_NINFO 56
+#define CORE_OBJECT_DNS_TYPE_RKEY 57
+#define CORE_OBJECT_DNS_TYPE_TALINK 58
+#define CORE_OBJECT_DNS_TYPE_CDS 59
+#define CORE_OBJECT_DNS_TYPE_CDNSKEY 60
+#define CORE_OBJECT_DNS_TYPE_OPENPGPKEY 61
+#define CORE_OBJECT_DNS_TYPE_CSYNC 62
+#define CORE_OBJECT_DNS_TYPE_SPF 99
+#define CORE_OBJECT_DNS_TYPE_UINFO 100
+#define CORE_OBJECT_DNS_TYPE_UID 101
+#define CORE_OBJECT_DNS_TYPE_GID 102
+#define CORE_OBJECT_DNS_TYPE_UNSPEC 103
+#define CORE_OBJECT_DNS_TYPE_NID 104
+#define CORE_OBJECT_DNS_TYPE_L32 105
+#define CORE_OBJECT_DNS_TYPE_L64 106
+#define CORE_OBJECT_DNS_TYPE_LP 107
+#define CORE_OBJECT_DNS_TYPE_EUI48 108
+#define CORE_OBJECT_DNS_TYPE_EUI64 109
+#define CORE_OBJECT_DNS_TYPE_TKEY 249
+#define CORE_OBJECT_DNS_TYPE_TSIG 250
+#define CORE_OBJECT_DNS_TYPE_IXFR 251
+#define CORE_OBJECT_DNS_TYPE_AXFR 252
+#define CORE_OBJECT_DNS_TYPE_MAILB 253
+#define CORE_OBJECT_DNS_TYPE_MAILA 254
+#define CORE_OBJECT_DNS_TYPE_ANY 255
+#define CORE_OBJECT_DNS_TYPE_URI 256
+#define CORE_OBJECT_DNS_TYPE_CAA 257
+#define CORE_OBJECT_DNS_TYPE_AVC 258
+#define CORE_OBJECT_DNS_TYPE_TA 32768
+#define CORE_OBJECT_DNS_TYPE_DLV 32769
+
+#define CORE_OBJECT_DNS_OPCODE_QUERY 0
+#define CORE_OBJECT_DNS_OPCODE_IQUERY 1
+#define CORE_OBJECT_DNS_OPCODE_STATUS 2
+#define CORE_OBJECT_DNS_OPCODE_NOTIFY 4
+#define CORE_OBJECT_DNS_OPCODE_UPDATE 5
+
+#define CORE_OBJECT_DNS_RCODE_NOERROR 0
+#define CORE_OBJECT_DNS_RCODE_FORMERR 1
+#define CORE_OBJECT_DNS_RCODE_SERVFAIL 2
+#define CORE_OBJECT_DNS_RCODE_NXDOMAIN 3
+#define CORE_OBJECT_DNS_RCODE_NOTIMP 4
+#define CORE_OBJECT_DNS_RCODE_REFUSED 5
+#define CORE_OBJECT_DNS_RCODE_YXDOMAIN 6
+#define CORE_OBJECT_DNS_RCODE_YXRRSET 7
+#define CORE_OBJECT_DNS_RCODE_NXRRSET 8
+#define CORE_OBJECT_DNS_RCODE_NOTAUTH 9
+#define CORE_OBJECT_DNS_RCODE_NOTZONE 10
+#define CORE_OBJECT_DNS_RCODE_BADVERS 16
+#define CORE_OBJECT_DNS_RCODE_BADSIG 16
+#define CORE_OBJECT_DNS_RCODE_BADKEY 17
+#define CORE_OBJECT_DNS_RCODE_BADTIME 18
+#define CORE_OBJECT_DNS_RCODE_BADMODE 19
+#define CORE_OBJECT_DNS_RCODE_BADNAME 20
+#define CORE_OBJECT_DNS_RCODE_BADALG 21
+#define CORE_OBJECT_DNS_RCODE_BADTRUNC 22
+#define CORE_OBJECT_DNS_RCODE_BADCOOKIE 23
+
+#define CORE_OBJECT_DNS_AFSDB_SUBTYPE_AFS3LOCSRV 1
+#define CORE_OBJECT_DNS_AFSDB_SUBTYPE_DCENCA_ROOT 2
+
+#define CORE_OBJECT_DNS_DHCID_TYPE_1OCTET 0
+#define CORE_OBJECT_DNS_DHCID_TYPE_DATAOCTET 1
+#define CORE_OBJECT_DNS_DHCID_TYPE_CLIENT_DUID 2
+
+#define CORE_OBJECT_DNS_EDNS0_OPT_LLQ 1
+#define CORE_OBJECT_DNS_EDNS0_OPT_UL 2
+#define CORE_OBJECT_DNS_EDNS0_OPT_NSID 3
+#define CORE_OBJECT_DNS_EDNS0_OPT_DAU 5
+#define CORE_OBJECT_DNS_EDNS0_OPT_DHU 6
+#define CORE_OBJECT_DNS_EDNS0_OPT_N3U 7
+#define CORE_OBJECT_DNS_EDNS0_OPT_CLIENT_SUBNET 8
+#define CORE_OBJECT_DNS_EDNS0_OPT_EXPIRE 9
+#define CORE_OBJECT_DNS_EDNS0_OPT_COOKIE 10
+#define CORE_OBJECT_DNS_EDNS0_OPT_TCP_KEEPALIVE 11
+#define CORE_OBJECT_DNS_EDNS0_OPT_PADDING 12
+#define CORE_OBJECT_DNS_EDNS0_OPT_CHAIN 13
+#define CORE_OBJECT_DNS_EDNS0_OPT_DEVICEID 26946
+
#endif
diff --git a/src/core/object/dns.hh b/src/core/object/dns.hh
index c107dfc0..ed8e537c 100644
--- a/src/core/object/dns.hh
+++ b/src/core/object/dns.hh
@@ -21,10 +21,56 @@
//lua:require("dnsjit.core.log")
//lua:require("dnsjit.core.object_h")
+typedef struct core_object_dns_label {
+ unsigned short is_end : 1;
+ unsigned short have_length : 1;
+ unsigned short have_offset : 1;
+ unsigned short have_extension_bits : 1;
+ unsigned short have_dn : 1;
+ unsigned short extension_bits : 2;
+
+ uint8_t length;
+ uint16_t offset;
+} core_object_dns_label_t;
+
+typedef struct core_object_dns_rr {
+ unsigned short have_type : 1;
+ unsigned short have_class : 1;
+ unsigned short have_ttl : 1;
+ unsigned short have_rdlength : 1;
+ unsigned short have_rdata : 1;
+ unsigned short have_rdata_labels : 1;
+ unsigned short have_padding : 1;
+
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength;
+
+ size_t labels;
+ size_t rdata_offset;
+ size_t rdata_labels;
+ size_t padding_offset;
+ size_t padding_length;
+} core_object_dns_rr_t;
+
+typedef struct core_object_dns_q {
+ unsigned short have_type : 1;
+ unsigned short have_class : 1;
+
+ uint16_t type;
+ uint16_t class;
+
+ size_t labels;
+} core_object_dns_q_t;
+
typedef struct core_object_dns {
const core_object_t* obj_prev;
int32_t obj_type;
+ const uint8_t *payload, *at;
+ size_t len, left;
+
unsigned short have_id : 1;
unsigned short have_qr : 1;
unsigned short have_opcode : 1;
@@ -56,26 +102,15 @@ typedef struct core_object_dns {
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
-
- size_t questions;
- size_t answers;
- size_t authorities;
- size_t additionals;
} core_object_dns_t;
core_log_t* core_object_dns_log();
-core_object_dns_t* core_object_dns_new(const core_object_t* obj);
+core_object_dns_t* core_object_dns_new();
core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self);
void core_object_dns_free(core_object_dns_t* self);
+void core_object_dns_reset(core_object_dns_t* self, const core_object_t* obj);
int core_object_dns_parse_header(core_object_dns_t* self);
-int core_object_dns_parse(core_object_dns_t* self);
-
-int core_object_dns_rr_reset(core_object_dns_t* self);
-int core_object_dns_rr_next(core_object_dns_t* self);
-int core_object_dns_rr_ok(core_object_dns_t* self);
-const char* core_object_dns_rr_label(core_object_dns_t* self);
-uint16_t core_object_dns_rr_type(core_object_dns_t* self);
-uint16_t core_object_dns_rr_class(core_object_dns_t* self);
-uint32_t core_object_dns_rr_ttl(core_object_dns_t* self);
+int core_object_dns_parse_q(core_object_dns_t* self, core_object_dns_q_t* q, core_object_dns_label_t* label, size_t labels);
+int core_object_dns_parse_rr(core_object_dns_t* self, core_object_dns_rr_t* rr, core_object_dns_label_t* label, size_t labels);
diff --git a/src/core/object/dns.lua b/src/core/object/dns.lua
index 70b47e5b..d195e647 100644
--- a/src/core/object/dns.lua
+++ b/src/core/object/dns.lua
@@ -18,37 +18,31 @@
-- dnsjit.core.object.dns
-- Container of a DNS message
--- local query = require("dnsjit.core.object.dns")
--- local q = query.new(pkt)
--- print(q:src(), q:dst(), q.id, q.rcode)
+-- .SS Parse DNS header and check if query or response
+-- local dns = require("dnsjit.core.object.dns").new(payload)
+-- if dns:parse_header() == 0 then
+-- if dns.qr == 0 then
+-- print(dns.id, dns.opcode_tostring(dns.opcode))
+-- else
+-- print(dns.id, dns.rcode_tostring(dns.rcode))
+-- end
+-- end
+-- .SS Print a DNS payload
+-- local dns = require("dnsjit.core.object.dns").new(payload)
+-- dns:print()
+-- .SS Parse a DNS payload
+-- local dns = require("dnsjit.core.object.dns").new(payload)
+-- local qs, q_labels, rrs, rr_labels = dns:parse()
+-- if qs and q_labels then
+-- ...
+-- if rrs and rr_labels then
+-- ...
+-- end
+-- end
--
-- The object that describes a DNS message.
-- .SS Attributes
-- .TP
--- src_id
--- Source ID, used to track the query through the input, filter and output
--- modules.
--- See also
--- .BR dnsjit.core.tracking (3).
--- .TP
--- qr_id
--- Query/Response ID, used to track the query through the input, filter
--- and output modules.
--- See also
--- .BR dnsjit.core.tracking (3).
--- .TP
--- dst_id
--- Destination ID, used to track the query through the input, filter
--- and output modules.
--- See also
--- .BR dnsjit.core.tracking (3).
--- .TP
--- sport
--- Source port.
--- .TP
--- dport
--- Destination port.
--- .TP
-- have_id
-- Set if there is a DNS ID.
-- .TP
@@ -138,34 +132,348 @@
-- .TP
-- arcount
-- The ARCOUNT.
--- .TP
--- questions
--- The actual number of questions found.
--- .TP
--- answers
--- The actual number of answers found.
--- .TP
--- authorities
--- The actual number of authorities found.
--- .TP
--- additionals
--- The actual number of additionals found.
+-- .SS Constants
+-- The following tables exists for DNS parameters, taken from
+-- .I https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+-- on the 2016-12-09.
+-- .LP
+-- .IR CLASS ,
+-- .IR CLASS_STR ,
+-- .IR TYPE ,
+-- .IR TYPE_STR ,
+-- .IR OPCODE ,
+-- .IR OPCODE_STR ,
+-- .IR RCODE ,
+-- .IR RCODE_STR ,
+-- .IR AFSDB ,
+-- .IR AFSDB_STR ,
+-- .IR DHCID ,
+-- .IR DHCID_STR ,
+-- .IR ENDS0 ,
+-- .IR ENDS0_STR
+-- .LP
+-- The
+-- .I *_STR
+-- tables can be used to get a textual representation of the numbers, see also
+-- .IR class_tostring() ,
+-- .IR type_tostring() ,
+-- .IR opcode_tostring() ,
+-- .IR rcode_tostring() ,
+-- .IR afsdb_tostring() ,
+-- .I dhcid_tostring()
+-- and
+-- .IR edns0_tostring() .
module(...,package.seeall)
require("dnsjit.core.object.dns_h")
+local label = require("dnsjit.core.object.dns.label")
+local Q = require("dnsjit.core.object.dns.q")
+local RR = require("dnsjit.core.object.dns.rr")
local ffi = require("ffi")
local C = ffi.C
local t_name = "core_object_dns_t"
local core_object_dns_t
-local Dns = {}
+local Dns = {
+ CLASS = {
+ IN = 1,
+ CH = 3,
+ HS = 4,
+ NONE = 254,
+ ANY = 255,
+ },
+ TYPE = {
+ 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,
+ RP = 17,
+ AFSDB = 18,
+ X25 = 19,
+ ISDN = 20,
+ RT = 21,
+ NSAP = 22,
+ NSAP_PTR = 23,
+ SIG = 24,
+ KEY = 25,
+ PX = 26,
+ GPOS = 27,
+ AAAA = 28,
+ LOC = 29,
+ NXT = 30,
+ EID = 31,
+ NIMLOC = 32,
+ SRV = 33,
+ ATMA = 34,
+ NAPTR = 35,
+ KX = 36,
+ CERT = 37,
+ A6 = 38,
+ DNAME = 39,
+ SINK = 40,
+ OPT = 41,
+ APL = 42,
+ DS = 43,
+ SSHFP = 44,
+ IPSECKEY = 45,
+ RRSIG = 46,
+ NSEC = 47,
+ DNSKEY = 48,
+ DHCID = 49,
+ NSEC3 = 50,
+ NSEC3PARAM = 51,
+ TLSA = 52,
+ SMIMEA = 53,
+ HIP = 55,
+ NINFO = 56,
+ RKEY = 57,
+ TALINK = 58,
+ CDS = 59,
+ CDNSKEY = 60,
+ OPENPGPKEY = 61,
+ CSYNC = 62,
+ SPF = 99,
+ UINFO = 100,
+ UID = 101,
+ GID = 102,
+ UNSPEC = 103,
+ NID = 104,
+ L32 = 105,
+ L64 = 106,
+ LP = 107,
+ EUI48 = 108,
+ EUI64 = 109,
+ TKEY = 249,
+ TSIG = 250,
+ IXFR = 251,
+ AXFR = 252,
+ MAILB = 253,
+ MAILA = 254,
+ ANY = 255,
+ URI = 256,
+ CAA = 257,
+ AVC = 258,
+ TA = 32768,
+ DLV = 32769,
+ },
+ OPCODE = {
+ QUERY = 0,
+ IQUERY = 1,
+ STATUS = 2,
+ NOTIFY = 4,
+ UPDATE = 5,
+ },
+ RCODE = {
+ NOERROR = 0,
+ FORMERR = 1,
+ SERVFAIL = 2,
+ NXDOMAIN = 3,
+ NOTIMP = 4,
+ REFUSED = 5,
+ YXDOMAIN = 6,
+ YXRRSET = 7,
+ NXRRSET = 8,
+ NOTAUTH = 9,
+ NOTZONE = 10,
+ BADVERS = 16,
+ BADSIG = 16,
+ BADKEY = 17,
+ BADTIME = 18,
+ BADMODE = 19,
+ BADNAME = 20,
+ BADALG = 21,
+ BADTRUNC = 22,
+ BADCOOKIE = 23,
+ },
+ AFSDB = {
+ SUBTYPE_AFS3LOCSRV = 1,
+ SUBTYPE_DCENCA_ROOT = 2,
+ },
+ DHCID = {
+ TYPE_1OCTET = 0,
+ TYPE_DATAOCTET = 1,
+ TYPE_CLIENT_DUID = 2,
+ },
+ EDNS0 = {
+ OPT_LLQ = 1,
+ OPT_UL = 2,
+ OPT_NSID = 3,
+ OPT_DAU = 5,
+ OPT_DHU = 6,
+ OPT_N3U = 7,
+ OPT_CLIENT_SUBNET = 8,
+ OPT_EXPIRE = 9,
+ OPT_COOKIE = 10,
+ OPT_TCP_KEEPALIVE = 11,
+ OPT_PADDING = 12,
+ OPT_CHAIN = 13,
+ OPT_DEVICEID = 26946,
+ },
+}
+local _CLASS = {}
+_CLASS[Dns.CLASS.IN] = "IN"
+_CLASS[Dns.CLASS.CH] = "CH"
+_CLASS[Dns.CLASS.HS] = "HS"
+_CLASS[Dns.CLASS.NONE] = "NONE"
+_CLASS[Dns.CLASS.ANY] = "ANY"
+local _TYPE = {}
+_TYPE[Dns.TYPE.A] = "A"
+_TYPE[Dns.TYPE.NS] = "NS"
+_TYPE[Dns.TYPE.MD] = "MD"
+_TYPE[Dns.TYPE.MF] = "MF"
+_TYPE[Dns.TYPE.CNAME] = "CNAME"
+_TYPE[Dns.TYPE.SOA] = "SOA"
+_TYPE[Dns.TYPE.MB] = "MB"
+_TYPE[Dns.TYPE.MG] = "MG"
+_TYPE[Dns.TYPE.MR] = "MR"
+_TYPE[Dns.TYPE.NULL] = "NULL"
+_TYPE[Dns.TYPE.WKS] = "WKS"
+_TYPE[Dns.TYPE.PTR] = "PTR"
+_TYPE[Dns.TYPE.HINFO] = "HINFO"
+_TYPE[Dns.TYPE.MINFO] = "MINFO"
+_TYPE[Dns.TYPE.MX] = "MX"
+_TYPE[Dns.TYPE.TXT] = "TXT"
+_TYPE[Dns.TYPE.RP] = "RP"
+_TYPE[Dns.TYPE.AFSDB] = "AFSDB"
+_TYPE[Dns.TYPE.X25] = "X25"
+_TYPE[Dns.TYPE.ISDN] = "ISDN"
+_TYPE[Dns.TYPE.RT] = "RT"
+_TYPE[Dns.TYPE.NSAP] = "NSAP"
+_TYPE[Dns.TYPE.NSAP_PTR] = "NSAP_PTR"
+_TYPE[Dns.TYPE.SIG] = "SIG"
+_TYPE[Dns.TYPE.KEY] = "KEY"
+_TYPE[Dns.TYPE.PX] = "PX"
+_TYPE[Dns.TYPE.GPOS] = "GPOS"
+_TYPE[Dns.TYPE.AAAA] = "AAAA"
+_TYPE[Dns.TYPE.LOC] = "LOC"
+_TYPE[Dns.TYPE.NXT] = "NXT"
+_TYPE[Dns.TYPE.EID] = "EID"
+_TYPE[Dns.TYPE.NIMLOC] = "NIMLOC"
+_TYPE[Dns.TYPE.SRV] = "SRV"
+_TYPE[Dns.TYPE.ATMA] = "ATMA"
+_TYPE[Dns.TYPE.NAPTR] = "NAPTR"
+_TYPE[Dns.TYPE.KX] = "KX"
+_TYPE[Dns.TYPE.CERT] = "CERT"
+_TYPE[Dns.TYPE.A6] = "A6"
+_TYPE[Dns.TYPE.DNAME] = "DNAME"
+_TYPE[Dns.TYPE.SINK] = "SINK"
+_TYPE[Dns.TYPE.OPT] = "OPT"
+_TYPE[Dns.TYPE.APL] = "APL"
+_TYPE[Dns.TYPE.DS] = "DS"
+_TYPE[Dns.TYPE.SSHFP] = "SSHFP"
+_TYPE[Dns.TYPE.IPSECKEY] = "IPSECKEY"
+_TYPE[Dns.TYPE.RRSIG] = "RRSIG"
+_TYPE[Dns.TYPE.NSEC] = "NSEC"
+_TYPE[Dns.TYPE.DNSKEY] = "DNSKEY"
+_TYPE[Dns.TYPE.DHCID] = "DHCID"
+_TYPE[Dns.TYPE.NSEC3] = "NSEC3"
+_TYPE[Dns.TYPE.NSEC3PARAM] = "NSEC3PARAM"
+_TYPE[Dns.TYPE.TLSA] = "TLSA"
+_TYPE[Dns.TYPE.SMIMEA] = "SMIMEA"
+_TYPE[Dns.TYPE.HIP] = "HIP"
+_TYPE[Dns.TYPE.NINFO] = "NINFO"
+_TYPE[Dns.TYPE.RKEY] = "RKEY"
+_TYPE[Dns.TYPE.TALINK] = "TALINK"
+_TYPE[Dns.TYPE.CDS] = "CDS"
+_TYPE[Dns.TYPE.CDNSKEY] = "CDNSKEY"
+_TYPE[Dns.TYPE.OPENPGPKEY] = "OPENPGPKEY"
+_TYPE[Dns.TYPE.CSYNC] = "CSYNC"
+_TYPE[Dns.TYPE.SPF] = "SPF"
+_TYPE[Dns.TYPE.UINFO] = "UINFO"
+_TYPE[Dns.TYPE.UID] = "UID"
+_TYPE[Dns.TYPE.GID] = "GID"
+_TYPE[Dns.TYPE.UNSPEC] = "UNSPEC"
+_TYPE[Dns.TYPE.NID] = "NID"
+_TYPE[Dns.TYPE.L32] = "L32"
+_TYPE[Dns.TYPE.L64] = "L64"
+_TYPE[Dns.TYPE.LP] = "LP"
+_TYPE[Dns.TYPE.EUI48] = "EUI48"
+_TYPE[Dns.TYPE.EUI64] = "EUI64"
+_TYPE[Dns.TYPE.TKEY] = "TKEY"
+_TYPE[Dns.TYPE.TSIG] = "TSIG"
+_TYPE[Dns.TYPE.IXFR] = "IXFR"
+_TYPE[Dns.TYPE.AXFR] = "AXFR"
+_TYPE[Dns.TYPE.MAILB] = "MAILB"
+_TYPE[Dns.TYPE.MAILA] = "MAILA"
+_TYPE[Dns.TYPE.ANY] = "ANY"
+_TYPE[Dns.TYPE.URI] = "URI"
+_TYPE[Dns.TYPE.CAA] = "CAA"
+_TYPE[Dns.TYPE.AVC] = "AVC"
+_TYPE[Dns.TYPE.TA] = "TA"
+_TYPE[Dns.TYPE.DLV] = "DLV"
+local _OPCODE = {}
+_OPCODE[Dns.OPCODE.QUERY] = "QUERY"
+_OPCODE[Dns.OPCODE.IQUERY] = "IQUERY"
+_OPCODE[Dns.OPCODE.STATUS] = "STATUS"
+_OPCODE[Dns.OPCODE.NOTIFY] = "NOTIFY"
+_OPCODE[Dns.OPCODE.UPDATE] = "UPDATE"
+local _RCODE = {}
+_RCODE[Dns.RCODE.NOERROR] = "NOERROR"
+_RCODE[Dns.RCODE.FORMERR] = "FORMERR"
+_RCODE[Dns.RCODE.SERVFAIL] = "SERVFAIL"
+_RCODE[Dns.RCODE.NXDOMAIN] = "NXDOMAIN"
+_RCODE[Dns.RCODE.NOTIMP] = "NOTIMP"
+_RCODE[Dns.RCODE.REFUSED] = "REFUSED"
+_RCODE[Dns.RCODE.YXDOMAIN] = "YXDOMAIN"
+_RCODE[Dns.RCODE.YXRRSET] = "YXRRSET"
+_RCODE[Dns.RCODE.NXRRSET] = "NXRRSET"
+_RCODE[Dns.RCODE.NOTAUTH] = "NOTAUTH"
+_RCODE[Dns.RCODE.NOTZONE] = "NOTZONE"
+_RCODE[Dns.RCODE.BADVERS] = "BADVERS"
+_RCODE[Dns.RCODE.BADSIG] = "BADSIG"
+_RCODE[Dns.RCODE.BADKEY] = "BADKEY"
+_RCODE[Dns.RCODE.BADTIME] = "BADTIME"
+_RCODE[Dns.RCODE.BADMODE] = "BADMODE"
+_RCODE[Dns.RCODE.BADNAME] = "BADNAME"
+_RCODE[Dns.RCODE.BADALG] = "BADALG"
+_RCODE[Dns.RCODE.BADTRUNC] = "BADTRUNC"
+_RCODE[Dns.RCODE.BADCOOKIE] = "BADCOOKIE"
+local _AFSDB = {}
+_AFSDB[Dns.AFSDB.SUBTYPE_AFS3LOCSRV] = "SUBTYPE_AFS3LOCSRV"
+_AFSDB[Dns.AFSDB.SUBTYPE_DCENCA_ROOT] = "SUBTYPE_DCENCA_ROOT"
+local _DHCID = {}
+_DHCID[Dns.DHCID.TYPE_1OCTET] = "TYPE_1OCTET"
+_DHCID[Dns.DHCID.TYPE_DATAOCTET] = "TYPE_DATAOCTET"
+_DHCID[Dns.DHCID.TYPE_CLIENT_DUID] = "TYPE_CLIENT_DUID"
+local _EDNS0 = {}
+_EDNS0[Dns.EDNS0.OPT_LLQ] = "OPT_LLQ"
+_EDNS0[Dns.EDNS0.OPT_UL] = "OPT_UL"
+_EDNS0[Dns.EDNS0.OPT_NSID] = "OPT_NSID"
+_EDNS0[Dns.EDNS0.OPT_DAU] = "OPT_DAU"
+_EDNS0[Dns.EDNS0.OPT_DHU] = "OPT_DHU"
+_EDNS0[Dns.EDNS0.OPT_N3U] = "OPT_N3U"
+_EDNS0[Dns.EDNS0.OPT_CLIENT_SUBNET] = "OPT_CLIENT_SUBNET"
+_EDNS0[Dns.EDNS0.OPT_EXPIRE] = "OPT_EXPIRE"
+_EDNS0[Dns.EDNS0.OPT_COOKIE] = "OPT_COOKIE"
+_EDNS0[Dns.EDNS0.OPT_TCP_KEEPALIVE] = "OPT_TCP_KEEPALIVE"
+_EDNS0[Dns.EDNS0.OPT_PADDING] = "OPT_PADDING"
+_EDNS0[Dns.EDNS0.OPT_CHAIN] = "OPT_CHAIN"
+_EDNS0[Dns.EDNS0.OPT_DEVICEID] = "OPT_DEVICEID"
+Dns.CLASS_STR = _CLASS
+Dns.TYPE_STR = _TYPE
+Dns.OPCODE_STR = _OPCODE
+Dns.RCODE_STR = _RCODE
+Dns.AFSDB_STR = _AFSDB
+Dns.DHCID_STR = _DHCID
+Dns.EDNS0_STR = _EDNS0
--- Create a new DNS object ontop of a packet or payload object.
+-- Create a new DNS object, optionally on-top of another object.
function Dns.new(obj)
- local self = C.core_object_dns_new(obj)
- if self ~= nil then
- ffi.gc(self, C.core_object_dns_free)
- end
+ local self = C.core_object_dns_new()
+ self.obj_prev = obj
+ ffi.gc(self, C.core_object_dns_free)
return self
end
@@ -199,77 +507,134 @@ function Dns:free()
C.core_object_dns_free(self)
end
--- Return the Log object to control logging of this instance or module.
+-- Return the Log object to control logging of this module.
function Dns:log()
return C.core_object_dns_log()
end
--- Parse the DNS headers or the query, returns 0 on success.
+-- Begin parsing the underlaying object, first the header is parsed then
+-- optionally continue calling
+-- .IR parse_q ()
+-- for the number of questions (see
+-- .IR qdcount ).
+-- After that continue calling
+-- .IR parse_rr ()
+-- for the number of answers, authorities and additionals resource records
+-- (see
+-- .IR ancount ", "
+-- .I nscount
+-- and
+-- .IR arcount ).
+-- Returns 0 on success or negative integer on error which can be for
+-- malformed or truncated DNS (-2) or if more space for labels is needed (-3).
function Dns:parse_header()
return C.core_object_dns_parse_header(self)
end
--- Parse the full DNS message or just the body if the header was already
--- parsed, returns 0 on success.
-function Dns:parse()
- return C.core_object_dns_parse(self)
+-- Parse the next resource record as a question.
+-- Returns 0 on success or negative integer on error which can be for
+-- malformed or truncated DNS (-2) or if more space for labels is needed (-3).
+function Dns:parse_q(q, labels, num_labels)
+ return C.core_object_dns_parse_q(self, q, labels, num_labels)
end
--- Return the IP source as a string.
-function Dns:src()
- return ffi.string(C.core_object_dns_src(self))
+-- Parse the next resource record.
+-- Returns 0 on success or negative integer on error which can be for
+-- malformed or truncated DNS (-2) or if more space for labels is needed (-3).
+function Dns:parse_rr(rr, labels, num_labels)
+ return C.core_object_dns_parse_rr(self, rr, labels, num_labels)
end
--- Return the IP destination as a string.
-function Dns:dst()
- return ffi.string(C.core_object_dns_dst(self))
-end
+-- Begin parsing the underlaying object using
+-- .IR parse_header "(), "
+-- .IR parse_q ()
+-- and
+-- .IR parse_rr ().
+-- The optional
+-- .I num_labels
+-- can be used to set a specific number of labels used for each question
+-- and resource record (default 16).
+-- Returns result code, an array of questions, an array of question labels,
+-- an array of resource records and an array of resource records labels.
+-- Result code is 0 on success or negative integer on error which can be for
+-- malformed or truncated DNS (-2) or if more space for labels is needed (-3).
+function Dns:parse(num_labels)
+ local qs, qls, rrs, rrls = {}, {}, {}, {}
+ if num_labels == nil then
+ num_labels = 16
+ end
--- Reset the walking of resource record(s), returns 0 on success.
-function Dns:rr_reset()
- return C.core_object_dns_rr_reset(self)
-end
+ ret = self:parse_header()
+ if ret ~= 0 then
+ return ret, qs, qls, rrs, rrls
+ end
+ for n = 1, self.qdcount do
+ local labels = label.new(num_labels)
+ local q = Q.new()
+ local ret = C.core_object_dns_parse_q(self, q, labels, num_labels)
--- Start walking the resource record(s) (RR) found or continue with the next.
--- Returns 0 on success, < 0 on end of RRs and > 0 on error.
-function Dns:rr_next()
- return C.core_object_dns_rr_next(self)
-end
+ if ret ~= 0 then
+ return ret, qs, qls, rrs, rrls
+ end
+ table.insert(qs, q)
+ table.insert(qls, labels)
+ end
+ for n = 1, self.ancount do
+ local labels = label.new(num_labels)
+ local rr = RR.new()
+ local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels)
--- Check if the RR at the current position was parsed successfully or not,
--- returns 1 if successful.
-function Dns:rr_ok()
- return C.core_object_dns_rr_ok(self)
-end
+ if ret ~= 0 then
+ return ret, qs, qls, rrs, rrls
+ end
+ table.insert(rrs, rr)
+ table.insert(rrls, labels)
+ end
+ for n = 1, self.nscount do
+ local labels = label.new(num_labels)
+ local rr = RR.new()
+ local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels)
--- Return the FQDN of the current RR or nil on error.
-function Dns:rr_label()
- local ptr = C.core_object_dns_rr_label(self)
- if ptr == nil then
- return
+ if ret ~= 0 then
+ return ret, qs, qls, rrs, rrls
+ end
+ table.insert(rrs, rr)
+ table.insert(rrls, labels)
end
- return ffi.string(ptr)
-end
+ for n = 1, self.arcount do
+ local labels = label.new(num_labels)
+ local rr = RR.new()
+ local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels)
--- Return an integer with the RR type.
-function Dns:rr_type()
- return C.core_object_dns_rr_type(self)
-end
+ if ret ~= 0 then
+ return ret, qs, qls, rrs, rrls
+ end
+ table.insert(rrs, rr)
+ table.insert(rrls, labels)
+ end
--- Return an integer with the RR class.
-function Dns:rr_class()
- return C.core_object_dns_rr_class(self)
+ return 0, qs, qls, rrs, rrls
end
--- Return an integer with the RR TTL.
-function Dns:rr_ttl()
- return C.core_object_dns_rr_ttl(self)
-end
+-- Begin parsing the underlaying object using
+-- .IR parse_header "(), "
+-- .IR parse_q ()
+-- and
+-- .IR parse_rr (),
+-- and print it's content.
+-- The optional
+-- .I num_labels
+-- can be used to set a specific number of labels used for each question
+-- and resource record (default 16).
+function Dns:print(num_labels)
+ if num_labels == nil then
+ num_labels = 16
+ end
+ local labels = label.new(num_labels)
+ local q = Q.new()
+ local rr = RR.new()
--- Print the content of this DNS message if previously parsed, returns 0 on
--- success.
-function Dns:print()
- if self:rr_reset() ~= 0 then
+ if self:parse_header() ~= 0 then
return
end
@@ -298,51 +663,117 @@ function Dns:print()
print("id:", self.id)
print("", "qr:", self.qr)
- print("", "opcode:", self.opcode)
+ print("", "opcode:", Dns.opcode_tostring(self.opcode))
print("", "flags:", table.concat(flags, " "))
- print("", "rcode:", self.opcode)
+ print("", "rcode:", Dns.rcode_tostring(self.rcode))
print("", "qdcount:", self.qdcount)
print("", "ancount:", self.ancount)
print("", "nscount:", self.nscount)
print("", "arcount:", self.arcount)
- local n = self.questions
+
print("", "questions:")
- while n > 0 and self:rr_next() == 0 do
- if self:rr_ok() == 1 then
- print("", "", self:rr_class(), self:rr_type(), self:rr_label())
+ for n = 1, self.qdcount do
+ if C.core_object_dns_parse_q(self, q, labels, num_labels) ~= 0 then
+ return
end
- n = n - 1
+ print("", "", Dns.class_tostring(q.class), Dns.type_tostring(q.type), label.tooffstr(self, labels, num_labels))
end
- n = self.answers
print("", "answers:")
- while n > 0 and self:rr_next() == 0 do
- if self:rr_ok() == 1 then
- print("", "", self:rr_class(), self:rr_type(), self:rr_ttl(), self:rr_label())
+ for n = 1, self.ancount do
+ if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then
+ return
+ end
+ if rr.rdata_labels == 0 then
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels))
+ else
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels))
end
- n = n - 1
end
- n = self.authorities
print("", "authorities:")
- while n > 0 and self:rr_next() == 0 do
- if self:rr_ok() == 1 then
- print("", "", self:rr_class(), self:rr_type(), self:rr_ttl(), self:rr_label())
+ for n = 1, self.nscount do
+ if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then
+ return
+ end
+ if rr.rdata_labels == 0 then
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels))
+ else
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels))
end
- n = n - 1
end
- n = self.additionals
print("", "additionals:")
- while n > 0 and self:rr_next() == 0 do
- if self:rr_ok() == 1 then
- print("", "", self:rr_class(), self:rr_type(), self:rr_ttl(), self:rr_label())
+ for n = 1, self.arcount do
+ if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then
+ return
end
- n = n - 1
+ if rr.rdata_labels == 0 then
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels))
+ else
+ print("", "", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels))
+ end
+ end
+end
+
+-- Return the textual name for a class.
+function Dns.class_tostring(class)
+ if Dns.CLASS_STR[class] == nil then
+ return "UNKNOWN("..class..")"
+ end
+ return Dns.CLASS_STR[class]
+end
+
+-- Return the textual name for a type.
+function Dns.type_tostring(type)
+ if Dns.TYPE_STR[type] == nil then
+ return "UNKNOWN("..type..")"
+ end
+ return Dns.TYPE_STR[type]
+end
+
+-- Return the textual name for an opcode.
+function Dns.opcode_tostring(opcode)
+ if Dns.OPCODE_STR[opcode] == nil then
+ return "UNKNOWN("..opcode..")"
+ end
+ return Dns.OPCODE_STR[opcode]
+end
+
+-- Return the textual name for a rcode.
+function Dns.rcode_tostring(rcode)
+ if Dns.RCODE_STR[rcode] == nil then
+ return "UNKNOWN("..rcode..")"
+ end
+ return Dns.RCODE_STR[rcode]
+end
+
+-- Return the textual name for an afsdb subtype.
+function Dns.afsdb_tostring(afsdb)
+ if Dns.AFSDB_STR[afsdb] == nil then
+ return "UNKNOWN("..afsdb..")"
+ end
+ return Dns.AFSDB_STR[afsdb]
+end
+
+-- Return the textual name for a dhcid type.
+function Dns.dhcid_tostring(dhcid)
+ if Dns.DHCID_STR[dhcid] == nil then
+ return "UNKNOWN("..dhcid..")"
+ end
+ return Dns.DHCID_STR[dhcid]
+end
+
+-- Return the textual name for an EDNS0 OPT record.
+function Dns.edns0_tostring(edns0)
+ if Dns.EDNS0_STR[edns0] == nil then
+ return "UNKNOWN("..edns0..")"
end
+ return Dns.EDNS0_STR[edns0]
end
core_object_dns_t = ffi.metatype(t_name, { __index = Dns })
-- dnsjit.core.object (3),
--- dnsjit.core.object.packet (3),
-- dnsjit.core.object.payload (3),
--- dnsjit.core.tracking (3)
+-- dnsjit.core.object.dns.label (3),
+-- dnsjit.core.object.dns.q (3),
+-- dnsjit.core.object.dns.rr (3)
return Dns
diff --git a/src/core/object/dns/label.lua b/src/core/object/dns/label.lua
new file mode 100644
index 00000000..5aaff34d
--- /dev/null
+++ b/src/core/object/dns/label.lua
@@ -0,0 +1,118 @@
+-- Copyright (c) 2018, OARC, Inc.
+-- All rights reserved.
+--
+-- This file is part of dnsjit.
+--
+-- dnsjit is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- dnsjit is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with dnsjit. If not, see .
+
+-- dnsjit.core.object.dns.label
+-- Container of a DNS label
+--
+-- The object that describes a DNS label.
+-- To extract a domain name label first check that
+-- .I have_dn
+-- is set, then use
+-- .I "offset + 1"
+-- to indicate where in the payload the label start and
+-- .I length
+-- for how many bytes long it is.
+-- .SS Attributes
+-- .TP
+-- is_end
+-- .TP
+-- have_length
+-- Set if there is a length.
+-- .TP
+-- have_offset
+-- Set if there is an offset.
+-- .TP
+-- have_extension_bits
+-- Set if there is extension bits.
+-- .TP
+-- have_dn
+-- Set if the label contained a domain name.
+-- .TP
+-- extension_bits
+-- The extension bits.
+-- .TP
+-- length
+-- The length of the domain name.
+-- .TP
+-- offset
+-- If
+-- .I have_dn
+-- is set then this contains the offset within the payload to where this label
+-- start otherwise it contains the offset to another label.
+module(...,package.seeall)
+
+require("dnsjit.core.object.dns_h")
+local ffi = require("ffi")
+
+local Label = {}
+
+-- Create a new array of labels.
+function Label.new(size)
+ return ffi.new("core_object_dns_label_t[?]", size)
+end
+
+-- Returns labels as a string and an offset to the next label.
+-- The string may be nil if the first label was an offset.
+-- The offset may be nil if the last label was an extension bits or end marker.
+function Label.tostring(dns, labels, num_labels, offset_labels)
+ if offset_labels == nil then
+ offset_labels = 0
+ end
+ local dn
+ for n = 1, tonumber(num_labels) do
+ local label = labels[n - 1 + offset_labels]
+
+ if label.have_dn == 1 then
+ if dn == nil then
+ dn = ""
+ end
+ dn = dn .. ffi.string(dns.payload + label.offset + 1, label.length) .. "."
+ elseif label.have_offset == 1 then
+ return dn, label.offset
+ else
+ return dn, nil
+ end
+ end
+ return dn, nil
+end
+
+-- Returns labels as a string which also includes a textual notation of the
+-- offset in the form of
+-- .IR "label" .
+function Label.tooffstr(dns, labels, num_labels, offset_labels)
+ if offset_labels == nil then
+ offset_labels = 0
+ end
+ local dn = ""
+ for n = 1, tonumber(num_labels) do
+ local label = labels[n - 1 + offset_labels]
+
+ if label.have_dn == 1 then
+ dn = dn .. "<" .. tonumber(label.offset) .. ">" .. ffi.string(dns.payload + label.offset + 1, label.length) .. "."
+ elseif label.have_offset == 1 then
+ dn = dn .. "<" .. tonumber(label.offset) .. ">"
+ break
+ else
+ break
+ end
+ end
+ return dn
+end
+
+-- dnsjit.core.object.dns (3)
+return Label
diff --git a/src/core/object/dns/q.lua b/src/core/object/dns/q.lua
new file mode 100644
index 00000000..8139b3d7
--- /dev/null
+++ b/src/core/object/dns/q.lua
@@ -0,0 +1,52 @@
+-- Copyright (c) 2018, OARC, Inc.
+-- All rights reserved.
+--
+-- This file is part of dnsjit.
+--
+-- dnsjit is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- dnsjit is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with dnsjit. If not, see .
+
+-- dnsjit.core.object.dns.q
+-- Container of a DNS question
+--
+-- The object that describes a DNS question.
+-- .SS Attributes
+-- .TP
+-- have_type
+-- Set if there is a type.
+-- .TP
+-- have_class
+-- Set if there is a class.
+-- .TP
+-- type
+-- The type.
+-- .TP
+-- class
+-- The class.
+-- .TP
+-- labels
+-- The number of labels found in the question.
+module(...,package.seeall)
+
+require("dnsjit.core.object.dns_h")
+local ffi = require("ffi")
+
+local Q = {}
+
+-- Create a new question.
+function Q.new(size)
+ return ffi.new("core_object_dns_q_t")
+end
+
+-- dnsjit.core.object.dns (3)
+return Q
diff --git a/src/core/object/dns/rr.lua b/src/core/object/dns/rr.lua
new file mode 100644
index 00000000..bacaa19f
--- /dev/null
+++ b/src/core/object/dns/rr.lua
@@ -0,0 +1,85 @@
+-- Copyright (c) 2018, OARC, Inc.
+-- All rights reserved.
+--
+-- This file is part of dnsjit.
+--
+-- dnsjit is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- dnsjit is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with dnsjit. If not, see .
+
+-- dnsjit.core.object.dns.rr
+-- Container of a DNS resource record
+--
+-- The object that describes a DNS resource record.
+-- .SS Attributes
+-- .TP
+-- have_type
+-- Set if there is a type.
+-- .TP
+-- have_class
+-- Set if there is a class.
+-- .TP
+-- have_ttl
+-- Set if there is a ttl.
+-- .TP
+-- have_rdlength
+-- Set if there is a rdlength.
+-- .TP
+-- have_rdata
+-- Set if there is resource record data.
+-- .TP
+-- have_rdata_labels
+-- Set if there are any labels within the rdata.
+-- .TP
+-- have_padding
+-- Set if there is padding.
+-- .TP
+-- type
+-- The type.
+-- .TP
+-- class
+-- The class.
+-- .TP
+-- ttl
+-- The TTL.
+-- .TP
+-- rdlength
+-- The resource record data length.
+-- .TP
+-- labels
+-- The number of labels found in the record.
+-- .TP
+-- rdata_offset
+-- The offset within the payload for the resource record data.
+-- .TP
+-- rdata_labels
+-- The number of labels found inside the resource record data.
+-- .TP
+-- padding_offset
+-- The offset within the payload where the padding starts.
+-- .TP
+-- padding_length
+-- The length of the padding.
+module(...,package.seeall)
+
+require("dnsjit.core.object.dns_h")
+local ffi = require("ffi")
+
+local Rr = {}
+
+-- Create a new resource record.
+function Rr.new()
+ return ffi.new("core_object_dns_rr_t")
+end
+
+-- dnsjit.core.object.dns (3)
+return Rr
diff --git a/src/filter/layer.c b/src/filter/layer.c
index fc515d3c..fb0341ca 100644
--- a/src/filter/layer.c
+++ b/src/filter/layer.c
@@ -36,6 +36,31 @@
#ifdef HAVE_NET_ETHERTYPES_H
#include
#endif
+#ifdef HAVE_ENDIAN_H
+#include
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include
+#endif
+#endif
+#endif
+#ifdef HAVE_BYTESWAP_H
+#include
+#endif
+#ifndef bswap_16
+#ifndef bswap16
+#define bswap_16(x) swap16(x)
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#else
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+#endif
#define N_IEEE802 3
@@ -94,36 +119,50 @@ void filter_layer_destroy(filter_layer_t* self)
p += 1; \
l -= 1
-#define need16(v, p, l) \
- if (l < 2) { \
- break; \
- } \
- v = (*p << 8) | *(p + 1); \
- p += 2; \
+static inline uint16_t _need16(const void* ptr)
+{
+ uint16_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be16toh(v);
+}
+
+#define need16(v, p, l) \
+ if (l < 2) { \
+ break; \
+ } \
+ v = _need16(p); \
+ p += 2; \
l -= 2
#define needr16(v, p, l) \
if (l < 2) { \
break; \
} \
- v = *p | (*(p + 1) << 8); \
+ v = bswap_16(_need16(p)); \
p += 2; \
l -= 2
-#define need32(v, p, l) \
- if (l < 4) { \
- break; \
- } \
- v = (*p << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | *(p + 3); \
- p += 4; \
+static inline uint32_t _need32(const void* ptr)
+{
+ uint32_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be32toh(v);
+}
+
+#define need32(v, p, l) \
+ if (l < 4) { \
+ break; \
+ } \
+ v = _need32(p); \
+ p += 4; \
l -= 4
-#define needr32(v, p, l) \
- if (l < 4) { \
- break; \
- } \
- v = *p | (*(p + 1) << 8) | (*(p + 2) << 16) | (*(p + 3) << 24); \
- p += 4; \
+#define needr32(v, p, l) \
+ if (l < 4) { \
+ break; \
+ } \
+ v = bswap_32(_need32(p)); \
+ p += 4; \
l -= 4
#define needxb(b, x, p, l) \
diff --git a/src/gen-makefile.sh b/src/gen-makefile.sh
index 19c1b8db..a28db7d0 100755
--- a/src/gen-makefile.sh
+++ b/src/gen-makefile.sh
@@ -35,10 +35,9 @@ BUILT_SOURCES = core/compat.hh core/log_errstr.c
bin_PROGRAMS = dnsjit
-dnsjit_SOURCES = dnsjit.c globals.c \
- omg-dns/omg_dns.c
-dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h output.lua \
- omg-dns/omg_dns.h
+dnsjit_SOURCES = dnsjit.c globals.c
+dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h \
+ output.lua
lua_hobjects = core/compat.luaho
lua_objects = core.luao lib.luao input.luao filter.luao output.luao
dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS)
diff --git a/src/input/fpcap.c b/src/input/fpcap.c
index 02b5b9ba..dadc7aa1 100644
--- a/src/input/fpcap.c
+++ b/src/input/fpcap.c
@@ -25,6 +25,31 @@
#include "core/object/pcap.h"
#include
+#ifdef HAVE_ENDIAN_H
+#include
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include
+#endif
+#endif
+#endif
+#ifdef HAVE_BYTESWAP_H
+#include
+#endif
+#ifndef bswap_16
+#ifndef bswap16
+#define bswap_16(x) swap16(x)
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#else
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+#endif
#define MAX_SNAPLEN 0x40000
@@ -60,16 +85,6 @@ void input_fpcap_destroy(input_fpcap_t* self)
free(self->buf);
}
-static inline uint16_t _flip16(uint16_t u16)
-{
- return ((u16 & 0xff) << 8) | (u16 >> 8);
-}
-
-static inline uint32_t _flip32(uint32_t u32)
-{
- return ((u32 & 0xff) << 24) | ((u32 & 0xff00) << 8) | ((u32 & 0xff0000) >> 8) | (u32 >> 24);
-}
-
int input_fpcap_open(input_fpcap_t* self, const char* file)
{
mlassert_self();
@@ -93,12 +108,12 @@ int input_fpcap_open(input_fpcap_t* self, const char* file)
self->is_nanosec = 1;
case 0xd4c3b2a1:
self->is_swapped = 1;
- self->version_major = _flip16(self->version_major);
- self->version_minor = _flip16(self->version_minor);
- self->thiszone = (int32_t)_flip32((uint32_t)self->thiszone);
- self->sigfigs = _flip32(self->sigfigs);
- self->snaplen = _flip32(self->snaplen);
- self->network = _flip32(self->network);
+ self->version_major = bswap_16(self->version_major);
+ self->version_minor = bswap_16(self->version_minor);
+ self->thiszone = (int32_t)bswap_32((uint32_t)self->thiszone);
+ self->sigfigs = bswap_32(self->sigfigs);
+ self->snaplen = bswap_32(self->snaplen);
+ self->network = bswap_32(self->network);
break;
case 0xa1b2c3d4:
case 0xa1b23c4d:
@@ -155,10 +170,10 @@ int input_fpcap_run(input_fpcap_t* self)
while ((ret = fread(&hdr, 1, 16, self->file)) == 16) {
if (self->is_swapped) {
- hdr.ts_sec = _flip32(hdr.ts_sec);
- hdr.ts_usec = _flip32(hdr.ts_usec);
- hdr.incl_len = _flip32(hdr.incl_len);
- hdr.orig_len = _flip32(hdr.orig_len);
+ hdr.ts_sec = bswap_32(hdr.ts_sec);
+ hdr.ts_usec = bswap_32(hdr.ts_usec);
+ hdr.incl_len = bswap_32(hdr.incl_len);
+ hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
@@ -216,10 +231,10 @@ static const core_object_t* _produce(void* ctx)
}
if (self->is_swapped) {
- hdr.ts_sec = _flip32(hdr.ts_sec);
- hdr.ts_usec = _flip32(hdr.ts_usec);
- hdr.incl_len = _flip32(hdr.incl_len);
- hdr.orig_len = _flip32(hdr.orig_len);
+ hdr.ts_sec = bswap_32(hdr.ts_sec);
+ hdr.ts_usec = bswap_32(hdr.ts_usec);
+ hdr.incl_len = bswap_32(hdr.incl_len);
+ hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
diff --git a/src/input/mmpcap.c b/src/input/mmpcap.c
index fc213f67..f5a93fd4 100644
--- a/src/input/mmpcap.c
+++ b/src/input/mmpcap.c
@@ -30,6 +30,31 @@
#include
#include
#include
+#ifdef HAVE_ENDIAN_H
+#include
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include
+#endif
+#endif
+#endif
+#ifdef HAVE_BYTESWAP_H
+#include
+#endif
+#ifndef bswap_16
+#ifndef bswap16
+#define bswap_16(x) swap16(x)
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#else
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+#endif
static core_log_t _log = LOG_T_INIT("input.mmpcap");
static input_mmpcap_t _defaults = {
@@ -65,16 +90,6 @@ void input_mmpcap_destroy(input_mmpcap_t* self)
}
}
-static inline uint16_t _flip16(uint16_t u16)
-{
- return ((u16 & 0xff) << 8) | (u16 >> 8);
-}
-
-static inline uint32_t _flip32(uint32_t u32)
-{
- return ((u32 & 0xff) << 24) | ((u32 & 0xff00) << 8) | ((u32 & 0xff0000) >> 8) | (u32 >> 24);
-}
-
int input_mmpcap_open(input_mmpcap_t* self, const char* file)
{
struct stat sb;
@@ -112,12 +127,12 @@ int input_mmpcap_open(input_mmpcap_t* self, const char* file)
self->is_nanosec = 1;
case 0xd4c3b2a1:
self->is_swapped = 1;
- self->version_major = _flip16(self->version_major);
- self->version_minor = _flip16(self->version_minor);
- self->thiszone = (int32_t)_flip32((uint32_t)self->thiszone);
- self->sigfigs = _flip32(self->sigfigs);
- self->snaplen = _flip32(self->snaplen);
- self->network = _flip32(self->network);
+ self->version_major = bswap_16(self->version_major);
+ self->version_minor = bswap_16(self->version_minor);
+ self->thiszone = (int32_t)bswap_32((uint32_t)self->thiszone);
+ self->sigfigs = bswap_32(self->sigfigs);
+ self->snaplen = bswap_32(self->snaplen);
+ self->network = bswap_32(self->network);
break;
case 0xa1b2c3d4:
case 0xa1b23c4d:
@@ -167,10 +182,10 @@ int input_mmpcap_run(input_mmpcap_t* self)
memcpy(&hdr, &self->buf[self->at], 16);
self->at += 16;
if (self->is_swapped) {
- hdr.ts_sec = _flip32(hdr.ts_sec);
- hdr.ts_usec = _flip32(hdr.ts_usec);
- hdr.incl_len = _flip32(hdr.incl_len);
- hdr.orig_len = _flip32(hdr.orig_len);
+ hdr.ts_sec = bswap_32(hdr.ts_sec);
+ hdr.ts_usec = bswap_32(hdr.ts_usec);
+ hdr.incl_len = bswap_32(hdr.incl_len);
+ hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
@@ -232,10 +247,10 @@ static const core_object_t* _produce(void* ctx)
memcpy(&hdr, &self->buf[self->at], 16);
self->at += 16;
if (self->is_swapped) {
- hdr.ts_sec = _flip32(hdr.ts_sec);
- hdr.ts_usec = _flip32(hdr.ts_usec);
- hdr.incl_len = _flip32(hdr.incl_len);
- hdr.orig_len = _flip32(hdr.orig_len);
+ hdr.ts_sec = bswap_32(hdr.ts_sec);
+ hdr.ts_usec = bswap_32(hdr.ts_usec);
+ hdr.incl_len = bswap_32(hdr.incl_len);
+ hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
diff --git a/src/omg-dns b/src/omg-dns
deleted file mode 160000
index 45d39dcf..00000000
--- a/src/omg-dns
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 45d39dcf3b2b8206a80e1b6c47e04efe69e621e6