[PATCH 1/2] unit/test-cipher: always report local ciphers as supported
by Sergei Trofimovich
Fixes test failure on system with CONFIG_CRYPTO_USER_API=n kernel:
FAIL: unit/test-cipher
======================
test-cipher: unit/test-cipher.c:124:
test_arc4: Assertion `l_cipher_is_supported(L_CIPHER_ARC4)' failed.
FAIL unit/test-cipher (exit status: 134)
Lack of AF_ALG family is the result of CONFIG_CRYPTO_USER_API=n.
The change moved supported ciphed detection before AF_ALG socket
creation attempt.
Signed-off-by: Sergei Trofimovich <slyich(a)gmail.com>
---
ell/cipher.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ell/cipher.c b/ell/cipher.c
index 0d10394..866fdb5 100644
--- a/ell/cipher.c
+++ b/ell/cipher.c
@@ -677,6 +677,10 @@ static void init_supported()
initialized = true;
+ for (c = 0; c < L_ARRAY_SIZE(local_impl_ciphers); c++)
+ if (HAVE_LOCAL_IMPLEMENTATION(c))
+ supported_ciphers |= 1 << c;
+
sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
if (sk < 0)
return;
@@ -698,10 +702,6 @@ static void init_supported()
supported_ciphers |= 1 << c;
}
- for (c = 0; c < L_ARRAY_SIZE(local_impl_ciphers); c++)
- if (HAVE_LOCAL_IMPLEMENTATION(c))
- supported_ciphers |= 1 << c;
-
strcpy((char *) salg.salg_type, "aead");
for (a = L_AEAD_CIPHER_AES_CCM; a <= L_AEAD_CIPHER_AES_GCM; a++) {
--
2.33.0
10 months
[PATCH] dhcp-server: Fill in DNS info in lease objects
by Andrew Zaborowski
Copy the DNS info that we send to the client also to the lease object
that we keep on our side for our own tracking, same as we copy the IP,
the gateway, the netmask etc.
---
ell/dhcp-server.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 05f9b73..9c0628a 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -316,6 +316,13 @@ static struct l_dhcp_lease *add_lease(struct l_dhcp_server *server,
lease->subnet_mask = server->netmask;
lease->router = server->gateway;
+ if (server->dns_list) {
+ unsigned int i;
+
+ for (i = 0; server->dns_list[i]; i++);
+ lease->dns = l_memdup(server->dns_list, (i + 1) * 4);
+ }
+
if (client_id)
lease->client_id = l_memdup(client_id, client_id[0] + 1);
--
2.30.2
10 months
[PATCH] rtnl: Add neighbor discovery utilities
by Andrew Zaborowski
Add a few variants of RTNL utilities to look up addresses in the
kernel's neighbour table entries and to add new entries. This is
basically the ARP (for IPv4) and NDP (for IPv6) tables, that map IP
addresses to hardware addresses.
---
ell/ell.sym | 2 +
ell/rtnl.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++
ell/rtnl.h | 17 +++++++
ell/useful.h | 4 ++
4 files changed, 150 insertions(+)
diff --git a/ell/ell.sym b/ell/ell.sym
index b29d98d..9fcf334 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -663,6 +663,8 @@ global:
l_rtnl_ifaddr_extract;
l_rtnl_ifaddr_add;
l_rtnl_ifaddr_delete;
+ l_rtnl_neighbor_get_hwaddr;
+ l_rtnl_neighbor_set_hwaddr;
/* icmp6 */
l_icmp6_client_new;
l_icmp6_client_free;
diff --git a/ell/rtnl.c b/ell/rtnl.c
index 1061105..4a1a248 100644
--- a/ell/rtnl.c
+++ b/ell/rtnl.c
@@ -27,6 +27,9 @@
#define _GNU_SOURCE
#include <linux/if.h>
#include <linux/icmpv6.h>
+#include <linux/neighbour.h>
+#include <linux/if_ether.h>
+#include <net/if_arp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
@@ -34,6 +37,7 @@
#include "useful.h"
#include "netlink.h"
#include "log.h"
+#include "util.h"
#include "rtnl.h"
#include "private.h"
@@ -1311,3 +1315,126 @@ LIB_EXPORT uint32_t l_rtnl_route_delete(struct l_netlink *rtnl, int ifindex,
return _rtnl_route_change(rtnl, RTM_DELROUTE, ifindex, rt,
cb, user_data, destroy);
}
+
+struct rtnl_neighbor_get_data {
+ l_rtnl_neighbor_get_cb_t cb;
+ void *user_data;
+ l_netlink_destroy_func_t destroy;
+};
+
+static void rtnl_neighbor_get_cb(int error, uint16_t type, const void *data,
+ uint32_t len, void *user_data)
+{
+ struct rtnl_neighbor_get_data *cb_data = user_data;
+ const struct ndmsg *ndmsg = data;
+ struct rtattr *attr;
+ const uint8_t *hwaddr = NULL;
+ size_t hwaddr_len = 0;
+
+ if (error != 0)
+ goto done;
+
+ if (type != RTM_NEWNEIGH || len < NLMSG_ALIGN(sizeof(*ndmsg))) {
+ error = -EIO;
+ goto done;
+ }
+
+ if (!(ndmsg->ndm_state & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE))) {
+ error = -ENOENT;
+ goto done;
+ }
+
+ attr = (void *) ndmsg + NLMSG_ALIGN(sizeof(*ndmsg));
+ len -= NLMSG_ALIGN(sizeof(*ndmsg));
+
+ for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))
+ switch (attr->rta_type) {
+ case NDA_LLADDR:
+ hwaddr = RTA_DATA(attr);
+ hwaddr_len = RTA_PAYLOAD(attr);
+ break;
+ }
+
+ if (!hwaddr)
+ error = -EIO;
+
+done:
+ if (cb_data->cb) {
+ cb_data->cb(error, hwaddr, hwaddr_len, cb_data->user_data);
+ cb_data->cb = NULL;
+ }
+}
+
+static void rtnl_neighbor_get_destroy_cb(void *user_data)
+{
+ struct rtnl_neighbor_get_data *cb_data = user_data;
+
+ if (cb_data->destroy)
+ cb_data->destroy(cb_data->user_data);
+
+ l_free(cb_data);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbor_get_hwaddr(struct l_netlink *rtnl,
+ int ifindex, int family,
+ const void *ip,
+ l_rtnl_neighbor_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ size_t bufsize = NLMSG_ALIGN(sizeof(struct ndmsg)) +
+ RTA_SPACE(16); /* NDA_DST */
+ uint8_t buf[bufsize];
+ struct ndmsg *ndmsg = (struct ndmsg *) buf;
+ void *rta_buf = (void *) ndmsg + NLMSG_ALIGN(sizeof(struct ndmsg));
+ __auto_type cb_data = struct_alloc(rtnl_neighbor_get_data,
+ cb, user_data, destroy);
+ uint32_t ret;
+
+ memset(buf, 0, bufsize);
+ ndmsg->ndm_family = family;
+ ndmsg->ndm_ifindex = ifindex;
+ ndmsg->ndm_flags = 0;
+
+ rta_buf += rta_add_address(rta_buf, NDA_DST, family, ip, ip);
+
+ ret = l_netlink_send(rtnl, RTM_GETNEIGH, 0, ndmsg,
+ rta_buf - (void *) ndmsg,
+ rtnl_neighbor_get_cb, cb_data,
+ rtnl_neighbor_get_destroy_cb);
+ if (ret)
+ return ret;
+
+ l_free(cb_data);
+ return 0;
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbor_set_hwaddr(struct l_netlink *rtnl,
+ int ifindex, int family,
+ const void *ip,
+ const uint8_t *hwaddr,
+ size_t hwaddr_len,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ size_t bufsize = NLMSG_ALIGN(sizeof(struct ndmsg)) +
+ RTA_SPACE(16) + /* NDA_DST */
+ RTA_SPACE(hwaddr_len); /* NDA_LLADDR */
+ uint8_t buf[bufsize];
+ struct ndmsg *ndmsg = (struct ndmsg *) buf;
+ void *rta_buf = (void *) ndmsg + NLMSG_ALIGN(sizeof(struct ndmsg));
+
+ memset(buf, 0, bufsize);
+ ndmsg->ndm_family = family;
+ ndmsg->ndm_ifindex = ifindex;
+ ndmsg->ndm_flags = 0;
+ ndmsg->ndm_state = NUD_REACHABLE;
+
+ rta_buf += rta_add_address(rta_buf, NDA_DST, family, ip, ip);
+ rta_buf += rta_add_data(rta_buf, NDA_LLADDR, hwaddr, hwaddr_len);
+
+ return l_netlink_send(rtnl, RTM_NEWNEIGH, NLM_F_CREATE | NLM_F_REPLACE,
+ ndmsg, rta_buf - (void *) ndmsg,
+ cb, user_data, destroy);
+}
diff --git a/ell/rtnl.h b/ell/rtnl.h
index 9ea24f5..85b1370 100644
--- a/ell/rtnl.h
+++ b/ell/rtnl.h
@@ -33,6 +33,10 @@ extern "C" {
struct l_rtnl_address;
struct l_rtnl_route;
+typedef void (*l_rtnl_neighbor_get_cb_t) (int error, const uint8_t *hwaddr,
+ size_t hwaddr_len,
+ void *user_data);
+
struct l_rtnl_address *l_rtnl_address_new(const char *ip, uint8_t prefix_len);
struct l_rtnl_address *l_rtnl_address_clone(const struct l_rtnl_address *orig);
void l_rtnl_address_free(struct l_rtnl_address *addr);
@@ -191,6 +195,19 @@ uint32_t l_rtnl_route_delete(struct l_netlink *rtnl, int ifindex,
void *user_data,
l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbor_get_hwaddr(struct l_netlink *rtnl, int ifindex,
+ int family, const void *ip,
+ l_rtnl_neighbor_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbor_set_hwaddr(struct l_netlink *rtnl, int ifindex,
+ int family, const void *ip,
+ const uint8_t *hwaddr,
+ size_t hwaddr_len,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+
#ifdef __cplusplus
}
#endif
diff --git a/ell/useful.h b/ell/useful.h
index d696bc3..b4783ce 100644
--- a/ell/useful.h
+++ b/ell/useful.h
@@ -83,3 +83,7 @@ static inline int secure_select(int select_left, int l, int r)
return r ^ ((l ^ r) & mask);
}
+
+#define struct_alloc(structname, ...) \
+ (struct structname *) l_memdup(&(struct structname) { __VA_ARGS__ }, \
+ sizeof(struct structname))
--
2.30.2
10 months, 1 week
[PATCH] rtnl: Add neighbor discovery utilities
by Andrew Zaborowski
Add a few variants of RTNL utilities to look up addresses in the
kernel's neighbour table entries and to add new entries. This is
basically the ARP (for IPv4) and NDP (for IPv6) tables, that map IP
addresses to hardware addresses.
---
There are three variants of each method, I currently only have a use
case for the ipv4 and ipv6 variants so I'm happy dropping the struct
l_rtnl_address variant.
ell/ell.sym | 6 ++
ell/rtnl.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++
ell/rtnl.h | 36 ++++++++++
ell/useful.h | 4 ++
4 files changed, 240 insertions(+)
diff --git a/ell/ell.sym b/ell/ell.sym
index b29d98d..8760f2b 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -663,6 +663,12 @@ global:
l_rtnl_ifaddr_extract;
l_rtnl_ifaddr_add;
l_rtnl_ifaddr_delete;
+ l_rtnl_neighbour_get_ipv4_hwaddr;
+ l_rtnl_neighbour_get_ipv6_hwaddr;
+ l_rtnl_neighbour_get_addr_hwaddr;
+ l_rtnl_neighbour_set_ipv4_hwaddr;
+ l_rtnl_neighbour_set_ipv6_hwaddr;
+ l_rtnl_neighbour_set_addr_hwaddr;
/* icmp6 */
l_icmp6_client_new;
l_icmp6_client_free;
diff --git a/ell/rtnl.c b/ell/rtnl.c
index 1061105..4d81c48 100644
--- a/ell/rtnl.c
+++ b/ell/rtnl.c
@@ -27,6 +27,9 @@
#define _GNU_SOURCE
#include <linux/if.h>
#include <linux/icmpv6.h>
+#include <linux/neighbour.h>
+#include <linux/if_ether.h>
+#include <net/if_arp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
@@ -34,6 +37,7 @@
#include "useful.h"
#include "netlink.h"
#include "log.h"
+#include "util.h"
#include "rtnl.h"
#include "private.h"
@@ -1311,3 +1315,193 @@ LIB_EXPORT uint32_t l_rtnl_route_delete(struct l_netlink *rtnl, int ifindex,
return _rtnl_route_change(rtnl, RTM_DELROUTE, ifindex, rt,
cb, user_data, destroy);
}
+
+struct rtnl_neighbour_get_data {
+ l_rtnl_neighbour_get_cb_t cb;
+ void *user_data;
+ l_netlink_destroy_func_t destroy;
+};
+
+static void rtnl_neighbour_get_cb(int error, uint16_t type, const void *data,
+ uint32_t len, void *user_data)
+{
+ struct rtnl_neighbour_get_data *cb_data = user_data;
+ const struct ndmsg *ndmsg = data;
+ struct rtattr *attr;
+ const uint8_t *hwaddr = NULL;
+
+ if (error != 0)
+ goto done;
+
+ if (type != RTM_NEWNEIGH || len < NLMSG_ALIGN(sizeof(*ndmsg))) {
+ error = -EIO;
+ goto done;
+ }
+
+ if (!(ndmsg->ndm_state & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE))) {
+ error = -ENOENT;
+ goto done;
+ }
+
+ attr = (void *) ndmsg + NLMSG_ALIGN(sizeof(*ndmsg));
+ len -= NLMSG_ALIGN(sizeof(*ndmsg));
+
+ for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))
+ switch (attr->rta_type) {
+ case NDA_LLADDR:
+ hwaddr = RTA_DATA(attr);
+ break;
+ }
+
+ if (!hwaddr)
+ error = -EIO;
+
+done:
+ if (cb_data->cb) {
+ cb_data->cb(error, hwaddr, cb_data->user_data);
+ cb_data->cb = NULL;
+ }
+}
+
+static void rtnl_neighbour_get_destroy_cb(void *user_data)
+{
+ struct rtnl_neighbour_get_data *cb_data = user_data;
+
+ if (cb_data->destroy)
+ cb_data->destroy(cb_data->user_data);
+
+ l_free(cb_data);
+}
+
+static uint32_t rtnl_neighbour_get_hwaddr(struct l_netlink *rtnl,
+ int ifindex, uint8_t family,
+ const void *addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ size_t bufsize = NLMSG_ALIGN(sizeof(struct ndmsg)) +
+ RTA_SPACE(16); /* NDA_DST */
+ uint8_t buf[bufsize];
+ struct ndmsg *ndmsg = (struct ndmsg *) buf;
+ void *rta_buf = (void *) ndmsg + NLMSG_ALIGN(sizeof(struct ndmsg));
+ __auto_type cb_data = struct_alloc(rtnl_neighbour_get_data,
+ cb, user_data, destroy);
+ uint32_t ret;
+
+ memset(buf, 0, bufsize);
+ ndmsg->ndm_family = family;
+ ndmsg->ndm_ifindex = ifindex;
+ ndmsg->ndm_flags = 0;
+
+ rta_buf += rta_add_address(rta_buf, NDA_DST, family, addr, addr);
+
+ ret = l_netlink_send(rtnl, RTM_GETNEIGH, 0, ndmsg,
+ rta_buf - (void *) ndmsg,
+ rtnl_neighbour_get_cb, cb_data,
+ rtnl_neighbour_get_destroy_cb);
+ if (ret)
+ return ret;
+
+ l_free(cb_data);
+ return 0;
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_get_ipv4_hwaddr(struct l_netlink *rtnl,
+ int ifindex, uint32_t addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ return rtnl_neighbour_get_hwaddr(rtnl, ifindex, AF_INET, &addr,
+ cb, user_data, destroy);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_get_ipv6_hwaddr(struct l_netlink *rtnl,
+ int ifindex, const uint8_t *addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ return rtnl_neighbour_get_hwaddr(rtnl, ifindex, AF_INET6, addr,
+ cb, user_data, destroy);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_get_addr_hwaddr(struct l_netlink *rtnl,
+ int ifindex,
+ const struct l_rtnl_address *addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ const uint8_t *ip = addr->family == AF_INET ?
+ (const void *) &addr->in_addr : (const void *) &addr->in6_addr;
+
+ return rtnl_neighbour_get_hwaddr(rtnl, ifindex, addr->family, ip,
+ cb, user_data, destroy);
+}
+
+static uint32_t rtnl_neighbour_set_hwaddr(struct l_netlink *rtnl,
+ int ifindex, uint8_t family,
+ const void *addr, const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ size_t bufsize = NLMSG_ALIGN(sizeof(struct ndmsg)) +
+ RTA_SPACE(16) + /* NDA_DST */
+ RTA_SPACE(ETH_ALEN); /* NDA_LLADDR */
+ uint8_t buf[bufsize];
+ struct ndmsg *ndmsg = (struct ndmsg *) buf;
+ void *rta_buf = (void *) ndmsg + NLMSG_ALIGN(sizeof(struct ndmsg));
+
+ memset(buf, 0, bufsize);
+ ndmsg->ndm_family = family;
+ ndmsg->ndm_ifindex = ifindex;
+ ndmsg->ndm_flags = 0;
+ ndmsg->ndm_state = NUD_REACHABLE;
+
+ rta_buf += rta_add_address(rta_buf, NDA_DST, family, addr, addr);
+ rta_buf += rta_add_data(rta_buf, NDA_LLADDR, hwaddr, ETH_ALEN);
+
+ return l_netlink_send(rtnl, RTM_NEWNEIGH, NLM_F_CREATE | NLM_F_REPLACE,
+ ndmsg, rta_buf - (void *) ndmsg,
+ cb, user_data, destroy);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_set_ipv4_hwaddr(struct l_netlink *rtnl,
+ int ifindex, uint32_t addr,
+ const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ return rtnl_neighbour_set_hwaddr(rtnl, ifindex, AF_INET, &addr,
+ hwaddr, cb, user_data, destroy);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_set_ipv6_hwaddr(struct l_netlink *rtnl,
+ int ifindex, const uint8_t *addr,
+ const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ return rtnl_neighbour_set_hwaddr(rtnl, ifindex, AF_INET6, addr,
+ hwaddr, cb, user_data, destroy);
+}
+
+LIB_EXPORT uint32_t l_rtnl_neighbour_set_addr_hwaddr(struct l_netlink *rtnl,
+ int ifindex,
+ const struct l_rtnl_address *addr,
+ const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy)
+{
+ const uint8_t *ip = addr->family == AF_INET ?
+ (const void *) &addr->in_addr : (const void *) &addr->in6_addr;
+
+ return rtnl_neighbour_set_hwaddr(rtnl, ifindex, addr->family, ip,
+ hwaddr, cb, user_data, destroy);
+}
diff --git a/ell/rtnl.h b/ell/rtnl.h
index 9ea24f5..834cd14 100644
--- a/ell/rtnl.h
+++ b/ell/rtnl.h
@@ -33,6 +33,9 @@ extern "C" {
struct l_rtnl_address;
struct l_rtnl_route;
+typedef void (*l_rtnl_neighbour_get_cb_t) (int error, const uint8_t *hwaddr,
+ void *user_data);
+
struct l_rtnl_address *l_rtnl_address_new(const char *ip, uint8_t prefix_len);
struct l_rtnl_address *l_rtnl_address_clone(const struct l_rtnl_address *orig);
void l_rtnl_address_free(struct l_rtnl_address *addr);
@@ -191,6 +194,39 @@ uint32_t l_rtnl_route_delete(struct l_netlink *rtnl, int ifindex,
void *user_data,
l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_get_ipv4_hwaddr(struct l_netlink *rtnl, int ifindex,
+ uint32_t addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_get_ipv6_hwaddr(struct l_netlink *rtnl, int ifindex,
+ const uint8_t *addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_get_addr_hwaddr(struct l_netlink *rtnl, int ifindex,
+ const struct l_rtnl_address *addr,
+ l_rtnl_neighbour_get_cb_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_set_ipv4_hwaddr(struct l_netlink *rtnl, int ifindex,
+ uint32_t addr, const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_set_ipv6_hwaddr(struct l_netlink *rtnl, int ifindex,
+ const uint8_t *addr,
+ const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+uint32_t l_rtnl_neighbour_set_addr_hwaddr(struct l_netlink *rtnl, int ifindex,
+ const struct l_rtnl_address *addr,
+ const uint8_t *hwaddr,
+ l_netlink_command_func_t cb,
+ void *user_data,
+ l_netlink_destroy_func_t destroy);
+
#ifdef __cplusplus
}
#endif
diff --git a/ell/useful.h b/ell/useful.h
index d696bc3..b4783ce 100644
--- a/ell/useful.h
+++ b/ell/useful.h
@@ -83,3 +83,7 @@ static inline int secure_select(int select_left, int l, int r)
return r ^ ((l ^ r) & mask);
}
+
+#define struct_alloc(structname, ...) \
+ (struct structname *) l_memdup(&(struct structname) { __VA_ARGS__ }, \
+ sizeof(struct structname))
--
2.30.2
10 months, 1 week
[PATCH 1/4] dhcp: Add public l_dhcp_lease_{new,free}
by Andrew Zaborowski
Make the constructor & destructor for struct l_dhcp_lease public, this
is to be used with the new l_dhcp_client_set_lease() method.
---
ell/dhcp-lease.c | 8 ++++----
ell/dhcp-private.h | 2 --
ell/dhcp-server.c | 18 +++++++++---------
ell/dhcp.c | 4 ++--
ell/dhcp.h | 2 ++
ell/ell.sym | 2 ++
6 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/ell/dhcp-lease.c b/ell/dhcp-lease.c
index c596c6b..a28a3f3 100644
--- a/ell/dhcp-lease.c
+++ b/ell/dhcp-lease.c
@@ -35,14 +35,14 @@
#include "utf8.h"
#include "net.h"
-struct l_dhcp_lease *_dhcp_lease_new(void)
+LIB_EXPORT struct l_dhcp_lease *l_dhcp_lease_new(void)
{
struct l_dhcp_lease *ret = l_new(struct l_dhcp_lease, 1);
return ret;
}
-void _dhcp_lease_free(struct l_dhcp_lease *lease)
+LIB_EXPORT void l_dhcp_lease_free(struct l_dhcp_lease *lease)
{
if (!lease)
return;
@@ -56,7 +56,7 @@ void _dhcp_lease_free(struct l_dhcp_lease *lease)
struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter)
{
- struct l_dhcp_lease *lease = _dhcp_lease_new();
+ struct l_dhcp_lease *lease = l_dhcp_lease_new();
uint8_t t, l;
const void *v;
@@ -183,7 +183,7 @@ struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter)
return lease;
error:
- _dhcp_lease_free(lease);
+ l_dhcp_lease_free(lease);
return NULL;
}
diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index bc10765..5864dc3 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -175,8 +175,6 @@ struct l_dhcp_lease {
bool offering : 1;
};
-struct l_dhcp_lease *_dhcp_lease_new(void);
-void _dhcp_lease_free(struct l_dhcp_lease *lease);
struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter);
struct dhcp_message_builder {
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 05f9b73..5d9f3f6 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -257,12 +257,12 @@ static void set_next_expire_timer(struct l_dhcp_server *server,
if (!expired->offering) {
if (l_queue_length(server->expired_list) >
server->max_expired)
- _dhcp_lease_free(l_queue_pop_head(
+ l_dhcp_lease_free(l_queue_pop_head(
server->expired_list));
l_queue_push_tail(server->expired_list, expired);
} else
- _dhcp_lease_free(expired);
+ l_dhcp_lease_free(expired);
}
next = l_queue_peek_tail(server->lease_list);
@@ -356,7 +356,7 @@ static bool remove_lease(struct l_dhcp_server *server,
if (!l_queue_remove(server->lease_list, lease))
return false;
- _dhcp_lease_free(lease);
+ l_dhcp_lease_free(lease);
set_next_expire_timer(server, NULL);
return true;
}
@@ -449,7 +449,7 @@ static uint32_t find_free_or_expired_ip(struct l_dhcp_server *server,
return 0;
ip_addr = lease->address;
- _dhcp_lease_free(lease);
+ l_dhcp_lease_free(lease);
return ip_addr;
}
@@ -997,9 +997,9 @@ LIB_EXPORT void l_dhcp_server_destroy(struct l_dhcp_server *server)
l_free(server->ifname);
l_queue_destroy(server->lease_list,
- (l_queue_destroy_func_t) _dhcp_lease_free);
+ (l_queue_destroy_func_t) l_dhcp_lease_free);
l_queue_destroy(server->expired_list,
- (l_queue_destroy_func_t) _dhcp_lease_free);
+ (l_queue_destroy_func_t) l_dhcp_lease_free);
if (server->dns_list)
l_free(server->dns_list);
@@ -1414,7 +1414,7 @@ LIB_EXPORT bool l_dhcp_server_lease_remove(struct l_dhcp_server *server,
!l_queue_remove(server->expired_list, lease)))
return false;
- _dhcp_lease_free(lease);
+ l_dhcp_lease_free(lease);
set_next_expire_timer(server, NULL);
return true;
}
@@ -1440,11 +1440,11 @@ static bool dhcp_expire_by_mac(void *data, void *user_data)
if (!lease->offering) {
if (l_queue_length(server->expired_list) > server->max_expired)
- _dhcp_lease_free(l_queue_pop_head(server->expired_list));
+ l_dhcp_lease_free(l_queue_pop_head(server->expired_list));
l_queue_push_tail(server->expired_list, lease);
} else
- _dhcp_lease_free(lease);
+ l_dhcp_lease_free(lease);
expire_data->expired_cnt++;
return true;
diff --git a/ell/dhcp.c b/ell/dhcp.c
index 32e4a7c..e06ab05 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -705,7 +705,7 @@ static int dhcp_client_receive_ack(struct l_dhcp_client *client,
client->lease->router != lease->router)
r = L_DHCP_CLIENT_EVENT_IP_CHANGED;
- _dhcp_lease_free(client->lease);
+ l_dhcp_lease_free(client->lease);
}
client->lease = lease;
@@ -1218,7 +1218,7 @@ LIB_EXPORT bool l_dhcp_client_stop(struct l_dhcp_client *client)
client->start_t = 0;
CLIENT_ENTER_STATE(DHCP_STATE_INIT);
- _dhcp_lease_free(client->lease);
+ l_dhcp_lease_free(client->lease);
client->lease = NULL;
if (client->acd) {
diff --git a/ell/dhcp.h b/ell/dhcp.h
index 5873c90..4f18f01 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -104,6 +104,8 @@ bool l_dhcp_client_set_debug(struct l_dhcp_client *client,
l_dhcp_debug_cb_t function,
void *user_data, l_dhcp_destroy_cb_t destroy);
+struct l_dhcp_lease *l_dhcp_lease_new(void);
+void l_dhcp_lease_free(struct l_dhcp_lease *lease);
char *l_dhcp_lease_get_address(const struct l_dhcp_lease *lease);
char *l_dhcp_lease_get_gateway(const struct l_dhcp_lease *lease);
diff --git a/ell/ell.sym b/ell/ell.sym
index b29d98d..66ebf46 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -223,6 +223,8 @@ global:
l_dbus_remove_signal_watch;
l_dbus_name_acquire;
/* dhcp */
+ l_dhcp_lease_new;
+ l_dhcp_lease_free;
l_dhcp_lease_get_address;
l_dhcp_lease_get_gateway;
l_dhcp_lease_get_mac;
--
2.30.2
10 months, 3 weeks
[PATCH 1/3] dhcp-server: Fix double free in l_dhcp_server_expire_by_mac
by Andrew Zaborowski
When using l_queue_foreach_remove() on lease_list we can't call
lease_release() because that will try to do l_queue_remove() on the same
queue, in addition to all the things we need it to do.
---
ell/dhcp-server.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index f92807a..84dc41d 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -1418,25 +1418,42 @@ LIB_EXPORT bool l_dhcp_server_lease_remove(struct l_dhcp_server *server,
struct dhcp_expire_by_mac_data {
struct l_dhcp_server *server;
const uint8_t *mac;
+ unsigned int expired_cnt;
};
static bool dhcp_expire_by_mac(void *data, void *user_data)
{
struct l_dhcp_lease *lease = data;
struct dhcp_expire_by_mac_data *expire_data = user_data;
+ struct l_dhcp_server *server = expire_data->server;
if (!match_lease_mac(lease, expire_data->mac))
return false;
- lease_release(expire_data->server, lease);
+ if (server->event_handler)
+ server->event_handler(server, L_DHCP_SERVER_EVENT_LEASE_EXPIRED,
+ server->user_data, lease);
+
+ if (!lease->offering) {
+ if (l_queue_length(server->expired_list) > server->max_expired)
+ _dhcp_lease_free(l_queue_pop_head(server->expired_list));
+
+ l_queue_push_tail(server->expired_list, lease);
+ } else
+ _dhcp_lease_free(lease);
+
+ expire_data->expired_cnt++;
return true;
}
LIB_EXPORT void l_dhcp_server_expire_by_mac(struct l_dhcp_server *server,
const uint8_t *mac)
{
- struct dhcp_expire_by_mac_data expire_data = { server, mac };
+ struct dhcp_expire_by_mac_data expire_data = { server, mac, 0 };
l_queue_foreach_remove(server->lease_list, dhcp_expire_by_mac,
&expire_data);
+
+ if (expire_data.expired_cnt)
+ set_next_expire_timer(server, NULL);
}
--
2.30.2
10 months, 3 weeks
[PATCH 01/15] dhcp-server: Add "authoritative" mode
by Andrew Zaborowski
An authoritative DHCP server basically assumes that there are no other
DHCP servers on the network and replies to DHCPREQUEST messages
requesting IPs from outside of its subnet or with a wrong server ID
value. This speeds up connections from clients who try to use IP
leases they have cached from other networks and who start their IP
configuration by trying DHCPREQUESTs for those leases.
The term is not defined in the DHCP standard but is used by various
implementations. Default to authoritative being true. When set to
false, handle a DHCPREQUEST message directed at other servers by taking
it as meaning the client is declining our own lease offer as mandated
by RFC 2131 on page 16.
Refactor the checks in DHCPREQUEST handling quoting parts of the RFC.
The new checks are stricter and I'm not preserving some of the checks
that didn't seem justified, for example in the
"if (server_id_opt || !lease) ... send_nak()" block it didn't seem to
make sense to only reply to clients who have no lease (offered or
active) and ignore those who do have a lease with a different IP
address, the opposite would make more sense.
---
ell/dhcp-server.c | 117 +++++++++++++++++++++++++++++++++++++++-------
ell/dhcp.h | 2 +
ell/ell.sym | 1 +
3 files changed, 103 insertions(+), 17 deletions(-)
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index bae0f10..4c12327 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -87,6 +87,8 @@ struct l_dhcp_server {
struct dhcp_transport *transport;
struct l_acd *acd;
+
+ bool authoritative : 1;
};
#define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
@@ -596,7 +598,8 @@ static void listener_event(const void *data, size_t len, void *user_data)
const void *v;
struct l_dhcp_lease *lease;
uint8_t type = 0;
- uint32_t server_id_opt = 0;
+ bool server_id_opt = false;
+ bool server_id_match = true;
uint32_t requested_ip_opt = 0;
SERVER_DEBUG("");
@@ -612,12 +615,11 @@ static void listener_event(const void *data, size_t len, void *user_data)
break;
case L_DHCP_OPTION_SERVER_IDENTIFIER:
- if (l == 4)
- server_id_opt = l_get_u32(v);
-
- if (server->address != server_id_opt)
- return;
+ if (l != 4)
+ break;
+ server_id_opt = true;
+ server_id_match = (l_get_u32(v) == server->address);
break;
case L_DHCP_OPTION_REQUESTED_IP_ADDRESS:
if (l == 4)
@@ -640,6 +642,9 @@ static void listener_event(const void *data, size_t len, void *user_data)
SERVER_DEBUG("Received DISCOVER, requested IP "NIPQUAD_FMT,
NIPQUAD(requested_ip_opt));
+ if (!server_id_match)
+ break;
+
send_offer(server, message, lease, requested_ip_opt);
break;
@@ -647,27 +652,91 @@ static void listener_event(const void *data, size_t len, void *user_data)
SERVER_DEBUG("Received REQUEST, requested IP "NIPQUAD_FMT,
NIPQUAD(requested_ip_opt));
- if (requested_ip_opt == 0) {
- requested_ip_opt = message->ciaddr;
- if (requested_ip_opt == 0)
+ /*
+ * RFC2131 Section 3.5: "Those servers not selected by the
+ * DHCPREQUEST message use the message as notification that
+ * the client has declined that server's offer."
+ */
+ if (!server_id_match) {
+ if (server->authoritative) {
+ send_nak(server, message);
+ break;
+ }
+
+ if (!lease || !lease->offering)
break;
- }
- if (lease && requested_ip_opt == lease->address) {
- send_ack(server, message, lease->address);
+ remove_lease(server, lease);
break;
}
- if (server_id_opt || !lease) {
- send_nak(server, message);
+ /*
+ * RFC2131 Section 3.5: "If the selected server is unable to
+ * satisfy the DHCPREQUEST message (...), the server SHOULD
+ * respond with a DHCPNAK message."
+ *
+ * But:
+ * 4.3.2: "If the DHCP server has no record of this client,
+ * then it MUST remain silent (...)"
+ */
+ if (!lease) {
+ if (server_id_opt || server->authoritative)
+ send_nak(server, message);
+
break;
}
+
+ /*
+ * 4.3.2: "If the DHCPREQUEST message contains a 'server
+ * identifier' option, the message is in response to a
+ * DHCPOFFER message. Otherwise, the message is a request
+ * to verify or extend an existing lease."
+ */
+ if (server_id_opt && server_id_match) {
+ /*
+ * Allow either no 'requested IP address' option or
+ * a value identical with the one we offered because
+ * the spec is unclear on whether it is to be
+ * included:
+ *
+ * Section 4.3.2: "DHCPREQUEST generated during
+ * SELECTING state: (...) 'requested IP address' MUST
+ * be filled in with the yiaddr value from the chosen
+ * DHCPOFFER."
+ *
+ * but section 3.5 suggests only in the INIT-REBOOT
+ * state: "The 'requested IP address' option is to be
+ * filled in only in a DHCPREQUEST message when the
+ * client is verifying network parameters obtained
+ * previously."
+ */
+ if (!lease->offering ||
+ (requested_ip_opt &&
+ requested_ip_opt != lease->address)) {
+ send_nak(server, message);
+ break;
+ }
+ } else {
+ /*
+ * 3.5: "If a server receives a DHCPREQUEST message
+ * with an invalid 'requested IP address', the server
+ * SHOULD respond to the client with a DHCPNAK message"
+ */
+ if (lease->offering ||
+ (requested_ip_opt &&
+ requested_ip_opt != lease->address)) {
+ send_nak(server, message);
+ break;
+ }
+ }
+
+ send_ack(server, message, lease->address);
break;
case DHCP_MESSAGE_TYPE_DECLINE:
SERVER_DEBUG("Received DECLINE");
- if (!server_id_opt || !requested_ip_opt || !lease ||
- !lease->offering)
+ if (!server_id_opt || !server_id_match || !requested_ip_opt ||
+ !lease || !lease->offering)
break;
if (requested_ip_opt == lease->address)
@@ -677,7 +746,8 @@ static void listener_event(const void *data, size_t len, void *user_data)
case DHCP_MESSAGE_TYPE_RELEASE:
SERVER_DEBUG("Received RELEASE");
- if (!server_id_opt || !lease || lease->offering)
+ if (!server_id_opt || !server_id_match || !lease ||
+ lease->offering)
break;
if (message->ciaddr == lease->address)
@@ -687,6 +757,9 @@ static void listener_event(const void *data, size_t len, void *user_data)
case DHCP_MESSAGE_TYPE_INFORM:
SERVER_DEBUG("Received INFORM");
+ if (!server_id_match)
+ break;
+
send_inform(server, message);
break;
}
@@ -732,6 +805,7 @@ LIB_EXPORT struct l_dhcp_server *l_dhcp_server_new(int ifindex)
server->expired_list = l_queue_new();
server->started = false;
+ server->authoritative = true;
server->lease_seconds = DEFAULT_DHCP_LEASE_SEC;
server->max_expired = MAX_EXPIRED_LEASES;
@@ -1053,6 +1127,15 @@ failed:
return false;
}
+LIB_EXPORT void l_dhcp_server_set_authoritative(struct l_dhcp_server *server,
+ bool authoritative)
+{
+ if (unlikely(!server))
+ return;
+
+ server->authoritative = authoritative;
+}
+
LIB_EXPORT struct l_dhcp_lease *l_dhcp_server_discover(
struct l_dhcp_server *server,
uint32_t requested_ip_opt,
diff --git a/ell/dhcp.h b/ell/dhcp.h
index 2804c78..830cbb1 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -141,6 +141,8 @@ bool l_dhcp_server_set_ip_address(struct l_dhcp_server *server,
bool l_dhcp_server_set_netmask(struct l_dhcp_server *server, const char *mask);
bool l_dhcp_server_set_gateway(struct l_dhcp_server *server, const char *ip);
bool l_dhcp_server_set_dns(struct l_dhcp_server *server, char **dns);
+void l_dhcp_server_set_authoritative(struct l_dhcp_server *server,
+ bool authoritative);
struct l_dhcp_lease *l_dhcp_server_discover(struct l_dhcp_server *server,
uint32_t requested_ip_opt,
diff --git a/ell/ell.sym b/ell/ell.sym
index 414c6d4..a781dea 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -259,6 +259,7 @@ global:
l_dhcp_server_set_netmask;
l_dhcp_server_set_gateway;
l_dhcp_server_set_dns;
+ l_dhcp_server_set_authoritative;
l_dhcp_server_discover;
l_dhcp_server_request;
l_dhcp_server_decline;
--
2.30.2
11 months