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