]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/utils: sockaddr key generation
authorOto Šťáva <oto.stava@nic.cz>
Fri, 29 Apr 2022 06:50:35 +0000 (08:50 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 2 May 2022 10:17:49 +0000 (12:17 +0200)
daemon/bindings/net.c
lib/utils.c
lib/utils.h

index 7e1afd715ead54ba6ad12133313a2fefefacd68d..c6b0f5dc56e1d6753236d64918544451c917d7b1 100644 (file)
@@ -414,18 +414,6 @@ static int net_close(lua_State *L)
        return 1;
 }
 
-/** Check whether `addr` points to an `AF_INET6` address and whether the address
- * is link-local. */
-static bool ip6_link_local(struct sockaddr_in6 *addr)
-{
-       if (addr->sin6_family != AF_INET6)
-               return false;
-
-       /* Link-local: https://tools.ietf.org/html/rfc4291#section-2.4 */
-       const uint8_t prefix[] = { 0xFE, 0x80 };
-       return kr_bitcmp((char *) addr->sin6_addr.s6_addr, (char *) prefix, 10) == 0;
-}
-
 /** List available interfaces. */
 static int net_interfaces(lua_State *L)
 {
@@ -457,7 +445,7 @@ static int net_interfaces(lua_State *L)
                        buf[0] = '\0';
                }
 
-               if (ip6_link_local(&iface.address.address6)) {
+               if (kr_sockaddr_link_local((struct sockaddr *) &iface.address)) {
                        /* Link-local IPv6: add %interface prefix */
                        auto_free char *str = NULL;
                        int ret = asprintf(&str, "%s%%%s", buf, iface.name);
index 29d0ce4e6519dab4bd4eb7326d8115215b5f6ce9..1f8db78e9528ff6701931fb1d14a073b6367d19d 100644 (file)
 #include <sys/statvfs.h>
 #include <sys/un.h>
 
+struct __attribute__((packed)) kr_sockaddr_key {
+       int family;
+};
+
+struct __attribute__((packed)) kr_sockaddr_in_key {
+       int family;
+       char address[sizeof(((struct sockaddr_in *) NULL)->sin_addr)];
+       uint16_t port;
+};
+
+struct __attribute__((packed)) kr_sockaddr_in6_key {
+       int family;
+       char address[sizeof(((struct sockaddr_in6 *) NULL)->sin6_addr)];
+       uint32_t scope;
+       uint16_t port;
+};
+
+struct __attribute((packed)) kr_sockaddr_un_key {
+       int family;
+       char path[sizeof(((struct sockaddr_un *) NULL)->sun_path)];
+};
+
 /* Logging & debugging */
 bool kr_dbg_assertion_abort = DBG_ASSERTION_ABORT;
 int kr_dbg_assertion_fork = DBG_ASSERTION_FORK;
@@ -284,6 +306,82 @@ int kr_sockaddr_len(const struct sockaddr *addr)
        }
 }
 
+ssize_t kr_sockaddr_key(struct kr_sockaddr_key_storage *dst,
+                        const struct sockaddr *addr)
+{
+       kr_require(addr);
+
+       switch (addr->sa_family) {
+       case AF_INET:;
+               const struct sockaddr_in *addr_in = (const struct sockaddr_in *) addr;
+               struct kr_sockaddr_in_key *inkey = (struct kr_sockaddr_in_key *) dst;
+               inkey->family = AF_INET;
+               memcpy(&inkey->address, &addr_in->sin_addr, sizeof(inkey->address));
+               memcpy(&inkey->port, &addr_in->sin_port, sizeof(inkey->port));
+               return sizeof(*inkey);
+
+       case AF_INET6:;
+               const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *) addr;
+               struct kr_sockaddr_in6_key *in6key = (struct kr_sockaddr_in6_key *) dst;
+               in6key->family = AF_INET6;
+               memcpy(&in6key->address, &addr_in6->sin6_addr, sizeof(in6key->address));
+               memcpy(&in6key->port, &addr_in6->sin6_port, sizeof(in6key->port));
+               if (kr_sockaddr_link_local(addr))
+                       memcpy(&in6key->scope, &addr_in6->sin6_scope_id, sizeof(in6key->scope));
+               else
+                       in6key->scope = 0;
+               return sizeof(*in6key);
+
+       case AF_UNIX:;
+               const struct sockaddr_un *addr_un = (const struct sockaddr_un *) addr;
+               struct kr_sockaddr_un_key *unkey = (struct kr_sockaddr_un_key *) dst;
+               unkey->family = AF_UNIX;
+               strncpy(unkey->path, addr_un->sun_path, sizeof(unkey->path));
+               size_t pathlen = strnlen(unkey->path, sizeof(unkey->path));
+               if (pathlen < sizeof(unkey->path)) /* Include null-terminator */
+                       pathlen += 1;
+               return offsetof(struct kr_sockaddr_un_key, path) + pathlen;
+
+       default:
+               return kr_error(EAFNOSUPPORT);
+       }
+}
+
+struct sockaddr *kr_sockaddr_from_key(struct sockaddr_storage *dst,
+                                      const char *key)
+{
+       kr_require(key);
+
+       switch (((struct kr_sockaddr_key *) key)->family) {
+       case AF_INET:;
+               const struct kr_sockaddr_in_key *inkey = (struct kr_sockaddr_in_key *) key;
+               struct sockaddr_in *addr_in = (struct sockaddr_in *) dst;
+               addr_in->sin_family = AF_INET;
+               memcpy(&addr_in->sin_addr, &inkey->address, sizeof(inkey->address));
+               memcpy(&addr_in->sin_port, &inkey->port, sizeof(inkey->port));
+               return (struct sockaddr *) addr_in;
+
+       case AF_INET6:;
+               const struct kr_sockaddr_in6_key *in6key = (struct kr_sockaddr_in6_key *) key;
+               struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) dst;
+               addr_in6->sin6_family = AF_INET6;
+               memcpy(&addr_in6->sin6_addr, &in6key->address, sizeof(in6key->address));
+               memcpy(&addr_in6->sin6_port, &in6key->port, sizeof(in6key->port));
+               memcpy(&addr_in6->sin6_scope_id, &in6key->scope, sizeof(in6key->scope));
+               return (struct sockaddr *) addr_in6;
+
+       case AF_UNIX:;
+               const struct kr_sockaddr_un_key *unkey = (struct kr_sockaddr_un_key *) key;
+               struct sockaddr_un *addr_un = (struct sockaddr_un *) dst;
+               addr_un->sun_family = AF_UNIX;
+               strncpy(addr_un->sun_path, unkey->path, sizeof(unkey->path));
+               return (struct sockaddr *) addr_un;
+
+       default:
+               return NULL;
+       }
+}
+
 int kr_sockaddr_cmp(const struct sockaddr *left, const struct sockaddr *right)
 {
        if (!left || !right) {
index cdcda131a51ecdb84eac016ac91473d0bfca3031..d9aadfa13ef98d3b9add3dc08e5ad9b04d2f0ff3 100644 (file)
 #include "lib/generic/array.h"
 #include "lib/log.h"
 
-
 /** When knot_pkt is passed from cache without ->wire, this is the ->size. */
 static const size_t KR_PKT_SIZE_NOWIRE = -1;
 
+/** Used for reserving enough space for the `kr_sockaddr_key` function
+ * output. */
+struct kr_sockaddr_key_storage {
+       char bytes[sizeof(struct sockaddr_storage)];
+};
+
 
 /*
  * Logging and debugging.
@@ -262,6 +267,22 @@ int kr_inaddr_len(const struct sockaddr *addr);
 /** Sockaddr length for given family, i.e. sizeof(struct sockaddr_in*). */
 KR_EXPORT KR_PURE
 int kr_sockaddr_len(const struct sockaddr *addr);
+
+/** Creates a packed structure from the specified `addr`, safe for use as a key
+ * in containers like `trie_t`, and writes it into `dst`. On success, returns
+ * the actual length of the key.
+ *
+ * Returns `kr_error(EAFNOSUPPORT)` if the family of `addr` is unsupported. */
+KR_EXPORT
+ssize_t kr_sockaddr_key(struct kr_sockaddr_key_storage *dst,
+                        const struct sockaddr *addr);
+
+/** Creates a `struct sockaddr` from the specified `key` created using the
+ * `kr_sockaddr_key()` function. */
+KR_EXPORT
+struct sockaddr *kr_sockaddr_from_key(struct sockaddr_storage *dst,
+                                      const char *key);
+
 /** Compare two given sockaddr.
  * return 0 - addresses are equal, error code otherwise.
  */
@@ -353,6 +374,19 @@ int kr_bitcmp(const char *a, const char *b, int bits);
 KR_EXPORT
 void kr_bitmask(unsigned char *a, size_t a_len, int bits);
 
+/** Check whether `addr` points to an `AF_INET6` address and whether the address
+ * is link-local. */
+static inline bool kr_sockaddr_link_local(const struct sockaddr *addr)
+{
+       if (addr->sa_family != AF_INET6)
+               return false;
+
+       /* Link-local: https://tools.ietf.org/html/rfc4291#section-2.4 */
+       const uint8_t prefix[] = { 0xFE, 0x80 };
+       const struct sockaddr_in6 *ip6 = (const struct sockaddr_in6 *) addr;
+       return kr_bitcmp((char *) ip6->sin6_addr.s6_addr, (char *) prefix, 10) == 0;
+}
+
 /** @internal RR map flags. */
 static const uint8_t KEY_FLAG_RRSIG = 0x02;
 static inline uint8_t KEY_FLAG_RANK(const char *key)