firewall-util: remove iptables/libiptc backend support (#38976)
This removes iptables/libiptc backend support in firewall-util, as
already announced by 5c68c51045.
Then, this drops meaningless `FirewallContext` wrapper.
This commit is contained in:
@@ -1305,11 +1305,6 @@ endif
|
||||
conf.set10('HAVE_LIBIDN', not have and libidn.found())
|
||||
conf.set10('HAVE_LIBIDN2', have)
|
||||
|
||||
libiptc = dependency('libiptc',
|
||||
required : get_option('libiptc'))
|
||||
conf.set10('HAVE_LIBIPTC', libiptc.found())
|
||||
libiptc_cflags = libiptc.partial_dependency(includes: true, compile_args: true)
|
||||
|
||||
libqrencode = dependency('libqrencode',
|
||||
version : '>= 3',
|
||||
required : get_option('qrencode'))
|
||||
@@ -3052,7 +3047,6 @@ foreach tuple : [
|
||||
['libfido2'],
|
||||
['libidn'],
|
||||
['libidn2'],
|
||||
['libiptc'],
|
||||
['microhttpd'],
|
||||
['openssl'],
|
||||
['p11kit'],
|
||||
|
||||
+1
-1
@@ -432,7 +432,7 @@ option('libidn2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' :
|
||||
description : 'libidn2 support')
|
||||
option('libidn', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
description : 'libidn support')
|
||||
option('libiptc', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
option('libiptc', type : 'feature', deprecated : true,
|
||||
description : 'libiptc support')
|
||||
option('qrencode', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
description : 'libqrencode support')
|
||||
|
||||
@@ -126,12 +126,6 @@ const char* const systemd_features =
|
||||
" -IDN"
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBIPTC
|
||||
" +IPTC"
|
||||
#else
|
||||
" -IPTC"
|
||||
#endif
|
||||
|
||||
#if HAVE_KMOD
|
||||
" +KMOD"
|
||||
#else
|
||||
|
||||
@@ -284,7 +284,6 @@ typedef struct ConfigTableItem ConfigTableItem;
|
||||
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;
|
||||
|
||||
+4
-6
@@ -28,12 +28,12 @@
|
||||
#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"
|
||||
@@ -1335,12 +1335,10 @@ void unit_modify_nft_set(Unit *u, bool add) {
|
||||
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));
|
||||
@@ -1351,7 +1349,7 @@ void unit_modify_nft_set(Unit *u, bool add) {
|
||||
|
||||
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);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#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"
|
||||
|
||||
@@ -115,10 +115,6 @@ int kmod_setup(void) {
|
||||
/* This should never be a module */
|
||||
{ "unix", "/proc/net/unix", true, true, NULL },
|
||||
|
||||
#if HAVE_LIBIPTC
|
||||
/* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
|
||||
{ "ip_tables", "/proc/net/ip_tables_names", false, false, NULL },
|
||||
#endif
|
||||
/* virtio_rng would be loaded by udev later, but real entropy might be needed very early */
|
||||
{ "virtio_rng", NULL, false, false, has_virtio_rng },
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#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"
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-messages.h"
|
||||
#include "sd-netlink.h"
|
||||
#include "sd-path.h"
|
||||
|
||||
#include "all-units.h"
|
||||
@@ -1753,7 +1754,7 @@ Manager* manager_free(Manager *m) {
|
||||
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);
|
||||
|
||||
+1
-1
@@ -474,7 +474,7 @@ typedef struct Manager {
|
||||
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. */
|
||||
|
||||
+4
-5
@@ -44,6 +44,7 @@
|
||||
#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"
|
||||
@@ -5290,19 +5291,17 @@ static void unit_modify_user_nft_set(Unit *u, bool add, NFTSetSource source, uin
|
||||
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);
|
||||
|
||||
@@ -466,7 +466,8 @@ static int timeout_compare(const void *a, const void *b) {
|
||||
}
|
||||
|
||||
size_t netlink_get_reply_callback_count(sd_netlink *nl) {
|
||||
assert(nl);
|
||||
if (!nl)
|
||||
return 0;
|
||||
|
||||
return hashmap_size(nl->reply_callbacks);
|
||||
}
|
||||
|
||||
@@ -669,6 +669,10 @@ static int address_set_masquerade(Address *address, bool add) {
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
assert(address->link->manager);
|
||||
|
||||
if (!address->link->manager->nfnl)
|
||||
return 0;
|
||||
|
||||
if (!address->link->network)
|
||||
return 0;
|
||||
@@ -687,7 +691,7 @@ static int address_set_masquerade(Address *address, bool add) {
|
||||
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;
|
||||
|
||||
@@ -702,14 +706,9 @@ static void address_modify_nft_set_context(Address *address, bool add, NFTSetCon
|
||||
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;
|
||||
|
||||
@@ -717,16 +716,16 @@ static void address_modify_nft_set_context(Address *address, bool add, NFTSetCon
|
||||
|
||||
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:
|
||||
@@ -749,6 +748,10 @@ static void address_modify_nft_set_context(Address *address, bool add, NFTSetCon
|
||||
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;
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#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"
|
||||
@@ -285,6 +285,28 @@ static int manager_connect_genl(Manager *m) {
|
||||
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. */
|
||||
@@ -435,7 +457,7 @@ static int manager_post_handler(sd_event_source *s, void *userdata) {
|
||||
|
||||
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);
|
||||
@@ -557,6 +579,10 @@ int manager_setup(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_nfnl(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (m->test_mode)
|
||||
return 0;
|
||||
|
||||
@@ -696,6 +722,7 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
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);
|
||||
@@ -720,8 +747,6 @@ Manager* manager_free(Manager *m) {
|
||||
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);
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef struct Manager {
|
||||
sd_netlink *rtnl;
|
||||
/* lazy initialized */
|
||||
sd_netlink *genl;
|
||||
sd_netlink *nfnl;
|
||||
sd_event *event;
|
||||
sd_resolve *resolve;
|
||||
sd_bus *bus;
|
||||
@@ -103,8 +104,6 @@ typedef struct Manager {
|
||||
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;
|
||||
|
||||
@@ -293,7 +293,7 @@ int manager_process_requests(Manager *manager) {
|
||||
* 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(). */
|
||||
|
||||
@@ -76,12 +76,13 @@ void expose_port_free_all(ExposePort *p) {
|
||||
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))
|
||||
@@ -90,14 +91,15 @@ int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_
|
||||
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));
|
||||
}
|
||||
@@ -106,12 +108,15 @@ int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_
|
||||
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
|
||||
@@ -129,7 +134,7 @@ int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *
|
||||
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))
|
||||
@@ -138,14 +143,15 @@ int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "firewall-util.h"
|
||||
#include "forward.h"
|
||||
#include "list.h"
|
||||
|
||||
@@ -18,5 +17,5 @@ int expose_port_parse(ExposePort **l, const char *s);
|
||||
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);
|
||||
|
||||
+14
-13
@@ -71,6 +71,7 @@
|
||||
#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"
|
||||
@@ -2539,7 +2540,7 @@ static int setup_kmsg(int fd_inner_socket) {
|
||||
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) {
|
||||
@@ -2548,8 +2549,8 @@ static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *user
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5607,8 +5608,8 @@ static int run_container(
|
||||
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;
|
||||
@@ -5730,8 +5731,8 @@ static int run_container(
|
||||
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;
|
||||
@@ -5900,7 +5901,7 @@ static int run(int argc, char *argv[]) {
|
||||
_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();
|
||||
@@ -6385,12 +6386,12 @@ static int run(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
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 (;;) {
|
||||
@@ -6454,8 +6455,8 @@ finish:
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,383 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <endian.h>
|
||||
#include <libiptc/libiptc.h>
|
||||
#include <linux/netfilter/nf_nat.h>
|
||||
#include <linux/netfilter/xt_addrtype.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dlfcn-util.h"
|
||||
#include "firewall-util-private.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "log.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
static DLSYM_PROTOTYPE(iptc_check_entry) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_commit) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_delete_entry) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_free) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_init) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_insert_entry) = NULL;
|
||||
static DLSYM_PROTOTYPE(iptc_strerror) = NULL;
|
||||
|
||||
static void *iptc_dl = NULL;
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xtc_handle*, sym_iptc_free, NULL);
|
||||
|
||||
static int entry_fill_basics(
|
||||
struct ipt_entry *entry,
|
||||
int protocol,
|
||||
const char *in_interface,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const char *out_interface,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen) {
|
||||
|
||||
assert(entry);
|
||||
|
||||
if (out_interface && !ifname_valid(out_interface))
|
||||
return -EINVAL;
|
||||
if (in_interface && !ifname_valid(in_interface))
|
||||
return -EINVAL;
|
||||
|
||||
entry->ip.proto = protocol;
|
||||
|
||||
if (in_interface) {
|
||||
size_t l;
|
||||
|
||||
l = strlen(in_interface);
|
||||
assert(l < sizeof entry->ip.iniface);
|
||||
assert(l < sizeof entry->ip.iniface_mask);
|
||||
|
||||
strcpy(entry->ip.iniface, in_interface);
|
||||
memset(entry->ip.iniface_mask, 0xFF, l + 1);
|
||||
}
|
||||
if (source) {
|
||||
entry->ip.src = source->in;
|
||||
in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
|
||||
}
|
||||
|
||||
if (out_interface) {
|
||||
size_t l = strlen(out_interface);
|
||||
assert(l < sizeof entry->ip.outiface);
|
||||
assert(l < sizeof entry->ip.outiface_mask);
|
||||
|
||||
strcpy(entry->ip.outiface, out_interface);
|
||||
memset(entry->ip.outiface_mask, 0xFF, l + 1);
|
||||
}
|
||||
if (destination) {
|
||||
entry->ip.dst = destination->in;
|
||||
in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_iptables_add_masquerade(
|
||||
bool add,
|
||||
int af,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen) {
|
||||
|
||||
static const xt_chainlabel chain = "POSTROUTING";
|
||||
_cleanup_(sym_iptc_freep) struct xtc_handle *h = NULL;
|
||||
struct ipt_entry *entry, *mask;
|
||||
struct ipt_entry_target *t;
|
||||
size_t sz;
|
||||
struct nf_nat_ipv4_multi_range_compat *mr;
|
||||
int r, protocol = 0;
|
||||
const char *out_interface = NULL;
|
||||
const union in_addr_union *destination = NULL;
|
||||
unsigned destination_prefixlen = 0;
|
||||
|
||||
if (af != AF_INET)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!source || source_prefixlen == 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = fw_iptables_init_nat(&h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sz = XT_ALIGN(sizeof(struct ipt_entry)) +
|
||||
XT_ALIGN(sizeof(struct ipt_entry_target)) +
|
||||
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
|
||||
|
||||
/* Put together the entry we want to add or remove */
|
||||
entry = alloca0(sz);
|
||||
entry->next_offset = sz;
|
||||
entry->target_offset = XT_ALIGN(sizeof(struct ipt_entry));
|
||||
r = entry_fill_basics(entry, protocol, NULL, source, source_prefixlen, out_interface, destination, destination_prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Fill in target part */
|
||||
t = ipt_get_target(entry);
|
||||
t->u.target_size =
|
||||
XT_ALIGN(sizeof(struct ipt_entry_target)) +
|
||||
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
|
||||
strncpy(t->u.user.name, "MASQUERADE", sizeof(t->u.user.name));
|
||||
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
|
||||
mr->rangesize = 1;
|
||||
|
||||
/* Create a search mask entry */
|
||||
mask = alloca_safe(sz);
|
||||
memset(mask, 0xFF, sz);
|
||||
|
||||
if (add) {
|
||||
if (sym_iptc_check_entry(chain, entry, (unsigned char*) mask, h))
|
||||
return 0;
|
||||
if (errno != ENOENT) /* if other error than not existing yet, fail */
|
||||
return -errno;
|
||||
|
||||
if (!sym_iptc_insert_entry(chain, entry, 0, h))
|
||||
return -errno;
|
||||
} else {
|
||||
if (!sym_iptc_delete_entry(chain, entry, (unsigned char*) mask, h)) {
|
||||
if (errno == ENOENT) /* if it's already gone, all is good! */
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sym_iptc_commit(h))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_iptables_add_local_dnat(
|
||||
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) {
|
||||
|
||||
static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT";
|
||||
_cleanup_(sym_iptc_freep) struct xtc_handle *h = NULL;
|
||||
struct ipt_entry *entry, *mask;
|
||||
struct ipt_entry_target *t;
|
||||
struct ipt_entry_match *m;
|
||||
struct xt_addrtype_info_v1 *at;
|
||||
struct nf_nat_ipv4_multi_range_compat *mr;
|
||||
size_t sz, msz;
|
||||
int r;
|
||||
const char *in_interface = NULL;
|
||||
const union in_addr_union *source = NULL;
|
||||
unsigned source_prefixlen = 0;
|
||||
const union in_addr_union *destination = NULL;
|
||||
unsigned destination_prefixlen = 0;
|
||||
|
||||
assert(add || !previous_remote);
|
||||
|
||||
if (af != AF_INET)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (local_port <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (remote_port <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = fw_iptables_init_nat(&h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sz = XT_ALIGN(sizeof(struct ipt_entry)) +
|
||||
XT_ALIGN(sizeof(struct ipt_entry_match)) +
|
||||
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
|
||||
XT_ALIGN(sizeof(struct ipt_entry_target)) +
|
||||
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
|
||||
|
||||
if (protocol == IPPROTO_TCP)
|
||||
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
|
||||
XT_ALIGN(sizeof(struct xt_tcp));
|
||||
else
|
||||
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
|
||||
XT_ALIGN(sizeof(struct xt_udp));
|
||||
|
||||
sz += msz;
|
||||
|
||||
/* Fill in basic part */
|
||||
entry = alloca0(sz);
|
||||
entry->next_offset = sz;
|
||||
entry->target_offset =
|
||||
XT_ALIGN(sizeof(struct ipt_entry)) +
|
||||
XT_ALIGN(sizeof(struct ipt_entry_match)) +
|
||||
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
|
||||
msz;
|
||||
r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Fill in first match */
|
||||
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)));
|
||||
m->u.match_size = msz;
|
||||
if (protocol == IPPROTO_TCP) {
|
||||
struct xt_tcp *tcp;
|
||||
|
||||
strncpy(m->u.user.name, "tcp", sizeof(m->u.user.name));
|
||||
tcp = (struct xt_tcp*) m->data;
|
||||
tcp->dpts[0] = tcp->dpts[1] = local_port;
|
||||
tcp->spts[0] = 0;
|
||||
tcp->spts[1] = 0xFFFF;
|
||||
|
||||
} else {
|
||||
struct xt_udp *udp;
|
||||
|
||||
strncpy(m->u.user.name, "udp", sizeof(m->u.user.name));
|
||||
udp = (struct xt_udp*) m->data;
|
||||
udp->dpts[0] = udp->dpts[1] = local_port;
|
||||
udp->spts[0] = 0;
|
||||
udp->spts[1] = 0xFFFF;
|
||||
}
|
||||
|
||||
/* Fill in second match */
|
||||
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz);
|
||||
m->u.match_size =
|
||||
XT_ALIGN(sizeof(struct ipt_entry_match)) +
|
||||
XT_ALIGN(sizeof(struct xt_addrtype_info_v1));
|
||||
strncpy(m->u.user.name, "addrtype", sizeof(m->u.user.name));
|
||||
m->u.user.revision = 1;
|
||||
at = (struct xt_addrtype_info_v1*) m->data;
|
||||
at->dest = XT_ADDRTYPE_LOCAL;
|
||||
|
||||
/* Fill in target part */
|
||||
t = ipt_get_target(entry);
|
||||
t->u.target_size =
|
||||
XT_ALIGN(sizeof(struct ipt_entry_target)) +
|
||||
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
|
||||
strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name));
|
||||
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
|
||||
mr->rangesize = 1;
|
||||
mr->range[0].flags = NF_NAT_RANGE_PROTO_SPECIFIED|NF_NAT_RANGE_MAP_IPS;
|
||||
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
|
||||
if (protocol == IPPROTO_TCP)
|
||||
mr->range[0].min.tcp.port = mr->range[0].max.tcp.port = htobe16(remote_port);
|
||||
else
|
||||
mr->range[0].min.udp.port = mr->range[0].max.udp.port = htobe16(remote_port);
|
||||
|
||||
mask = alloca0(sz);
|
||||
memset(mask, 0xFF, sz);
|
||||
|
||||
if (add) {
|
||||
/* Add the PREROUTING rule, if it is missing so far */
|
||||
if (!sym_iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -EINVAL;
|
||||
|
||||
if (!sym_iptc_insert_entry(chain_pre, entry, 0, h))
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* If a previous remote is set, remove its entry */
|
||||
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
|
||||
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
|
||||
|
||||
if (!sym_iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
|
||||
}
|
||||
|
||||
/* Add the OUTPUT rule, if it is missing so far */
|
||||
if (!in_interface) {
|
||||
|
||||
/* Don't apply onto loopback addresses */
|
||||
if (!destination) {
|
||||
entry->ip.dst.s_addr = htobe32(0x7F000000);
|
||||
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
|
||||
entry->ip.invflags = IPT_INV_DSTIP;
|
||||
}
|
||||
|
||||
if (!sym_iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
if (!sym_iptc_insert_entry(chain_output, entry, 0, h))
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* If a previous remote is set, remove its entry */
|
||||
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
|
||||
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
|
||||
|
||||
if (!sym_iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!sym_iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!in_interface) {
|
||||
if (!destination) {
|
||||
entry->ip.dst.s_addr = htobe32(0x7F000000);
|
||||
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
|
||||
entry->ip.invflags = IPT_INV_DSTIP;
|
||||
}
|
||||
|
||||
if (!sym_iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sym_iptc_commit(h))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dlopen_iptc(void) {
|
||||
ELF_NOTE_DLOPEN("ip4tc",
|
||||
"Support for firewall rules with iptables backend",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libip4tc.so.2");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&iptc_dl,
|
||||
"libip4tc.so.2", LOG_DEBUG,
|
||||
DLSYM_ARG(iptc_check_entry),
|
||||
DLSYM_ARG(iptc_commit),
|
||||
DLSYM_ARG(iptc_delete_entry),
|
||||
DLSYM_ARG(iptc_free),
|
||||
DLSYM_ARG(iptc_init),
|
||||
DLSYM_ARG(iptc_insert_entry),
|
||||
DLSYM_ARG(iptc_strerror));
|
||||
}
|
||||
|
||||
int fw_iptables_init_nat(struct xtc_handle **ret) {
|
||||
_cleanup_(sym_iptc_freep) struct xtc_handle *h = NULL;
|
||||
int r;
|
||||
|
||||
r = dlopen_iptc();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h = sym_iptc_init("nat");
|
||||
if (!h)
|
||||
return log_debug_errno(errno, "Failed to init \"nat\" table: %s", sym_iptc_strerror(errno));
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "firewall-util.h"
|
||||
#include "forward.h"
|
||||
|
||||
typedef enum FirewallBackend {
|
||||
FW_BACKEND_NONE,
|
||||
#if HAVE_LIBIPTC
|
||||
FW_BACKEND_IPTABLES,
|
||||
#endif
|
||||
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);
|
||||
|
||||
#if HAVE_LIBIPTC
|
||||
struct xtc_handle;
|
||||
|
||||
int fw_iptables_add_masquerade(
|
||||
bool add,
|
||||
int af,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen);
|
||||
|
||||
int fw_iptables_add_local_dnat(
|
||||
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 fw_iptables_init_nat(struct xtc_handle **ret);
|
||||
#endif
|
||||
+1276
-93
File diff suppressed because it is too large
Load Diff
@@ -4,25 +4,15 @@
|
||||
#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,
|
||||
@@ -64,7 +54,7 @@ const char* nft_set_source_to_string(int i) _const_;
|
||||
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,
|
||||
@@ -74,7 +64,7 @@ int nft_set_element_modify_iprange(
|
||||
unsigned source_prefixlen);
|
||||
|
||||
int nft_set_element_modify_ip(
|
||||
FirewallContext *ctx,
|
||||
sd_netlink *nfnl,
|
||||
bool add,
|
||||
int nfproto,
|
||||
int af,
|
||||
@@ -83,7 +73,7 @@ int nft_set_element_modify_ip(
|
||||
const union in_addr_union *source);
|
||||
|
||||
int nft_set_element_modify_any(
|
||||
FirewallContext *ctx,
|
||||
sd_netlink *nfnl,
|
||||
bool add,
|
||||
int nfproto,
|
||||
const char *table,
|
||||
|
||||
@@ -76,7 +76,6 @@ shared_sources = files(
|
||||
'fdset.c',
|
||||
'fido2-util.c',
|
||||
'find-esp.c',
|
||||
'firewall-util-nft.c',
|
||||
'firewall-util.c',
|
||||
'fork-notify.c',
|
||||
'format-table.c',
|
||||
@@ -249,10 +248,6 @@ if conf.get('ENABLE_UTMP') == 1
|
||||
shared_sources += files('utmp-wtmp.c')
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_LIBIPTC') == 1
|
||||
shared_sources += files('firewall-util-iptables.c')
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_LIBBPF') == 1
|
||||
shared_sources += files('bpf-link.c')
|
||||
endif
|
||||
@@ -323,7 +318,6 @@ libshared_deps = [threads,
|
||||
libcrypt,
|
||||
libdl,
|
||||
libgcrypt_cflags,
|
||||
libiptc_cflags,
|
||||
libkmod_cflags,
|
||||
liblz4_cflags,
|
||||
libmount,
|
||||
|
||||
@@ -3,22 +3,24 @@
|
||||
#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.");
|
||||
@@ -29,22 +31,19 @@ static void test_v6(FirewallContext *ctx) {
|
||||
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));
|
||||
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");
|
||||
|
||||
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(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) {
|
||||
@@ -54,52 +53,31 @@ 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);
|
||||
ASSERT_NOT_NULL(nfnl);
|
||||
|
||||
log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend));
|
||||
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);
|
||||
|
||||
#if HAVE_LIBIPTC
|
||||
if (ctx->backend == FW_BACKEND_IPTABLES && fw_iptables_init_nat(NULL) < 0) {
|
||||
log_debug("iptables backend is used, but nat table is not enabled, skipping tests");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
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");
|
||||
|
||||
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" : "");
|
||||
|
||||
if (ignore)
|
||||
return false;
|
||||
}
|
||||
ASSERT_OK(r);
|
||||
|
||||
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));
|
||||
|
||||
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");
|
||||
@@ -107,21 +85,16 @@ int main(int argc, char *argv[]) {
|
||||
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");
|
||||
|
||||
if (test_v4(ctx) && ctx->backend == FW_BACKEND_NFTABLES)
|
||||
test_v6(ctx);
|
||||
|
||||
#if HAVE_LIBIPTC
|
||||
if (ctx->backend != FW_BACKEND_IPTABLES) {
|
||||
ctx->backend = FW_BACKEND_IPTABLES;
|
||||
test_v4(ctx);
|
||||
}
|
||||
#endif
|
||||
r = sd_nfnl_socket_open(&nfnl);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "Failed to initialize nftables");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outro(void) {
|
||||
sd_netlink_unref(nfnl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_FULL(LOG_DEBUG, intro, outro);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "firewall-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "netlink-internal.h"
|
||||
@@ -25,9 +27,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
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"))
|
||||
@@ -41,7 +42,7 @@ int main(int argc, char **argv) {
|
||||
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;
|
||||
@@ -49,7 +50,7 @@ int main(int argc, char **argv) {
|
||||
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;
|
||||
@@ -58,7 +59,7 @@ int main(int argc, char **argv) {
|
||||
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;
|
||||
@@ -68,7 +69,7 @@ int main(int argc, char **argv) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user