Commit 5ed52f46 authored by Vladimír Čunát's avatar Vladimír Čunát

policy.FORWARD: support IPv6 link-local addresses

These shouldn't make any problems:
- the verbose messages don't print any scope, and
- reputation cache doesn't consider scope.
parent 3f668106
......@@ -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);
......
......@@ -109,6 +109,7 @@ EOF
kr_straddr_subnet
kr_bitcmp
kr_family_len
kr_straddr_socket
kr_rrarray_add
# Trust anchors
kr_ta_get
......
......@@ -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,
},
......
......@@ -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, '#');
......
......@@ -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();
}
......
......@@ -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.
......
......@@ -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) {
......
......@@ -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
......
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment