shared: add minimal firewall manipulation helpers for establishing NAT rules, using libiptc
This commit is contained in:
parent
6cb7fa17b3
commit
76917807eb
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -182,6 +182,7 @@
|
|||
/test-fdset
|
||||
/test-fileio
|
||||
/test-fstab-util
|
||||
/test-fw-util
|
||||
/test-hashmap
|
||||
/test-hostname
|
||||
/test-icmp6-rs
|
||||
|
|
33
Makefile.am
33
Makefile.am
|
@ -982,6 +982,24 @@ libsystemd_label_la_LIBADD = \
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if HAVE_LIBIPTC
|
||||
noinst_LTLIBRARIES += \
|
||||
libsystemd-fw.la
|
||||
|
||||
libsystemd_fw_la_SOURCES = \
|
||||
src/shared/fw-util.h \
|
||||
src/shared/fw-util.c
|
||||
|
||||
libsystemd_fw_la_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(LIBIPTC_CFLAGS)
|
||||
|
||||
libsystemd_fw_la_LIBADD = \
|
||||
$(LIBIPTC_LIBS)
|
||||
endif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if ENABLE_LDCONFIG
|
||||
dist_systemunit_DATA += \
|
||||
units/ldconfig.service
|
||||
|
@ -1334,7 +1352,8 @@ manual_tests += \
|
|||
test-watchdog \
|
||||
test-log \
|
||||
test-ipcrm \
|
||||
test-btrfs
|
||||
test-btrfs \
|
||||
test-fw-util
|
||||
|
||||
if HAVE_KMOD
|
||||
manual_tests += \
|
||||
|
@ -1815,6 +1834,18 @@ test_btrfs_LDADD = \
|
|||
libsystemd-label.la \
|
||||
libsystemd-shared.la
|
||||
|
||||
test_fw_util_SOURCES = \
|
||||
src/test/test-fw-util.c
|
||||
|
||||
test_fw_util_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(LIBIPTC_CFLAGS)
|
||||
|
||||
test_fw_util_LDADD = \
|
||||
libsystemd-fw.la \
|
||||
libsystemd-shared.la \
|
||||
$(LIBIPTC_LIBS)
|
||||
|
||||
test_rtnl_manual_SOURCES = \
|
||||
src/test/test-rtnl-manual.c
|
||||
|
||||
|
|
16
configure.ac
16
configure.ac
|
@ -869,6 +869,21 @@ if test "x$enable_libidn" != "xno"; then
|
|||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBIDN, [test "$have_libidn" = "yes"])
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
have_libiptc=no
|
||||
AC_ARG_ENABLE(libiptc, AS_HELP_STRING([--disable-libiptc], [Disable optional LIBIPTC support]))
|
||||
if test "x$enable_libiptc" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBIPTC, [libiptc],
|
||||
[AC_DEFINE(HAVE_LIBIPTC, 1, [Define if libiptc is available])
|
||||
have_libiptc=yes
|
||||
M4_DEFINES="$M4_DEFINES -DHAVE_LIBIPTC"],
|
||||
[have_libiptc=no])
|
||||
if test "x$have_libiptc" = "xno" -a "x$enable_libiptc" = "xyes"; then
|
||||
AC_MSG_ERROR([*** libiptc support requested but libraries not found])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBIPTC, [test "$have_libiptc" = "yes"])
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
have_binfmt=no
|
||||
AC_ARG_ENABLE(binfmt, AS_HELP_STRING([--disable-binfmt], [disable binfmt tool]))
|
||||
|
@ -1405,6 +1420,7 @@ AC_MSG_RESULT([
|
|||
GNUTLS: ${have_gnutls}
|
||||
libcurl: ${have_libcurl}
|
||||
libidn: ${have_libidn}
|
||||
libiptc: ${have_libiptc}
|
||||
ELFUTILS: ${have_elfutils}
|
||||
binfmt: ${have_binfmt}
|
||||
vconsole: ${have_vconsole}
|
||||
|
|
344
src/shared/fw-util.c
Normal file
344
src/shared/fw-util.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2015 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/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 "util.h"
|
||||
#include "fw-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 && strlen(out_interface) >= IFNAMSIZ)
|
||||
return -EINVAL;
|
||||
|
||||
if (in_interface && strlen(in_interface) >= IFNAMSIZ)
|
||||
return -EINVAL;
|
||||
|
||||
entry->ip.proto = protocol;
|
||||
|
||||
if (in_interface) {
|
||||
strcpy(entry->ip.iniface, in_interface);
|
||||
memset(entry->ip.iniface_mask, 0xFF, strlen(in_interface)+1);
|
||||
}
|
||||
if (source) {
|
||||
entry->ip.src = source->in;
|
||||
in_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
|
||||
}
|
||||
|
||||
if (out_interface) {
|
||||
strcpy(entry->ip.outiface, out_interface);
|
||||
memset(entry->ip.outiface_mask, 0xFF, strlen(out_interface)+1);
|
||||
}
|
||||
if (destination) {
|
||||
entry->ip.dst = destination->in;
|
||||
in_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_add_masquerade(
|
||||
bool add,
|
||||
int af,
|
||||
int protocol,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const char *out_interface,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen) {
|
||||
|
||||
_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;
|
||||
|
||||
if (af != AF_INET)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (protocol != 0 && protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
|
||||
return -ENOTSUP;
|
||||
|
||||
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("POSTROUTING", entry, (unsigned char*) mask, h))
|
||||
return 0;
|
||||
if (errno != ENOENT) /* if other error than not existing yet, fail */
|
||||
return -errno;
|
||||
|
||||
if (!iptc_insert_entry("POSTROUTING", entry, 0, h))
|
||||
return -errno;
|
||||
} else {
|
||||
if (!iptc_delete_entry("POSTROUTING", 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_add_local_dnat(
|
||||
bool add,
|
||||
int af,
|
||||
int protocol,
|
||||
const char *in_interface,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen,
|
||||
uint16_t local_port,
|
||||
const union in_addr_union *remote,
|
||||
uint16_t remote_port,
|
||||
const union in_addr_union *previous_remote) {
|
||||
|
||||
|
||||
_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;
|
||||
|
||||
assert(add || !previous_remote);
|
||||
|
||||
if (af != AF_INET)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
|
||||
return -ENOTSUP;
|
||||
|
||||
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 = htons(remote_port);
|
||||
else
|
||||
mr->range[0].min.udp.port = mr->range[0].max.udp.port = htons(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("PREROUTING", entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -EINVAL;
|
||||
|
||||
if (!iptc_insert_entry("PREROUTING", 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("PREROUTING", 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("OUTPUT", entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
if (!iptc_insert_entry("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("OUTPUT", entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!iptc_delete_entry("PREROUTING", 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("OUTPUT", entry, (unsigned char*) mask, h)) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!iptc_commit(h))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
82
src/shared/fw-util.h
Normal file
82
src/shared/fw-util.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2015 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
#ifdef HAVE_LIBIPTC
|
||||
|
||||
int fw_add_masquerade(
|
||||
bool add,
|
||||
int af,
|
||||
int protocol,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const char *out_interface,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen);
|
||||
|
||||
int fw_add_local_dnat(
|
||||
bool add,
|
||||
int af,
|
||||
int protocol,
|
||||
const char *in_interface,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen,
|
||||
uint16_t local_port,
|
||||
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,
|
||||
int protocol,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const char *out_interface,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static inline int fw_add_local_dnat(
|
||||
bool add,
|
||||
int af,
|
||||
int protocol,
|
||||
const char *in_interface,
|
||||
const union in_addr_union *source,
|
||||
unsigned source_prefixlen,
|
||||
const union in_addr_union *destination,
|
||||
unsigned destination_prefixlen,
|
||||
uint16_t local_port,
|
||||
const union in_addr_union *remote,
|
||||
uint16_t remote_port,
|
||||
const union in_addr_union *previous_remote) {
|
||||
return -ENOSTUP;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -243,12 +243,25 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
return 32 - u32ctz(be32toh(addr->s_addr));
|
||||
}
|
||||
|
||||
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
|
||||
assert(addr);
|
||||
assert(prefixlen <= 32);
|
||||
|
||||
/* Shifting beyond 32 is not defined, handle this specially. */
|
||||
if (prefixlen == 0)
|
||||
addr->s_addr = 0;
|
||||
else
|
||||
addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
|
||||
uint8_t msb_octet = *(uint8_t*) addr;
|
||||
|
||||
|
@ -284,9 +297,6 @@ int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(prefixlen > 0 && prefixlen < 32);
|
||||
|
||||
mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
|
||||
|
||||
in_addr_prefixlen_to_netmask(mask, prefixlen);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
|
|||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
|
||||
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||
int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
||||
|
||||
|
|
60
src/test/test-fw-util.c
Normal file
60
src/test/test-fw-util.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2015 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "log.h"
|
||||
#include "fw-util.h"
|
||||
|
||||
#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
|
||||
r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_masquerade(false, AF_INET, 0, NULL, 0, "foobar", NULL, 0);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, &MAKE_IN_ADDR_UNION(1, 2, 3, 4));
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
r = fw_add_local_dnat(false, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, NULL);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to modify firewall: %m");
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue