]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
wip vendor-ljdns
authorMarek Vavruša <mvavrusa@cloudflare.com>
Tue, 5 Dec 2017 00:51:11 +0000 (16:51 -0800)
committerMarek Vavruša <mvavrusa@cloudflare.com>
Tue, 5 Dec 2017 05:39:21 +0000 (21:39 -0800)
12 files changed:
.gitmodules
.luacheckrc
contrib/ljdns [new submodule]
daemon/daemon.mk
daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
daemon/lua/kres.lua
daemon/lua/sandbox.lua
modules/dns64/dns64.lua
modules/policy/policy.lua
modules/priming/priming.lua
modules/ta_signal_query/ta_signal_query.lua

index 2c60e9d04e63ca01330583e63db50c3067788b04..706a3e06089308e8aef1f6bea3b4f6b795e1c185 100644 (file)
@@ -7,3 +7,6 @@
 [submodule "tests/config/tapered"]
        path = tests/config/tapered
        url = https://github.com/telemachus/tapered.git
+[submodule "contrib/ljdns"]
+       path = contrib/ljdns
+       url = https://github.com/vavrusa/ljdns.git
index e45db7d05d37841e98cb6695b83d04d976c5161e..4b2d9b4de0e603c2280422420cfb68933b850c89 100644 (file)
@@ -35,6 +35,7 @@ new_read_globals = {
        'reorder_RR',
        'option',
        'env',
+       'dns',
        'kres',
        'trustanchor',
        'libknot_SONAME',
diff --git a/contrib/ljdns b/contrib/ljdns
new file mode 160000 (submodule)
index 0000000..15fd202
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 15fd20225d3f782095a020e312431cff637321d1
index d1cef6c22847b3ac457de96064069c748ce6aa65..64b4d435beeb26268f503c50fc7847c258eaf4a6 100644 (file)
@@ -24,6 +24,8 @@ endif
 # Installed FFI bindings
 bindings-install: $(kresd_DIST) $(DESTDIR)$(MODULEDIR)
        $(INSTALL) -m 0644 $(kresd_DIST) $(DESTDIR)$(MODULEDIR)
+       $(INSTALL) -d $(DESTDIR)/$(MODULEDIR)/dns
+       $(INSTALL) -m 0644 contrib/ljdns/dns/*.lua $(DESTDIR)/$(MODULEDIR)/dns/
 
 LUA_HAS_SETFUNCS := \
        $(shell pkg-config luajit --atleast-version=2.1.0-beta3 && echo 1 || echo 0)
index 44919113f7d549afc2b5b87cb22d409fec0ab984..aae5bdd65bd4112e2a84c98c0049e55aac572011 100644 (file)
@@ -1,5 +1,25 @@
 local ffi = require('ffi')
 --[[ This file is generated by ./kres-gen.sh ]] ffi.cdef[[
+/* stdlib */
+typedef long time_t;
+struct timeval {
+       time_t tv_sec;
+       time_t tv_usec;
+};
+struct sockaddr {
+       uint16_t sa_family;
+       uint8_t _stub[]; /* Do not touch */
+};
+
+/*
+ * libc APIs
+ */
+void * malloc(size_t size);
+void free(void *ptr);
+char *strdup(const char *s);
+void *calloc(size_t nmemb, size_t size);
+int memcmp(const void *a, const void *b, size_t len);
+int inet_pton(int af, const char *src, void *dst);
 
 typedef struct knot_dump_style knot_dump_style_t;
 extern const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT;
@@ -11,13 +31,15 @@ typedef struct knot_mm {
 typedef void *(*map_alloc_f)(void *, size_t);
 typedef void (*map_free_f)(void *baton, void *ptr);
 typedef void (*trace_log_f) (const struct kr_query *, const char *, const char *);
+
+typedef struct knot_dname { uint8_t bytes[?]; } knot_dname_t;
+
 typedef enum {KNOT_ANSWER, KNOT_AUTHORITY, KNOT_ADDITIONAL} knot_section_t;
 typedef struct {
        uint16_t pos;
        uint16_t flags;
        uint16_t compress_ptr[16];
 } knot_rrinfo_t;
-typedef unsigned char knot_dname_t;
 typedef unsigned char knot_rdata_t;
 typedef struct knot_rdataset knot_rdataset_t;
 struct knot_rdataset {
@@ -165,7 +187,7 @@ struct kr_request {
 enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32};
 struct knot_rrset {
        knot_dname_t *_owner;
-       uint16_t type;
+       uint16_t _type;
        uint16_t rclass;
        knot_rdataset_t rrs;
        void *additional;
@@ -204,6 +226,8 @@ struct kr_context {
        struct kr_zonecut root_hints;
        char _stub[];
 };
+const char *knot_strerror(int code);
+int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src, size_t maxlen, const uint8_t *pkt);
 knot_dname_t *knot_dname_from_str(uint8_t *, const char *, size_t);
 _Bool knot_dname_is_equal(const knot_dname_t *, const knot_dname_t *);
 _Bool knot_dname_is_sub(const knot_dname_t *, const knot_dname_t *);
@@ -212,6 +236,8 @@ int knot_dname_size(const knot_dname_t *);
 char *knot_dname_to_str(char *, const knot_dname_t *, size_t);
 uint16_t knot_rdata_rdlen(const knot_rdata_t *);
 uint8_t *knot_rdata_data(const knot_rdata_t *);
+uint32_t knot_rdata_ttl(const knot_rdata_t *rr);
+void knot_rdata_set_ttl(knot_rdata_t *rr, uint32_t ttl);
 size_t knot_rdata_array_size(uint16_t);
 knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *, size_t);
 int knot_rrset_add_rdata(knot_rrset_t *, const uint8_t *, const uint16_t, const uint32_t, knot_mm_t *);
@@ -226,6 +252,15 @@ int knot_pkt_begin(knot_pkt_t *, knot_section_t);
 int knot_pkt_put_question(knot_pkt_t *, const knot_dname_t *, uint16_t, uint16_t);
 const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *, uint16_t);
 const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *, knot_section_t);
+uint8_t knot_edns_get_version(const knot_rrset_t *opt_rr);
+void knot_edns_set_version(knot_rrset_t *opt_rr, uint8_t version);
+int knot_edns_add_option(knot_rrset_t *opt_rr, uint16_t code, uint16_t length, const uint8_t *data, void *mm);
+bool knot_edns_has_option(const knot_rrset_t *opt_rr, uint16_t code);
+uint8_t *knot_edns_get_option(const knot_rrset_t *opt_rr, uint16_t code);
+uint16_t knot_edns_opt_get_length(const uint8_t *opt);
+size_t knot_edns_wire_size(knot_rrset_t *opt_rr);
+void knot_edns_set_ext_rcode(knot_rrset_t *opt_rr, uint8_t ext_rcode);
+uint8_t knot_edns_get_ext_rcode(const knot_rrset_t *opt_rr);
 struct kr_rplan *kr_resolve_plan(struct kr_request *);
 knot_mm_t *kr_resolve_pool(struct kr_request *);
 struct kr_query *kr_rplan_push(struct kr_rplan *, struct kr_query *, const knot_dname_t *, uint16_t, uint16_t);
index 7db4f6f831e75526ee9dc6bd7c629d18fff54651..54fb0f240df385df7f52404860424cb9bd00123d 100755 (executable)
 printf -- "local ffi = require('ffi')\n"
 printf -- "--[[ This file is generated by ./kres-gen.sh ]] ffi.cdef[[\n"
 
+## Standard library declarations
+printf "
+/* stdlib */
+typedef long time_t;
+struct timeval {
+       time_t tv_sec;
+       time_t tv_usec;
+};
+struct sockaddr {
+       uint16_t sa_family;
+       uint8_t _stub[]; /* Do not touch */
+};
+
+/*
+ * libc APIs
+ */
+void * malloc(size_t size);
+void free(void *ptr);
+char *strdup(const char *s);
+void *calloc(size_t nmemb, size_t size);
+int memcmp(const void *a, const void *b, size_t len);
+int inet_pton(int af, const char *src, void *dst);
+"
+
 ## Various types (mainly), from libknot and libkres
 
 printf "
@@ -35,10 +59,14 @@ typedef void (*map_free_f)(void *baton, void *ptr);
 typedef void (*trace_log_f) (const struct kr_query *, const char *, const char *);
 "
 
+# Several types are promoted to structs in order to be able to attach metatypes
+printf "
+typedef struct knot_dname { uint8_t bytes[?]; } knot_dname_t;
+"
+
 ./scripts/gen-cdefs.sh libkres types <<-EOF
        knot_section_t
        knot_rrinfo_t
-       knot_dname_t
        knot_rdata_t
        knot_rdataset_t
        struct knot_rdataset
@@ -66,7 +94,7 @@ genResType() {
 }
 
 # No simple way to fixup this rename in ./kres.lua AFAIK.
-genResType "struct knot_rrset" | sed 's/\<owner\>/_owner/'
+genResType "struct knot_rrset" | sed -e 's/\<owner\>/_owner/' -e 's/\<type\>/_type/'
 
 ## Some definitions would need too many deps, so shorten them.
 
@@ -80,7 +108,9 @@ printf "\tchar _stub[];\n};\n"
 
 ## libknot API
 ./scripts/gen-cdefs.sh libknot functions <<-EOF
+       knot_strerror
 # Domain names
+       knot_dname_unpack
        knot_dname_from_str
        knot_dname_is_equal
        knot_dname_is_sub
@@ -91,6 +121,8 @@ printf "\tchar _stub[];\n};\n"
        knot_rdata_rdlen
        knot_rdata_data
        knot_rdata_array_size
+       knot_rdata_ttl
+       knot_rdata_set_ttl
        knot_rdataset_at
        knot_rrset_add_rdata
        knot_rrset_init_empty
@@ -105,6 +137,16 @@ printf "\tchar _stub[];\n};\n"
        knot_pkt_put_question
        knot_pkt_rr
        knot_pkt_section
+# EDNS
+       knot_edns_get_version
+       knot_edns_set_version
+       knot_edns_add_option
+       knot_edns_has_option
+       knot_edns_get_option
+       knot_edns_opt_get_length
+       knot_edns_wire_size
+       knot_edns_set_ext_rcode
+       knot_edns_get_ext_rcode
 EOF
 
 ## libkres API
index 5e7340a82f23ffacfe5c39712889613e3d549dc0..cd7516c97e8be3c563d7b787fc1281ad8ba46dc0 100644 (file)
@@ -4,37 +4,10 @@
 local kres -- the module
 
 local ffi = require('ffi')
-local bit = require('bit')
-local bor = bit.bor
-local band = bit.band
 local C = ffi.C
 local knot = ffi.load(libknot_SONAME)
 
 -- Various declarations that are very stable.
-ffi.cdef[[
-/*
- * Data structures
- */
-
-/* stdlib */
-typedef long time_t;
-struct timeval {
-       time_t tv_sec;
-       time_t tv_usec;
-};
-struct sockaddr {
-    uint16_t sa_family;
-    uint8_t _stub[]; /* Do not touch */
-};
-
-/*
- * libc APIs
- */
-void * malloc(size_t size);
-void free(void *ptr);
-int inet_pton(int af, const char *src, void *dst);
-]]
-
 require('kres-gen')
 
 -- Constant tables
@@ -160,113 +133,11 @@ ffi.metatype( sockaddr_t, {
        }
 })
 
--- Metatype for RR set.  Beware, the indexing is 0-based (rdata, get, tostring).
-local rrset_buflen = (64 + 1) * 1024
-local rrset_buf = ffi.new('char[?]', rrset_buflen)
-local knot_rrset_t = ffi.typeof('knot_rrset_t')
-ffi.metatype( knot_rrset_t, {
-       -- beware: `owner` and `rdata` are typed as a plain lua strings
-       --         and not the real types they represent.
-       __tostring = function(rr) return rr:txt_dump() end,
-       __index = {
-               owner = function(rr) return ffi.string(rr._owner, knot.knot_dname_size(rr._owner)) end,
-               ttl = function(rr) return tonumber(knot.knot_rrset_ttl(rr)) end,
-               rdata = function(rr, i)
-                       local rdata = knot.knot_rdataset_at(rr.rrs, i)
-                       return ffi.string(knot.knot_rdata_data(rdata), knot.knot_rdata_rdlen(rdata))
-               end,
-               get = function(rr, i)
-                       return {owner = rr:owner(),
-                               ttl = rr:ttl(),
-                               class = tonumber(rr.rclass),
-                               type = tonumber(rr.type),
-                               rdata = rr:rdata(i)}
-               end,
-               tostring = function(rr, i)
-                       assert(ffi.istype(knot_rrset_t, rr))
-                       if rr.rrs.rr_count > 0 then
-                               local ret
-                               if i ~= nil then
-                                       ret = knot.knot_rrset_txt_dump_data(rr, i, rrset_buf, rrset_buflen, knot.KNOT_DUMP_STYLE_DEFAULT)
-                               else
-                                       ret = -1
-                               end
-                               return ret >= 0 and ffi.string(rrset_buf)
-                       end
-               end,
-
-               -- Dump the rrset in presentation format (dig-like).
-               txt_dump = function(rr, style)
-                       local bufsize = 1024
-                       local dump = ffi.new('char *[1]', C.malloc(bufsize))
-                               -- ^ one pointer to a string
-                       local size = ffi.new('size_t[1]', { bufsize }) -- one size_t = bufsize
-
-                       local ret = knot.knot_rrset_txt_dump(rr, dump, size,
-                                                       style or knot.KNOT_DUMP_STYLE_DEFAULT)
-                       local result = nil
-                       if ret >= 0 then
-                               result = ffi.string(dump[0], ret)
-                       end
-                       C.free(dump[0])
-                       return result
-               end,
-       },
-})
-
--- Metatype for packet
-local knot_pkt_t = ffi.typeof('knot_pkt_t')
-ffi.metatype( knot_pkt_t, {
-       __index = {
-               qname = function(pkt)
-                       local qname = knot.knot_pkt_qname(pkt)
-                       return ffi.string(qname, knot.knot_dname_size(qname))
-               end,
-               qclass = function(pkt) return knot.knot_pkt_qclass(pkt) end,
-               qtype  = function(pkt) return knot.knot_pkt_qtype(pkt) end,
-               rcode = function (pkt, val)
-                       pkt.wire[3] = (val) and bor(band(pkt.wire[3], 0xf0), val) or pkt.wire[3]
-                       return band(pkt.wire[3], 0x0f)
-               end,
-               tc = function (pkt, val)
-                       pkt.wire[2] = bor(pkt.wire[2], (val) and 0x02 or 0x00)
-                       return band(pkt.wire[2], 0x02)
-               end,
-               rrsets = function (pkt, section_id)
-                       local records = {}
-                       local section = knot.knot_pkt_section(pkt, section_id)
-                       for i = 1, section.count do
-                               local rrset = knot.knot_pkt_rr(section, i - 1)
-                               table.insert(records, rrset)
-                       end
-                       return records
-               end,
-               section = function (pkt, section_id)
-                       local records = {}
-                       local section = knot.knot_pkt_section(pkt, section_id)
-                       for i = 1, section.count do
-                               local rrset = knot.knot_pkt_rr(section, i - 1)
-                               for k = 1, rrset.rrs.rr_count do
-                                       table.insert(records, rrset:get(k - 1))
-                               end
-                       end
-                       return records
-               end,
-               begin = function (pkt, section) return knot.knot_pkt_begin(pkt, section) end,
-               put = function (pkt, owner, ttl, rclass, rtype, rdata)
-                       return C.kr_pkt_put(pkt, owner, ttl, rclass, rtype, rdata, #rdata)
-               end,
-               clear = function (pkt) return C.kr_pkt_recycle(pkt) end,
-               question = function(pkt, qname, qclass, qtype)
-                       return C.knot_pkt_put_question(pkt, qname, qclass, qtype)
-               end,
-       },
-})
 -- Metatype for query
 local kr_query_t = ffi.typeof('struct kr_query')
 ffi.metatype( kr_query_t, {
        __index = {
-               name = function(qry) return ffi.string(qry.sname, knot.knot_dname_size(qry.sname)) end,
+               name = function(qry) return qry.sname end,
        },
 })
 -- Metatype for request
@@ -326,7 +197,7 @@ ffi.metatype(ranked_rr_array_t, {
        }
 })
 
--- Pretty print for domain name
+--- Pretty print for domain name
 local function dname2str(dname)
        return ffi.string(ffi.gc(C.knot_dname_to_str(nil, dname, 0), C.free))
 end
index e3fd530ab9286fc8a6a9dc6b7eb57875032a4fa3..5852e6c78f1865c4900b367249f43075d2ed6160 100644 (file)
@@ -21,6 +21,10 @@ function log(fmt, ...)
         print(string.format(fmt, ...))
 end
 
+-- DNS library bindings
+libknot_CDEFS = 'kres-gen'
+dns = require('dns')
+
 -- Resolver bindings
 kres = require('kres')
 if rawget(kres, 'str2dname') ~= nil then
index 2f14f20176df1209f01a941dad8f8ea09fcac984..0095068331443aeebe1c0a4be39b5f7d49f31ca3 100644 (file)
@@ -50,7 +50,7 @@ mod.layer = {
                        end
                else -- Observe AAAA NODATA responses
                        local is_nodata = (pkt:rcode() == kres.rcode.NOERROR) and (#answer == 0)
-                       if pkt:qtype() == kres.type.AAAA and is_nodata and pkt:qname() == qry:name()
+                       if pkt:qtype() == kres.type.AAAA and is_nodata and pkt:qname():equals(qry:name())
                                        and (qry.flags.RESOLVED and qry.parent == nil) then
                                local extraFlags = kres.mk_qflags({})
                                extraFlags.DNSSEC_WANT = qry.flags.DNSSEC_WANT
index 2e975a67395f6219a4a83b8f053a83b5f908ad02..4ab86968779d3650973fac9c29480f9b5040562b 100644 (file)
@@ -251,7 +251,7 @@ function policy.suffix(action, zone_list)
        local AC = require('ahocorasick')
        local tree = AC.create(zone_list)
        return function(_, query)
-               local match = AC.match(tree, query:name(), false)
+               local match = AC.match(tree, query:name():towire(), false)
                if match ~= nil then
                        return action
                end
@@ -265,7 +265,7 @@ function policy.suffix_common(action, suffix_list, common_suffix)
        local suffix_count = #suffix_list
        return function(_, query)
                -- Preliminary check
-               local qname = query:name()
+               local qname = query:name():towire()
                if not string.find(qname, common_suffix, -common_len, true) then
                        return nil
                end
@@ -283,7 +283,7 @@ end
 -- Filter QNAME pattern
 function policy.pattern(action, pattern)
        return function(_, query)
-               if string.find(query:name(), pattern) then
+               if string.find(query:name():towire(), pattern) then
                        return action
                end
                return nil
@@ -320,7 +320,7 @@ local function rpz_zonefile(action, path)
        local rules = rpz_parse(action, path)
        collectgarbage()
        return function(_, query)
-               local label = query:name()
+               local label = query:name():towire()
                local rule = rules[label]
                while rule == nil and string.len(label) > 0 do
                        label = string.sub(label, string.byte(label) + 2)
index 6f05d7fdbf2db8c7f7d2483859e06742ea175902..7cfb76b5d19c6e65527eab211bd0f10114bb0aa2 100644 (file)
@@ -1,6 +1,5 @@
 -- Module interface
 local ffi = require('ffi')
-local knot = ffi.load(libknot_SONAME)
 
 local priming = {}
 priming.retry_time = 10 * sec -- retry time when priming fail
@@ -19,10 +18,10 @@ internal.event = nil -- stores event id
 local function publish_hints(nsset)
        local roothints = kres.context().root_hints
        -- reset zone cut and clear address list
-       ffi.C.kr_zonecut_set(roothints, kres.str2dname("."))
-       for dname, addresses in pairs(nsset) do
+       ffi.C.kr_zonecut_set(roothints, dns.dname.parse("."))
+       for name, addresses in pairs(nsset) do
                for _, rdata_addr in pairs(addresses) do
-                       ffi.C.kr_zonecut_add(roothints, dname, rdata_addr)
+                       ffi.C.kr_zonecut_add(roothints, dns.dname(name), rdata_addr)
                end
        end
 end
@@ -46,14 +45,11 @@ local function address_callback(pkt, req)
        if pkt:rcode() ~= kres.rcode.NOERROR then
                warn("[priming] cannot resolve address '%s', type: %d", kres.dname2str(pkt:qname()), pkt:qtype())
        else
-               local section = pkt:rrsets(kres.section.ANSWER)
-               for i = 1, #section do
-                       local rr = section[i]
-                       if rr.type == kres.type.A or rr.type == kres.type.AAAA then
-                               for k = 0, rr.rrs.rr_count-1 do
-                                       local rdata = knot.knot_rdataset_at(rr.rrs, k)
-                                       rdata = ffi.string(rdata, knot.knot_rdata_array_size(knot.knot_rdata_rdlen(rdata)))
-                                       table.insert(internal.nsset[rr:owner()], rdata)
+               for _, rr in ipairs(pkt) do
+                       if rr:type() == kres.type.A or rr:type() == kres.type.AAAA then
+                               local name = rr:owner():towire()
+                               for _, rdata in ipairs(rr) do
+                                       table.insert(internal.nsset[name], tostring(rdata))
                                end
                        end
                end
@@ -78,23 +74,21 @@ end
 -- These new queries should be resolved from cache.
 -- luacheck: no unused args
 local function priming_callback(pkt, req)
-       pkt = kres.pkt_t(pkt)
+       pkt = dns.topacket(pkt)
        -- req = kres.request_t(req)
        if pkt:rcode() ~= kres.rcode.NOERROR then
                warn("[priming] cannot resolve '.' NS, next priming query in %d seconds", priming.retry_time / sec)
                internal.event = event.after(priming.retry_time, internal.prime)
                return nil
        end
-       local section = pkt:rrsets(kres.section.ANSWER)
-       for i = 1, #section do
-               local rr = section[i]
-               if rr.type == kres.type.NS then
+       for i, rr in ipairs(pkt) do
+               if rr:type() == kres.type.NS then
                        internal.min_ttl = math.min(internal.min_ttl, rr:ttl())
                        internal.to_resolve = internal.to_resolve + 2 * rr.rrs.rr_count
-                       for k = 0, rr.rrs.rr_count-1 do
+                       for k = 0, rr:count() - 1 do
+                               local rdata_wire = rr:rdata(k)
                                local nsname_text = rr:tostring(k)
-                               local nsname_wire = rr:rdata(k)
-                               internal.nsset[nsname_wire] = {}
+                               internal.nsset[rdata_wire] = {}
                                resolve(nsname_text, kres.type.A, kres.class.IN, 0, address_callback)
                                resolve(nsname_text, kres.type.AAAA, kres.class.IN, 0, address_callback)
                        end
index f141173137272e0d8f4f4b0ec9a1a1e53b5d6f06..86f9600f9414a6ee4f4a7f7a57501db188c4ba33 100644 (file)
@@ -54,7 +54,7 @@ function M.layer.consume(state, req, _)
        req = kres.request_t(req)
        local qry = req:current()
        if qry.stype == kres.type.DNSKEY and not qry.flags.CACHED then
-               send_ta_query(qry:name())
+               send_ta_query(qry.name():towire())
        end
        return state  -- do not interfere with normal query processing
 end