]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
policy.FORWARD: support IPv6 link-local addresses
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 27 Jan 2017 15:57:16 +0000 (16:57 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 27 Jan 2017 17:01:30 +0000 (18:01 +0100)
These shouldn't make any problems:
- the verbose messages don't print any scope, and
- reputation cache doesn't consider scope.

daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
daemon/lua/kres.lua
daemon/main.c
lib/nsrep.c
lib/nsrep.h
lib/utils.c
lib/utils.h
modules/policy/policy.lua

index 37ce821448a5812abbc9ec100a276ba50c4df91c..e62681e1a871e5b69756bf31fc78f07ed955f59e 100644 (file)
@@ -174,7 +174,7 @@ 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);
 int kr_rplan_pop(struct kr_rplan *, struct kr_query *);
 struct kr_query *kr_rplan_resolved(struct kr_rplan *);
-int kr_nsrep_set(struct kr_query *, size_t, uint8_t *, size_t, int);
+int kr_nsrep_set(struct kr_query *, size_t, const struct sockaddr *);
 unsigned int kr_rand_uint(unsigned int);
 int kr_pkt_put(knot_pkt_t *, const knot_dname_t *, uint32_t, uint16_t, uint16_t, const uint8_t *, uint16_t);
 int kr_pkt_recycle(knot_pkt_t *);
@@ -185,6 +185,7 @@ int kr_straddr_family(const char *);
 int kr_straddr_subnet(void *, const char *);
 int kr_bitcmp(const char *, const char *, int);
 int kr_family_len(int);
+struct sockaddr *kr_straddr_socket(const char *, int);
 int kr_rrarray_add(rr_array_t *, const knot_rrset_t *, knot_mm_t *);
 knot_rrset_t *kr_ta_get(map_t *, const knot_dname_t *);
 int kr_ta_add(map_t *, const knot_dname_t *, uint16_t, uint32_t, const uint8_t *, uint16_t);
index 34e4424ca51a0f861eab42dab5ea8211f946cb86..6f1584a678a65184e69b2f430ee87cfaae054e61 100755 (executable)
@@ -109,6 +109,7 @@ EOF
        kr_straddr_subnet
        kr_bitcmp
        kr_family_len
+       kr_straddr_socket
        kr_rrarray_add
 # Trust anchors
        kr_ta_get
index a24a73a4662c0356ea4607bc1782d3c9e9db26e4..a14f6244fc60f110db614fe0d27f994186271c88 100644 (file)
@@ -227,11 +227,11 @@ ffi.metatype( kr_query_t, {
                nslist = function(qry, list)
                        assert(#list <= 4, 'maximum of 4 addresses can be evaluated for each query')
                        for i, ns in ipairs(list) do
-                               C.kr_nsrep_set(qry, i - 1, ffi.cast(ub_t, ns[1]), #ns[1], ns[2] or 53)
+                               assert(C.kr_nsrep_set(qry, i - 1, ns) == 0);
                        end
                        -- If less than maximum NSs, insert guard to terminate the list
                        if #list < 4 then
-                               C.kr_nsrep_set(qry, #list, nil, 0, 0)
+                               assert(C.kr_nsrep_set(qry, #list, nil) == 0);
                        end
                end,
        },
index 009fb6026c5b60b59acd4c3109102e763895f872..435a09275861ff8782edeb981aca0df23c3cd18b 100644 (file)
@@ -250,6 +250,7 @@ static void signal_handler(uv_signal_t *handle, int signum)
        uv_signal_stop(handle);
 }
 
+/** Split away port from the address. */
 static const char *set_addr(char *addr, int *port)
 {
        char *p = strchr(addr, '#');
index be584d9fdda832c4032bbb69fe278494392d2046..f3dd405afbcfce2397c2e9eb7856f166191e3180 100644 (file)
@@ -172,7 +172,7 @@ static int eval_nsrep(const char *k, void *v, void *baton)
        return kr_ok();
 }
 
-int kr_nsrep_set(struct kr_query *qry, size_t index, uint8_t *addr, size_t addr_len, int port)
+int kr_nsrep_set(struct kr_query *qry, size_t index, const struct sockaddr *sock)
 {
        if (!qry) {
                return kr_error(EINVAL);
@@ -186,17 +186,33 @@ int kr_nsrep_set(struct kr_query *qry, size_t index, uint8_t *addr, size_t addr_
                qry->ns.score = KR_NS_UNKNOWN;
                qry->ns.reputation = 0;
        }
+
+       if (!sock) {
+               qry->ns.addr[index].ip.sa_family = AF_UNSPEC;
+               return kr_ok();
+       }
+
+       switch (sock->sa_family) {
+       case AF_INET:
+               qry->ns.addr[index].ip4 = *(const struct sockaddr_in *)sock;
+               break;
+       case AF_INET6:
+               qry->ns.addr[index].ip6 = *(const struct sockaddr_in6 *)sock;
+               break;
+       default:
+               qry->ns.addr[index].ip.sa_family = AF_UNSPEC;
+               return kr_error(EINVAL);
+       }
+
        /* Retrieve RTT from cache */
-       if (addr && addr_len > 0) {
-               struct kr_context *ctx = qry->ns.ctx;
-               unsigned *score = ctx
-                       ? lru_get_try(ctx->cache_rtt, (const char *)addr, addr_len)
-                       : NULL;
-               if (score) {
-                       qry->ns.score = MIN(qry->ns.score, *score);
-               }
+       struct kr_context *ctx = qry->ns.ctx;
+       unsigned *score = ctx
+               ? lru_get_try(ctx->cache_rtt, kr_inaddr(sock), kr_family_len(sock->sa_family))
+               : NULL;
+       if (score) {
+               qry->ns.score = MIN(qry->ns.score, *score);
        }
-       update_nsrep(&qry->ns, index, addr, addr_len, port);
+
        return kr_ok();
 }
 
index e94f245ca569be3570590776d1349fcb7545cb0d..5e4eed8388532b83dcf7ff8c993a486b1bd5a969 100644 (file)
@@ -96,13 +96,11 @@ struct kr_nsrep
  * Set given NS address.
  * @param  qry      updated query
  * @param  index    index of the updated target
- * @param  addr     address bytes (struct in_addr or struct in6_addr)
- * @param  addr_len address bytes length (type will be derived from this)
- * @param  port     address port (if <= 0, 53 will be used)
+ * @param  sock     socket address to use (sockaddr_in or sockaddr_in6 or NULL)
  * @return          0 or an error code
  */
 KR_EXPORT
-int kr_nsrep_set(struct kr_query *qry, size_t index, uint8_t *addr, size_t addr_len, int port);
+int kr_nsrep_set(struct kr_query *qry, size_t index, const struct sockaddr *sock);
 
 /**
  * Elect best nameserver/address pair from the nsset.
index 794119ebb469014d52fc94813ca61faf17896f91..574e75a7eee26e9297b0ef15da3552832b0720cd 100644 (file)
@@ -27,6 +27,7 @@
 #include <libknot/rrtype/rrsig.h>
 #include <libknot/rrset-dump.h>
 #include <libknot/version.h>
+#include <uv.h>
 
 #include "lib/defines.h"
 #include "lib/utils.h"
@@ -291,6 +292,32 @@ int kr_family_len(int family)
        }
 }
 
+struct sockaddr * kr_straddr_socket(const char *addr, int port)
+{
+       switch (kr_straddr_family(addr)) {
+       case AF_INET: {
+               struct sockaddr_in *res = malloc(sizeof(*res));
+               if (uv_ip4_addr(addr, port, res) >= 0) {
+                       return (struct sockaddr *)res;
+               } else {
+                       free(res);
+                       return NULL;
+               }
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 *res = malloc(sizeof(*res));
+               if (uv_ip6_addr(addr, port, res) >= 0) {
+                       return (struct sockaddr *)res;
+               } else {
+                       free(res);
+                       return NULL;
+               }
+       }
+       default:
+               return NULL;
+       }
+}
+
 int kr_straddr_subnet(void *dst, const char *addr)
 {
        if (!dst || !addr) {
index 24044438dc7e4dacb4970300a7ca0a3ede45ba0e..041edc017c84c684d41ee22437545349b9b49f85 100644 (file)
@@ -152,6 +152,9 @@ int kr_straddr_family(const char *addr);
 /** Return address length in given family. */
 KR_EXPORT KR_CONST
 int kr_family_len(int family);
+/** Create a sockaddr* from string+port representation (also accepts IPv6 link-local). */
+KR_EXPORT
+struct sockaddr * kr_straddr_socket(const char *addr, int port);
 /** Parse address and return subnet length (bits).
   * @warning 'dst' must be at least `sizeof(struct in6_addr)` long. */
 KR_EXPORT
index e5d020a6de1c61763a902aa02cfcd8af31d526c5..6c31954e134f3aa489317cc0025223984c4dc7fc 100644 (file)
@@ -42,6 +42,17 @@ local function parse_target(target)
        return addr, port
 end
 
+local function parse_sock(target)
+       local addr, port = target:match '([^@]*)@?(.*)'
+       port = port and tonumber(port) or 53
+       sock = ffi.gc(ffi.C.kr_straddr_socket(addr, port), ffi.C.free);
+
+       if sock == nil then
+               error("target '"..target..'" is not a valid IP address')
+       end
+       return sock
+end
+
 -- Mirror request elsewhere, and continue solving
 local function mirror(target)
        local addr, port = parse_target(target)
@@ -63,11 +74,11 @@ local function forward(target)
        local list = {}
        if type(target) == 'table' then
                for _, v in pairs(target) do
-                       table.insert(list, {parse_target(v)})
+                       table.insert(list, parse_sock(v))
                        assert(#list <= 4, 'at most 4 FORWARD targets are supported')
                end
        else
-               table.insert(list, {parse_target(target)})
+               table.insert(list, parse_sock(target))
        end
        return function(state, req)
                req = kres.request_t(req)