1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

firewall-util: prepare for alternative to iptables backend

In a nutshell:
1. git mv firewall-util.c firewall-util-iptables.c
2. existing external functions gain _iptables_ in their names
3. firewall-util.c provides old function names
4. build system always compiles firewall-util.c,
   firewall-util-iptables.c is conditional instead (libiptc).
5. On first call to any of the 'old' API functions performs
   a probe that should return the preferred backend.

In a future step, can add firewall-util-FOOTYPE.c, add its
probe function to firewall-util.c and then have calls to
fw_add_masq/local_dnat handed to the detected backend.

For now, only iptables backend exists, and no special probing
takes place for it, i.e. when systemd was built with iptables,
that will be used.  If not, requets to add masquerade/dnat will
fail with same error (-EOPNOTSUPP) as before this change.

For reference, the rules added by the libiptc/iptables backend look like this:

for service export (via systemd-nspawn):
[0:0] -A PREROUTING -p tcp -m tcp --dport $exportedport -m addrtype --dst-type LOCAL -j DNAT --to-destination $containerip:$port
[0:0] -A OUTPUT ! -d 127.0.0.0/8 -p tcp -m tcp --dport $exportedport -m addrtype --dst-type LOCAL -j DNAT --to-destination $containerip:$port

for ip masquerade:
[0:0] -A POSTROUTING -s network/prefix -j MASQUERADE
This commit is contained in:
Florian Westphal 2020-06-25 15:00:54 +02:00
parent 47ed20e1e0
commit 3122097217
5 changed files with 410 additions and 336 deletions

View File

@ -0,0 +1,350 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/* Temporary work-around for broken glibc vs. linux kernel header definitions
* This is already fixed upstream, remove this when distributions have updated.
*/
#define _NET_IF_H 1
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <net/if.h>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
#include <libiptc/libiptc.h>
#include "alloc-util.h"
#include "firewall-util.h"
#include "firewall-util-private.h"
#include "in-addr-util.h"
#include "macro.h"
#include "socket-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
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_(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;
h = iptc_init("nat");
if (!h)
return -errno;
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(sz);
memset(mask, 0xFF, sz);
if (add) {
if (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 (!iptc_insert_entry(chain, entry, 0, h))
return -errno;
} else {
if (!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 (!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_(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;
h = iptc_init("nat");
if (!h)
return -errno;
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 (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -EINVAL;
if (!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 (!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 (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
if (!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 (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
} else {
if (!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 (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
if (!iptc_commit(h))
return -errno;
return 0;
}

View File

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "in-addr-util.h"
#if HAVE_LIBIPTC
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);
#endif

View File

@ -1,81 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* Temporary work-around for broken glibc vs. linux kernel header definitions
* This is already fixed upstream, remove this when distributions have updated.
*/
#define _NET_IF_H 1
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <net/if.h>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
#include <libiptc/libiptc.h>
#include "alloc-util.h"
#include "firewall-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "socket-util.h"
#include "firewall-util-private.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
enum FirewallBackend {
FW_BACKEND_NONE,
#if HAVE_LIBIPTC
FW_BACKEND_IPTABLES,
#endif
};
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) {
static enum FirewallBackend FirewallBackend;
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;
static enum FirewallBackend firewall_backend_probe(void) {
#if HAVE_LIBIPTC
return FW_BACKEND_IPTABLES;
#else
return FW_BACKEND_NONE;
#endif
}
int fw_add_masquerade(
@ -84,73 +31,19 @@ int fw_add_masquerade(
const union in_addr_union *source,
unsigned source_prefixlen) {
static const xt_chainlabel chain = "POSTROUTING";
_cleanup_(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 (FirewallBackend == FW_BACKEND_NONE)
FirewallBackend = firewall_backend_probe();
if (af != AF_INET)
switch (FirewallBackend) {
case FW_BACKEND_NONE:
return -EOPNOTSUPP;
if (!source || source_prefixlen == 0)
return -EINVAL;
h = iptc_init("nat");
if (!h)
return -errno;
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(sz);
memset(mask, 0xFF, sz);
if (add) {
if (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 (!iptc_insert_entry(chain, entry, 0, h))
return -errno;
} else {
if (!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 HAVE_LIBIPTC
case FW_BACKEND_IPTABLES:
return fw_iptables_add_masquerade(add, af, source, source_prefixlen);
#endif
}
if (!iptc_commit(h))
return -errno;
return 0;
return -EOPNOTSUPP;
}
int fw_add_local_dnat(
@ -162,188 +55,17 @@ int fw_add_local_dnat(
uint16_t remote_port,
const union in_addr_union *previous_remote) {
static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT";
_cleanup_(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;
if (FirewallBackend == FW_BACKEND_NONE)
FirewallBackend = firewall_backend_probe();
assert(add || !previous_remote);
if (af != AF_INET)
switch (FirewallBackend) {
case FW_BACKEND_NONE:
return -EOPNOTSUPP;
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
return -EOPNOTSUPP;
if (local_port <= 0)
return -EINVAL;
if (remote_port <= 0)
return -EINVAL;
h = iptc_init("nat");
if (!h)
return -errno;
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;
#if HAVE_LIBIPTC
case FW_BACKEND_IPTABLES:
return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote);
#endif
}
/* 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 (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -EINVAL;
if (!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 (!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 (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
if (!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 (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
} else {
if (!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 (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
if (!iptc_commit(h))
return -errno;
return 0;
return -EOPNOTSUPP;
}

View File

@ -6,8 +6,6 @@
#include "in-addr-util.h"
#if HAVE_LIBIPTC
int fw_add_masquerade(
bool add,
int af,
@ -22,26 +20,3 @@ int fw_add_local_dnat(
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote);
#else
static inline int fw_add_masquerade(
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen) {
return -EOPNOTSUPP;
}
static inline int fw_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) {
return -EOPNOTSUPP;
}
#endif

View File

@ -101,7 +101,9 @@ shared_sources = files('''
fdset.h
fileio-label.c
fileio-label.h
firewall-util.c
firewall-util.h
firewall-util-private.h
format-table.c
format-table.h
fsck-util.h
@ -293,7 +295,7 @@ if conf.get('HAVE_SECCOMP') == 1
endif
if conf.get('HAVE_LIBIPTC') == 1
shared_sources += files('firewall-util.c')
shared_sources += files('firewall-util-iptables.c')
endif
if conf.get('HAVE_KMOD') == 1