typedef struct CPUSet CPUSet;
typedef struct FDSet FDSet;
typedef struct Fido2HmacSalt Fido2HmacSalt;
-typedef struct FirewallContext FirewallContext;
typedef struct GroupRecord GroupRecord;
typedef struct Image Image;
typedef struct ImagePolicy ImagePolicy;
#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
-#include "firewall-util.h"
#include "in-addr-prefix-util.h"
#include "inotify-util.h"
#include "ip-protocol-list.h"
#include "limits-util.h"
#include "manager.h"
+#include "netlink-internal.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
if (!crt || crt->cgroup_id == 0)
return;
- if (!u->manager->fw_ctx) {
- r = fw_ctx_new_full(&u->manager->fw_ctx, /* init_tables= */ false);
+ if (!u->manager->nfnl) {
+ r = sd_nfnl_socket_open(&u->manager->nfnl);
if (r < 0)
return;
-
- assert(u->manager->fw_ctx);
}
CGroupContext *c = ASSERT_PTR(unit_get_cgroup_context(u));
uint64_t element = crt->cgroup_id;
- r = nft_set_element_modify_any(u->manager->fw_ctx, add, nft_set->nfproto, nft_set->table, nft_set->set, &element, sizeof(element));
+ r = nft_set_element_modify_any(u->manager->nfnl, add, nft_set->nfproto, nft_set->table, nft_set->set, &element, sizeof(element));
if (r < 0)
log_warning_errno(r, "Failed to %s NFT set entry: family %s, table %s, set %s, cgroup %" PRIu64 ", ignoring: %m",
add? "add" : "delete", nfproto_to_string(nft_set->nfproto), nft_set->table, nft_set->set, crt->cgroup_id);
#include "cgroup-util.h"
#include "dbus-cgroup.h"
#include "escape.h"
-#include "firewall-util.h"
#include "in-addr-prefix-util.h"
#include "limits-util.h"
#include "manager.h"
#include "execute.h"
#include "extract-word.h"
#include "fd-util.h"
-#include "firewall-util.h"
#include "fstab-util.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-messages.h"
+#include "sd-netlink.h"
#include "sd-path.h"
#include "all-units.h"
free(m->watchdog_pretimeout_governor);
free(m->watchdog_pretimeout_governor_overridden);
- fw_ctx_free(m->fw_ctx);
+ sd_netlink_unref(m->nfnl);
#if BPF_FRAMEWORK
bpf_restrict_fs_destroy(m->restrict_fs);
sd_event_source *memory_pressure_event_source;
/* For NFTSet= */
- FirewallContext *fw_ctx;
+ sd_netlink *nfnl;
/* Pin the systemd-executor binary, so that it never changes until re-exec, ensuring we don't have
* serialization/deserialization compatibility issues during upgrades. */
#include "manager.h"
#include "mount-util.h"
#include "mountpoint-util.h"
+#include "netlink-internal.h"
#include "path-util.h"
#include "process-util.h"
#include "quota-util.h"
if (!c)
return;
- if (!u->manager->fw_ctx) {
- r = fw_ctx_new_full(&u->manager->fw_ctx, /* init_tables= */ false);
+ if (!u->manager->nfnl) {
+ r = sd_nfnl_socket_open(&u->manager->nfnl);
if (r < 0)
return;
-
- assert(u->manager->fw_ctx);
}
FOREACH_ARRAY(nft_set, c->nft_set_context.sets, c->nft_set_context.n_sets) {
if (nft_set->source != source)
continue;
- r = nft_set_element_modify_any(u->manager->fw_ctx, add, nft_set->nfproto, nft_set->table, nft_set->set, &element, sizeof(element));
+ r = nft_set_element_modify_any(u->manager->nfnl, add, nft_set->nfproto, nft_set->table, nft_set->set, &element, sizeof(element));
if (r < 0)
log_warning_errno(r, "Failed to %s NFT set entry: family %s, table %s, set %s, ID %u, ignoring: %m",
add? "add" : "delete", nfproto_to_string(nft_set->nfproto), nft_set->table, nft_set->set, element);
assert(address);
assert(address->link);
+ assert(address->link->manager);
+
+ if (!address->link->manager->nfnl)
+ return 0;
if (!address->link->network)
return 0;
if (r < 0)
return r;
- r = fw_add_masquerade(&address->link->manager->fw_ctx, add, address->family, &masked, address->prefixlen);
+ r = fw_nftables_add_masquerade(address->link->manager->nfnl, add, address->family, &masked, address->prefixlen);
if (r < 0)
return r;
assert(address);
assert(address->link);
assert(address->link->manager);
+ assert(address->link->manager->nfnl);
assert(nft_set_context);
- if (!address->link->manager->fw_ctx) {
- r = fw_ctx_new_full(&address->link->manager->fw_ctx, /* init_tables= */ false);
- if (r < 0)
- return;
- }
-
FOREACH_ARRAY(nft_set, nft_set_context->sets, nft_set_context->n_sets) {
uint32_t ifindex;
switch (nft_set->source) {
case NFT_SET_SOURCE_ADDRESS:
- r = nft_set_element_modify_ip(address->link->manager->fw_ctx, add, nft_set->nfproto, address->family, nft_set->table, nft_set->set,
+ r = nft_set_element_modify_ip(address->link->manager->nfnl, add, nft_set->nfproto, address->family, nft_set->table, nft_set->set,
&address->in_addr);
break;
case NFT_SET_SOURCE_PREFIX:
- r = nft_set_element_modify_iprange(address->link->manager->fw_ctx, add, nft_set->nfproto, address->family, nft_set->table, nft_set->set,
+ r = nft_set_element_modify_iprange(address->link->manager->nfnl, add, nft_set->nfproto, address->family, nft_set->table, nft_set->set,
&address->in_addr, address->prefixlen);
break;
case NFT_SET_SOURCE_IFINDEX:
ifindex = address->link->ifindex;
- r = nft_set_element_modify_any(address->link->manager->fw_ctx, add, nft_set->nfproto, nft_set->table, nft_set->set,
+ r = nft_set_element_modify_any(address->link->manager->nfnl, add, nft_set->nfproto, nft_set->table, nft_set->set,
&ifindex, sizeof(ifindex));
break;
default:
static void address_modify_nft_set(Address *address, bool add) {
assert(address);
assert(address->link);
+ assert(address->link->manager);
+
+ if (!address->link->manager->nfnl)
+ return;
if (!IN_SET(address->family, AF_INET, AF_INET6))
return;
#include "env-util.h"
#include "errno-util.h"
#include "fd-util.h"
-#include "firewall-util.h"
#include "initrd-util.h"
#include "mount-util.h"
+#include "netlink-internal.h"
#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-address-label.h"
return 0;
}
+static int manager_connect_nfnl(Manager *m) {
+ int r;
+
+ assert(m);
+
+ r = sd_nfnl_socket_open(&m->nfnl);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to open nftables netlink socket. IPMasquerade= and NFTSet= settings will not be applied. Ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_increase_rxbuf(m->nfnl, RCVBUF_SIZE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to increase receive buffer size for nftables netlink socket, ignoring: %m");
+
+ r = sd_netlink_attach_event(m->nfnl, m->event, 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int manager_setup_rtnl_filter(Manager *manager) {
struct sock_filter filter[] = {
/* Check the packet length. */
if (netlink_get_reply_callback_count(manager->rtnl) > 0 ||
netlink_get_reply_callback_count(manager->genl) > 0 ||
- fw_ctx_get_reply_callback_count(manager->fw_ctx) > 0)
+ netlink_get_reply_callback_count(manager->nfnl) > 0)
return 0; /* There are some message calls waiting for their replies. */
(void) manager_serialize(manager);
if (r < 0)
return r;
+ r = manager_connect_nfnl(m);
+ if (r < 0)
+ return r;
+
if (m->test_mode)
return 0;
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
+ sd_netlink_unref(m->nfnl);
sd_resolve_unref(m->resolve);
m->routes = set_free(m->routes);
safe_close(m->ethtool_fd);
safe_close(m->persistent_storage_fd);
- m->fw_ctx = fw_ctx_free(m->fw_ctx);
-
m->serialization_fd = safe_close(m->serialization_fd);
return mfree(m);
sd_netlink *rtnl;
/* lazy initialized */
sd_netlink *genl;
+ sd_netlink *nfnl;
sd_event *event;
sd_resolve *resolve;
sd_bus *bus;
usec_t speed_meter_usec_new;
usec_t speed_meter_usec_old;
- FirewallContext *fw_ctx;
-
bool request_queued;
OrderedSet *request_queue;
OrderedSet *remove_request_queue;
* queued, then this event may make reply callback queue in sd-netlink full. */
if (netlink_get_reply_callback_count(manager->rtnl) >= REPLY_CALLBACK_COUNT_THRESHOLD ||
netlink_get_reply_callback_count(manager->genl) >= REPLY_CALLBACK_COUNT_THRESHOLD ||
- fw_ctx_get_reply_callback_count(manager->fw_ctx) >= REPLY_CALLBACK_COUNT_THRESHOLD)
+ netlink_get_reply_callback_count(manager->nfnl) >= REPLY_CALLBACK_COUNT_THRESHOLD)
break;
/* Avoid the request and link freed by req->process() and request_detach(). */
LIST_CLEAR(ports, p, free);
}
-int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_addr_union *exposed) {
+int expose_port_flush(sd_netlink *nfnl, ExposePort* l, int af, union in_addr_union *exposed) {
int r;
+ assert(IN_SET(af, AF_INET, AF_INET6));
assert(exposed);
- if (!l)
+ if (!nfnl || !l)
return 0;
if (!in_addr_is_set(af, exposed))
log_debug("Lost IP address.");
LIST_FOREACH(ports, p, l) {
- r = fw_add_local_dnat(fw_ctx,
- false,
- af,
- p->protocol,
- p->host_port,
- exposed,
- p->container_port,
- NULL);
+ r = fw_nftables_add_local_dnat(
+ nfnl,
+ /* add = */ false,
+ af,
+ p->protocol,
+ p->host_port,
+ exposed,
+ p->container_port,
+ /* previous_remote = */ NULL);
if (r < 0)
log_warning_errno(r, "Failed to modify %s firewall: %m", af_to_name(af));
}
return 0;
}
-int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, int af, union in_addr_union *exposed) {
+int expose_port_execute(sd_netlink *rtnl, sd_netlink *nfnl, ExposePort *l, int af, union in_addr_union *exposed) {
_cleanup_free_ struct local_address *addresses = NULL;
union in_addr_union new_exposed;
bool add;
int r;
+ assert(rtnl);
+ assert(nfnl);
+ assert(IN_SET(af, AF_INET, AF_INET6));
assert(exposed);
/* Invoked each time an address is added or removed inside the
addresses[0].scope < RT_SCOPE_LINK;
if (!add)
- return expose_port_flush(fw_ctx, l, af, exposed);
+ return expose_port_flush(nfnl, l, af, exposed);
new_exposed = addresses[0].address;
if (in_addr_equal(af, exposed, &new_exposed))
log_debug("New container IP is %s.", IN_ADDR_TO_STRING(af, &new_exposed));
LIST_FOREACH(ports, p, l) {
- r = fw_add_local_dnat(fw_ctx,
- true,
- af,
- p->protocol,
- p->host_port,
- &new_exposed,
- p->container_port,
- in_addr_is_set(af, exposed) ? exposed : NULL);
+ r = fw_nftables_add_local_dnat(
+ nfnl,
+ /* add = */ true,
+ af,
+ p->protocol,
+ p->host_port,
+ &new_exposed,
+ p->container_port,
+ in_addr_is_set(af, exposed) ? exposed : NULL);
if (r < 0)
log_warning_errno(r, "Failed to modify %s firewall: %m", af_to_name(af));
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include "firewall-util.h"
#include "forward.h"
#include "list.h"
int expose_port_watch_rtnl(sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, void *userdata, sd_netlink **ret);
int expose_port_send_rtnl(int send_fd);
-int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, int af, union in_addr_union *exposed);
-int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_addr_union *exposed);
+int expose_port_execute(sd_netlink *rtnl, sd_netlink *nfnl, ExposePort *l, int af, union in_addr_union *exposed);
+int expose_port_flush(sd_netlink *nfnl, ExposePort* l, int af, union in_addr_union *exposed);
#include "mount-util.h"
#include "mountpoint-util.h"
#include "namespace-util.h"
+#include "netlink-internal.h"
#include "notify-recv.h"
#include "nspawn-bind-user.h"
#include "nspawn-cgroup.h"
struct ExposeArgs {
union in_addr_union address4;
union in_addr_union address6;
- struct FirewallContext *fw_ctx;
+ sd_netlink *nfnl;
};
static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
assert(rtnl);
assert(m);
- (void) expose_port_execute(rtnl, &args->fw_ctx, arg_expose_ports, AF_INET, &args->address4);
- (void) expose_port_execute(rtnl, &args->fw_ctx, arg_expose_ports, AF_INET6, &args->address6);
+ (void) expose_port_execute(rtnl, args->nfnl, arg_expose_ports, AF_INET, &args->address4);
+ (void) expose_port_execute(rtnl, args->nfnl, arg_expose_ports, AF_INET6, &args->address6);
return 0;
}
if (r < 0)
return r;
- (void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET, &expose_args->address4);
- (void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6);
+ (void) expose_port_execute(rtnl, expose_args->nfnl, arg_expose_ports, AF_INET, &expose_args->address4);
+ (void) expose_port_execute(rtnl, expose_args->nfnl, arg_expose_ports, AF_INET6, &expose_args->address6);
}
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
return 0; /* finito */
}
- expose_port_flush(&expose_args->fw_ctx, arg_expose_ports, AF_INET, &expose_args->address4);
- expose_port_flush(&expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6);
+ expose_port_flush(expose_args->nfnl, arg_expose_ports, AF_INET, &expose_args->address4);
+ expose_port_flush(expose_args->nfnl, arg_expose_ports, AF_INET6, &expose_args->address6);
(void) remove_veth_links(veth_name, arg_network_veth_extra);
*veth_created = false;
_cleanup_(rmdir_and_freep) char *rootdir = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_(fw_ctx_freep) FirewallContext *fw_ctx = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
log_setup();
}
if (arg_expose_ports) {
- r = fw_ctx_new(&fw_ctx);
+ r = sd_nfnl_socket_open(&nfnl);
if (r < 0) {
- log_error_errno(r, "Cannot expose configured ports, firewall initialization failed: %m");
+ log_error_errno(r, "Cannot expose configured ports, failed to initialize nftables: %m");
goto finish;
}
- expose_args.fw_ctx = fw_ctx;
+ expose_args.nfnl = nfnl;
}
for (;;) {
cleanup_propagation_and_export_directories();
- expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET, &expose_args.address4);
- expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET6, &expose_args.address6);
+ expose_port_flush(nfnl, arg_expose_ports, AF_INET, &expose_args.address4);
+ expose_port_flush(nfnl, arg_expose_ports, AF_INET6, &expose_args.address6);
if (arg_userns_mode != USER_NAMESPACE_MANAGED) {
if (veth_created)
#include "escape.h"
#include "extract-word.h"
#include "firewall-util.h"
-#include "firewall-util-private.h"
#include "in-addr-util.h"
#include "log.h"
#include "netlink-internal.h"
return 0;
}
-int fw_nftables_init_full(FirewallContext *ctx, bool init_tables) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
- int r;
-
- assert(ctx);
- assert(!ctx->nfnl);
-
- r = sd_nfnl_socket_open(&nfnl);
- if (r < 0)
- return r;
-
- if (init_tables) {
- r = fw_nftables_init_family(nfnl, AF_INET);
- if (r < 0)
- return r;
-
- if (socket_ipv6_is_supported()) {
- r = fw_nftables_init_family(nfnl, AF_INET6);
- if (r < 0)
- return log_error_errno(r, "Failed to init ipv6 NAT: %m");
- }
- }
-
- ctx->nfnl = TAKE_PTR(nfnl);
- return 0;
-}
-
-int fw_nftables_init(FirewallContext *ctx) {
- return fw_nftables_init_full(ctx, /* init_tables= */ true);
-}
-
-void fw_nftables_exit(FirewallContext *ctx) {
- assert(ctx);
-
- ctx->nfnl = sd_netlink_unref(ctx->nfnl);
-}
-
static int nft_message_append_setelem_iprange(
sd_netlink_message *m,
const union in_addr_union *source,
}
int nft_set_element_modify_iprange(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int nfproto,
int af,
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
- assert(ctx->nfnl);
+ assert(nfnl);
assert(IN_SET(af, AF_INET, AF_INET6));
assert(nfproto_is_valid(nfproto));
assert(table);
if (af == AF_INET6 && source_prefixlen < 8)
return -EINVAL;
- r = sd_nfnl_nft_message_new_setelems(ctx->nfnl, &m, add, nfproto, table, set);
+ r = sd_nfnl_nft_message_new_setelems(nfnl, &m, add, nfproto, table, set);
if (r < 0)
return r;
if (r < 0)
return r;
- return sd_nfnl_call_batch(ctx->nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
+ return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
}
int nft_set_element_modify_ip(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int nfproto,
int af,
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
- assert(ctx->nfnl);
+ assert(nfnl);
assert(IN_SET(af, AF_INET, AF_INET6));
assert(nfproto_is_valid(nfproto));
assert(table);
if (!source)
return -EINVAL;
- r = sd_nfnl_nft_message_new_setelems(ctx->nfnl, &m, add, nfproto, table, set);
+ r = sd_nfnl_nft_message_new_setelems(nfnl, &m, add, nfproto, table, set);
if (r < 0)
return r;
if (r < 0)
return r;
- return sd_nfnl_call_batch(ctx->nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
+ return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
}
-int nft_set_element_modify_any(FirewallContext *ctx, bool add, int nfproto, const char *table, const char *set, const void *element, size_t element_size) {
+int nft_set_element_modify_any(
+ sd_netlink *nfnl,
+ bool add,
+ int nfproto,
+ const char *table,
+ const char *set,
+ const void *element,
+ size_t element_size) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
- assert(ctx);
- assert(ctx->nfnl);
+ assert(nfnl);
assert(nfproto_is_valid(nfproto));
assert(table);
assert(set);
assert(element);
if (add)
- r = nft_add_element(ctx->nfnl, &m, nfproto, table, set, element, element_size, NULL, 0);
+ r = nft_add_element(nfnl, &m, nfproto, table, set, element, element_size, NULL, 0);
else
- r = nft_del_element(ctx->nfnl, &m, nfproto, table, set, element, element_size, NULL, 0);
+ r = nft_del_element(nfnl, &m, nfproto, table, set, element, element_size, NULL, 0);
if (r < 0)
return r;
- return sd_nfnl_call_batch(ctx->nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
+ return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL);
}
static int af_to_nfproto(int af) {
}
int fw_nftables_add_masquerade(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int af,
const union in_addr_union *source,
int r;
- assert(ctx);
- assert(ctx->nfnl);
+ assert(nfnl);
assert(IN_SET(af, AF_INET, AF_INET6));
if (!socket_ipv6_is_supported() && af == AF_INET6)
return -EOPNOTSUPP;
- r = nft_set_element_modify_iprange(ctx, add, af_to_nfproto(af), af, nft_table_name(), NFT_SYSTEMD_MASQ_SET_NAME,
+ r = nft_set_element_modify_iprange(nfnl, add, af_to_nfproto(af), af, nft_table_name(), NFT_SYSTEMD_MASQ_SET_NAME,
source, source_prefixlen);
if (r != -ENOENT)
return r;
* of extending the kernel to allow tables to be owned by stystemd-networkd and making them
* non-deleteable except by the 'owning process'. */
- r = fw_nftables_init_family(ctx->nfnl, af);
+ r = fw_nftables_init_family(nfnl, af);
if (r < 0)
return r;
- return nft_set_element_modify_iprange(ctx, add, af_to_nfproto(af), af, nft_table_name(), NFT_SYSTEMD_MASQ_SET_NAME,
+ return nft_set_element_modify_iprange(nfnl, add, af_to_nfproto(af), af, nft_table_name(), NFT_SYSTEMD_MASQ_SET_NAME,
source, source_prefixlen);
}
}
int fw_nftables_add_local_dnat(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int af,
int protocol,
int r;
- assert(ctx);
- assert(ctx->nfnl);
+ assert(nfnl);
assert(IN_SET(af, AF_INET, AF_INET6));
if (!socket_ipv6_is_supported() && af == AF_INET6)
return -EOPNOTSUPP;
- r = fw_nftables_add_local_dnat_internal(ctx->nfnl, add, af, protocol, local_port, remote, remote_port, previous_remote);
+ r = fw_nftables_add_local_dnat_internal(nfnl, add, af, protocol, local_port, remote, remote_port, previous_remote);
if (r != -ENOENT)
return r;
/* See comment in fw_nftables_add_masquerade(). */
- r = fw_nftables_init_family(ctx->nfnl, af);
+ r = fw_nftables_init_family(nfnl, af);
if (r < 0)
return r;
/* table created anew; previous address already gone */
- return fw_nftables_add_local_dnat_internal(ctx->nfnl, add, af, protocol, local_port, remote, remote_port, NULL);
+ return fw_nftables_add_local_dnat_internal(nfnl, add, af, protocol, local_port, remote, remote_port, NULL);
}
static const char *const nfproto_table[] = {
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "firewall-util.h"
-#include "forward.h"
-
-typedef enum FirewallBackend {
- FW_BACKEND_NONE,
- FW_BACKEND_NFTABLES,
- _FW_BACKEND_MAX,
- _FW_BACKEND_INVALID = -EINVAL,
-} FirewallBackend;
-
-struct FirewallContext {
- FirewallBackend backend;
- sd_netlink *nfnl;
-};
-
-const char* firewall_backend_to_string(FirewallBackend b) _const_;
-
-int fw_nftables_init(FirewallContext *ctx);
-int fw_nftables_init_full(FirewallContext *ctx, bool init_tables);
-void fw_nftables_exit(FirewallContext *ctx);
-
-int fw_nftables_add_masquerade(
- FirewallContext *ctx,
- bool add,
- int af,
- const union in_addr_union *source,
- unsigned source_prefixlen);
-
-int fw_nftables_add_local_dnat(
- FirewallContext *ctx,
- bool add,
- int af,
- int protocol,
- uint16_t local_port,
- const union in_addr_union *remote,
- uint16_t remote_port,
- const union in_addr_union *previous_remote);
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "firewall-util.h"
-#include "firewall-util-private.h"
-#include "log.h"
-#include "netlink-util.h"
-#include "string-table.h"
-#include "string-util.h"
-
-static const char * const firewall_backend_table[_FW_BACKEND_MAX] = {
- [FW_BACKEND_NONE] = "none",
- [FW_BACKEND_NFTABLES] = "nftables",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_TO_STRING(firewall_backend, FirewallBackend);
-
-static void firewall_backend_probe(FirewallContext *ctx, bool init_tables) {
- const char *e;
-
- assert(ctx);
-
- if (ctx->backend != _FW_BACKEND_INVALID)
- return;
-
- e = secure_getenv("SYSTEMD_FIREWALL_BACKEND");
- if (e) {
- if (streq(e, "nftables"))
- ctx->backend = FW_BACKEND_NFTABLES;
- else
- log_debug("Unrecognized $SYSTEMD_FIREWALL_BACKEND value, ignoring: %s", e);
- }
-
- if (ctx->backend == _FW_BACKEND_INVALID) {
-
- if (fw_nftables_init_full(ctx, init_tables) >= 0)
- ctx->backend = FW_BACKEND_NFTABLES;
- else
- ctx->backend = FW_BACKEND_NONE;
- }
-
- if (ctx->backend != FW_BACKEND_NONE)
- log_debug("Using %s as firewall backend.", firewall_backend_to_string(ctx->backend));
- else
- log_debug("No firewall backend found.");
-}
-
-int fw_ctx_new_full(FirewallContext **ret, bool init_tables) {
- _cleanup_free_ FirewallContext *ctx = NULL;
-
- ctx = new(FirewallContext, 1);
- if (!ctx)
- return -ENOMEM;
-
- *ctx = (FirewallContext) {
- .backend = _FW_BACKEND_INVALID,
- };
-
- firewall_backend_probe(ctx, init_tables);
-
- *ret = TAKE_PTR(ctx);
- return 0;
-}
-
-int fw_ctx_new(FirewallContext **ret) {
- return fw_ctx_new_full(ret, /* init_tables= */ true);
-}
-
-FirewallContext *fw_ctx_free(FirewallContext *ctx) {
- if (!ctx)
- return NULL;
-
- fw_nftables_exit(ctx);
-
- return mfree(ctx);
-}
-
-size_t fw_ctx_get_reply_callback_count(FirewallContext *ctx) {
- if (!ctx || !ctx->nfnl)
- return 0;
-
- return netlink_get_reply_callback_count(ctx->nfnl);
-}
-
-int fw_add_masquerade(
- FirewallContext **ctx,
- bool add,
- int af,
- const union in_addr_union *source,
- unsigned source_prefixlen) {
-
- int r;
-
- assert(ctx);
-
- if (!*ctx) {
- r = fw_ctx_new(ctx);
- if (r < 0)
- return r;
- }
-
- switch ((*ctx)->backend) {
- case FW_BACKEND_NFTABLES:
- return fw_nftables_add_masquerade(*ctx, add, af, source, source_prefixlen);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-int fw_add_local_dnat(
- FirewallContext **ctx,
- bool add,
- int af,
- int protocol,
- uint16_t local_port,
- const union in_addr_union *remote,
- uint16_t remote_port,
- const union in_addr_union *previous_remote) {
-
- int r;
-
- assert(ctx);
-
- if (!*ctx) {
- r = fw_ctx_new(ctx);
- if (r < 0)
- return r;
- }
-
- switch ((*ctx)->backend) {
- case FW_BACKEND_NFTABLES:
- return fw_nftables_add_local_dnat(*ctx, add, af, protocol, local_port, remote, remote_port, previous_remote);
- default:
- return -EOPNOTSUPP;
- }
-}
#include "conf-parser-forward.h"
#include "forward.h"
-typedef struct FirewallContext FirewallContext;
-
-int fw_ctx_new(FirewallContext **ret);
-int fw_ctx_new_full(FirewallContext **ret, bool init_tables);
-FirewallContext *fw_ctx_free(FirewallContext *ctx);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FirewallContext *, fw_ctx_free);
-
-size_t fw_ctx_get_reply_callback_count(FirewallContext *ctx);
-
-int fw_add_masquerade(
- FirewallContext **ctx,
+int fw_nftables_add_masquerade(
+ sd_netlink *nfnl,
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen);
-int fw_add_local_dnat(
- FirewallContext **ctx,
+int fw_nftables_add_local_dnat(
+ sd_netlink *nfnl,
bool add,
int af,
int protocol,
int nft_set_source_from_string(const char *s) _pure_;
int nft_set_element_modify_iprange(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int nfproto,
int af,
unsigned source_prefixlen);
int nft_set_element_modify_ip(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int nfproto,
int af,
const union in_addr_union *source);
int nft_set_element_modify_any(
- FirewallContext *ctx,
+ sd_netlink *nfnl,
bool add,
int nfproto,
const char *table,
'fido2-util.c',
'find-esp.c',
'firewall-util-nft.c',
- 'firewall-util.c',
'fork-notify.c',
'format-table.c',
'fstab-util.c',
#include <stdlib.h>
#include <unistd.h>
+#include "sd-netlink.h"
+
#include "firewall-util.h"
-#include "firewall-util-private.h"
#include "in-addr-util.h"
#include "log.h"
+#include "netlink-internal.h"
#include "random-util.h"
#include "socket-util.h"
#include "tests.h"
-static void test_v6(FirewallContext *ctx) {
+static sd_netlink *nfnl = NULL;
+
+TEST(v6) {
union in_addr_union u1, u2, u3;
uint8_t prefixlen;
int r;
- ASSERT_NOT_NULL(ctx);
-
- log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend));
+ ASSERT_NOT_NULL(nfnl);
if (!socket_ipv6_is_supported())
return log_info("IPv6 is not supported by kernel, skipping tests.");
prefixlen = random_u64_range(128 + 1 - 8) + 8;
random_bytes(&u3, sizeof(u3));
- ASSERT_OK(fw_add_masquerade(&ctx, true, AF_INET6, &u1, 128));
- ASSERT_OK(fw_add_masquerade(&ctx, false, AF_INET6, &u1, 128));
- ASSERT_OK(fw_add_masquerade(&ctx, true, AF_INET6, &u1, 64));
- ASSERT_OK(fw_add_masquerade(&ctx, false, AF_INET6, &u1, 64));
- ASSERT_OK(fw_add_masquerade(&ctx, true, AF_INET6, &u3, prefixlen));
- ASSERT_OK(fw_add_masquerade(&ctx, false, AF_INET6, &u3, prefixlen));
-
- r = fw_add_local_dnat(&ctx, true, AF_INET6, IPPROTO_TCP, 4711, &u1, 815, NULL);
- if (r == -EOPNOTSUPP) {
- log_info("IPv6 DNAT seems not supported, skipping the following tests.");
- return;
- }
- ASSERT_OK(r);
-
- ASSERT_OK(fw_add_local_dnat(&ctx, true, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, &u1));
- ASSERT_OK(fw_add_local_dnat(&ctx, false, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, NULL));
+ ASSERT_OK_OR(r = fw_nftables_add_masquerade(nfnl, true, AF_INET6, &u1, 128),
+ -EPERM, -EOPNOTSUPP, -ENOPROTOOPT);
+ if (r < 0)
+ return (void) log_tests_skipped_errno(r, "Failed to add IPv6 masquerade");
+
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET6, &u1, 128));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, true, AF_INET6, &u1, 64));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET6, &u1, 64));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, true, AF_INET6, &u3, prefixlen));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET6, &u3, prefixlen));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, true, AF_INET6, IPPROTO_TCP, 4711, &u1, 815, NULL));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, true, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, &u1));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, false, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, NULL));
}
static union in_addr_union *parse_addr(const char *str, union in_addr_union *u) {
return u;
}
-static bool test_v4(FirewallContext *ctx) {
+TEST(v4) {
union in_addr_union u, v;
int r;
- ASSERT_NOT_NULL(ctx);
-
- log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend));
-
- ASSERT_ERROR(fw_add_masquerade(&ctx, true, AF_INET, NULL, 0), EINVAL);
- ASSERT_ERROR(fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.1.2.0", &u), 0), EINVAL);
-
- r = fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.1.2.3", &u), 32);
- if (r < 0) {
- bool ignore = IN_SET(r, -EPERM, -EOPNOTSUPP, -ENOPROTOOPT);
-
- log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r,
- "Failed to add IPv4 masquerade%s: %m",
- ignore ? ", skipping following tests" : "");
+ ASSERT_NOT_NULL(nfnl);
- if (ignore)
- return false;
- }
- ASSERT_OK(r);
+ ASSERT_ERROR(fw_nftables_add_masquerade(nfnl, true, AF_INET, NULL, 0), EINVAL);
+ ASSERT_ERROR(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.1.2.0", &u), 0), EINVAL);
- ASSERT_OK(fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.0.2.0", &u), 28));
- ASSERT_OK(fw_add_masquerade(&ctx, false, AF_INET, parse_addr("10.0.2.0", &u), 28));
- ASSERT_OK(fw_add_masquerade(&ctx, false, AF_INET, parse_addr("10.1.2.3", &u), 32));
- ASSERT_OK(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL));
- ASSERT_OK(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL));
- ASSERT_OK(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, parse_addr("1.2.3.4", &v)));
- ASSERT_OK(fw_add_local_dnat(&ctx, false, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, NULL));
+ ASSERT_OK_OR(r = fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.1.2.3", &u), 32),
+ -EPERM, -EOPNOTSUPP, -ENOPROTOOPT);
+ if (r < 0)
+ return (void) log_tests_skipped_errno(r, "Failed to add IPv4 masquerade");
- return true;
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.0.2.0", &u), 28));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET, parse_addr("10.0.2.0", &u), 28));
+ ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET, parse_addr("10.1.2.3", &u), 32));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, parse_addr("1.2.3.4", &v)));
+ ASSERT_OK(fw_nftables_add_local_dnat(nfnl, false, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, NULL));
}
-int main(int argc, char *argv[]) {
- _cleanup_(fw_ctx_freep) FirewallContext *ctx = NULL;
-
- test_setup_logging(LOG_DEBUG);
+static int intro(void) {
+ int r;
if (getuid() != 0)
return log_tests_skipped("not root");
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_NFT_TABLE_NAME", "io.systemd-test.nat", /* overwrite = */ true));
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_DNAT_MAP_NAME", "test_map_port_ipport", /* overwrite = */ true));
- ASSERT_OK(fw_ctx_new(&ctx));
- ASSERT_NOT_NULL(ctx);
-
- if (ctx->backend == FW_BACKEND_NONE)
- return log_tests_skipped("no firewall backend supported");
+ r = sd_nfnl_socket_open(&nfnl);
+ if (r < 0)
+ return log_tests_skipped_errno(r, "Failed to initialize nftables");
- if (test_v4(ctx) && ctx->backend == FW_BACKEND_NFTABLES)
- test_v6(ctx);
+ return 0;
+}
+static int outro(void) {
+ sd_netlink_unref(nfnl);
return 0;
}
+
+DEFINE_TEST_MAIN_FULL(LOG_DEBUG, intro, outro);
#include <unistd.h>
+#include "sd-netlink.h"
+
#include "firewall-util.h"
#include "in-addr-util.h"
#include "netlink-internal.h"
const char *table = argv[3], *set = argv[4];
- FirewallContext *ctx;
- r = fw_ctx_new(&ctx);
- assert_se(r == 0);
+ _cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
+ ASSERT_OK(sd_nfnl_socket_open(&nfnl));
bool add;
if (streq(argv[1], "add"))
r = safe_atou32(argv[6], &element);
assert_se(r == 0);
- r = nft_set_element_modify_any(ctx, add, nfproto, table, set, &element, sizeof(element));
+ r = nft_set_element_modify_any(nfnl, add, nfproto, table, set, &element, sizeof(element));
assert_se(r == 0);
} else if (streq(argv[5], "uint64")) {
uint64_t element;
r = safe_atou64(argv[6], &element);
assert_se(r == 0);
- r = nft_set_element_modify_any(ctx, add, nfproto, table, set, &element, sizeof(element));
+ r = nft_set_element_modify_any(nfnl, add, nfproto, table, set, &element, sizeof(element));
assert_se(r == 0);
} else if (streq(argv[5], "in_addr")) {
union in_addr_union addr;
r = in_addr_from_string_auto(argv[6], &af, &addr);
assert_se(r == 0);
- r = nft_set_element_modify_ip(ctx, add, nfproto, af, table, set, &addr);
+ r = nft_set_element_modify_ip(nfnl, add, nfproto, af, table, set, &addr);
assert_se(r == 0);
} else if (streq(argv[5], "network")) {
union in_addr_union addr;
r = in_addr_prefix_from_string_auto(argv[6], &af, &addr, &prefixlen);
assert_se(r == 0);
- r = nft_set_element_modify_iprange(ctx, add, nfproto, af, table, set, &addr, prefixlen);
+ r = nft_set_element_modify_iprange(nfnl, add, nfproto, af, table, set, &addr, prefixlen);
assert_se(r == 0);
}