Commit 278668fa authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

New upstream version 1.8.0

parent 5beab31f
...@@ -124,6 +124,29 @@ brnflog_print(const void *ip, const struct xt_entry_target *target, ...@@ -124,6 +124,29 @@ brnflog_print(const void *ip, const struct xt_entry_target *target,
printf("--nflog-threshold %d ", info->threshold); printf("--nflog-threshold %d ", info->threshold);
} }
static int brnflog_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct ebt_nflog_info *info = (void *)params->target->data;
xt_xlate_add(xl, "log ");
if (info->prefix[0] != '\0') {
if (params->escape_quotes)
xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix);
else
xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
}
xt_xlate_add(xl, "group %u ", info->group);
if (info->len)
xt_xlate_add(xl, "snaplen %u ", info->len);
if (info->threshold != EBT_NFLOG_DEFAULT_THRESHOLD)
xt_xlate_add(xl, "queue-threshold %u ", info->threshold);
return 1;
}
static struct xtables_target brnflog_watcher = { static struct xtables_target brnflog_watcher = {
.name = "nflog", .name = "nflog",
.revision = 0, .revision = 0,
...@@ -135,6 +158,7 @@ static struct xtables_target brnflog_watcher = { ...@@ -135,6 +158,7 @@ static struct xtables_target brnflog_watcher = {
.help = brnflog_help, .help = brnflog_help,
.parse = brnflog_parse, .parse = brnflog_parse,
.print = brnflog_print, .print = brnflog_print,
.xlate = brnflog_xlate,
.extra_opts = brnflog_opts, .extra_opts = brnflog_opts,
}; };
......
ebtables-translate -A INPUT --nflog
nft add rule bridge filter INPUT log group 1 counter
ebtables-translate -A INPUT --nflog-group 42
nft add rule bridge filter INPUT log group 42 counter
ebtables-translate -A INPUT --nflog-range 42
nft add rule bridge filter INPUT log group 1 snaplen 42 counter
ebtables-translate -A INPUT --nflog-threshold 100 --nflog-prefix foo
nft add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter
/* ebt_pkttype
*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
*
* April, 2003
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/if_packet.h>
#include <linux/netfilter_bridge/ebt_pkttype.h>
static const char *classes[] = {
"host",
"broadcast",
"multicast",
"otherhost",
"outgoing",
"loopback",
"fastroute",
};
static const struct option brpkttype_opts[] =
{
{ "pkttype-type" , required_argument, 0, '1' },
{ 0 }
};
static void brpkttype_print_help(void)
{
printf(
"pkttype options:\n"
"--pkttype-type [!] type: class the packet belongs to\n"
"Possible values: broadcast, multicast, host, otherhost, or any other byte value (which would be pretty useless).\n");
}
static int brpkttype_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ebt_pkttype_info *ptinfo = (struct ebt_pkttype_info *)(*match)->data;
char *end;
long int i;
switch (c) {
case '1':
if (invert)
ptinfo->invert = 1;
i = strtol(optarg, &end, 16);
if (*end != '\0') {
for (i = 0; i < ARRAY_SIZE(classes); i++) {
if (!strcasecmp(optarg, classes[i]))
break;
}
if (i >= ARRAY_SIZE(classes))
xtables_error(PARAMETER_PROBLEM, "Could not parse class '%s'", optarg);
}
if (i < 0 || i > 255)
xtables_error(PARAMETER_PROBLEM, "Problem with specified pkttype class");
ptinfo->pkt_type = (uint8_t)i;
break;
default:
return 0;
}
return 1;
}
static void brpkttype_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
struct ebt_pkttype_info *pt = (struct ebt_pkttype_info *)match->data;
printf("--pkttype-type %s", pt->invert ? "! " : "");
if (pt->pkt_type < ARRAY_SIZE(classes))
printf("%s ", classes[pt->pkt_type]);
else
printf("%d ", pt->pkt_type);
}
static int brpkttype_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ebt_pkttype_info *info = (const void*)params->match->data;
xt_xlate_add(xl, "meta pkttype %s", info->invert ? "!= " : "");
if (info->pkt_type < 3)
xt_xlate_add(xl, "%s ", classes[info->pkt_type]);
else if (info->pkt_type == 3)
xt_xlate_add(xl, "other ");
else
xt_xlate_add(xl, "%d ", info->pkt_type);
return 1;
}
static struct xtables_match brpkttype_match = {
.name = "pkttype",
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
.help = brpkttype_print_help,
.parse = brpkttype_parse,
.print = brpkttype_print,
.xlate = brpkttype_xlate,
.extra_opts = brpkttype_opts,
};
void _init(void)
{
xtables_register_match(&brpkttype_match);
}
ebtables-translate -A INPUT --pkttype-type host
nft add rule bridge filter INPUT meta pkttype host counter
ebtables-translate -A INPUT ! --pkttype-type broadcast
nft add rule bridge filter INPUT meta pkttype != broadcast counter
ebtables-translate -A INPUT --pkttype-type ! multicast
nft add rule bridge filter INPUT meta pkttype != multicast counter
ebtables-translate -A INPUT --pkttype-type otherhost
nft add rule bridge filter INPUT meta pkttype other counter
ebtables-translate -A INPUT --pkttype-type outgoing
nft add rule bridge filter INPUT meta pkttype 4 counter
ebtables-translate -A INPUT --pkttype-type loopback
nft add rule bridge filter INPUT meta pkttype 5 counter
ebtables-translate -A INPUT --pkttype-type fastroute
nft add rule bridge filter INPUT meta pkttype 6 counter
/* ebt_redirect
*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
*
* April, 2002
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_redirect.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
#define REDIRECT_TARGET '1'
static const struct option brredir_opts[] =
{
{ "redirect-target", required_argument, 0, REDIRECT_TARGET },
{ 0 }
};
static void brredir_print_help(void)
{
printf(
"redirect option:\n"
" --redirect-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
}
static void brredir_init(struct xt_entry_target *target)
{
struct ebt_redirect_info *redirectinfo =
(struct ebt_redirect_info *)target->data;
redirectinfo->target = EBT_ACCEPT;
}
#define OPT_REDIRECT_TARGET 0x01
static int brredir_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct ebt_redirect_info *redirectinfo =
(struct ebt_redirect_info *)(*target)->data;
switch (c) {
case REDIRECT_TARGET:
EBT_CHECK_OPTION(flags, OPT_REDIRECT_TARGET);
if (ebt_fill_target(optarg, (unsigned int *)&redirectinfo->target))
xtables_error(PARAMETER_PROBLEM, "Illegal --redirect-target target");
break;
default:
return 0;
}
return 1;
}
static void brredir_print(const void *ip, const struct xt_entry_target *target, int numeric)
{
struct ebt_redirect_info *redirectinfo =
(struct ebt_redirect_info *)target->data;
if (redirectinfo->target == EBT_ACCEPT)
return;
printf(" --redirect-target %s", ebt_target_name(redirectinfo->target));
}
static const char* brredir_verdict(int verdict)
{
switch (verdict) {
case EBT_ACCEPT: return "accept";
case EBT_DROP: return "drop";
case EBT_CONTINUE: return "continue";
case EBT_RETURN: return "return";
}
return "";
}
static int brredir_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct ebt_redirect_info *red = (const void*)params->target->data;
xt_xlate_add(xl, "meta set pkttype host");
if (red->target != EBT_ACCEPT)
xt_xlate_add(xl, " %s ", brredir_verdict(red->target));
return 0;
}
static struct xtables_target brredirect_target = {
.name = "redirect",
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_redirect_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_redirect_info)),
.help = brredir_print_help,
.init = brredir_init,
.parse = brredir_parse,
.print = brredir_print,
.xlate = brredir_xlate,
.extra_opts = brredir_opts,
};
void _init(void)
{
xtables_register_target(&brredirect_target);
}
/* ebt_nat
*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
*
* June, 2002
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <netinet/ether.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
#define NAT_S '1'
#define NAT_S_TARGET '2'
#define NAT_S_ARP '3'
static const struct option brsnat_opts[] =
{
{ "to-source" , required_argument, 0, NAT_S },
{ "to-src" , required_argument, 0, NAT_S },
{ "snat-target" , required_argument, 0, NAT_S_TARGET },
{ "snat-arp" , no_argument, 0, NAT_S_ARP },
{ 0 }
};
static void brsnat_print_help(void)
{
printf(
"snat options:\n"
" --to-src address : MAC address to map source to\n"
" --snat-target target : ACCEPT, DROP, RETURN or CONTINUE\n"
" --snat-arp : also change src address in arp msg\n");
}
static void brsnat_init(struct xt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
natinfo->target = EBT_ACCEPT;
}
#define OPT_SNAT 0x01
#define OPT_SNAT_TARGET 0x02
#define OPT_SNAT_ARP 0x04
static int brsnat_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
struct ether_addr *addr;
switch (c) {
case NAT_S:
EBT_CHECK_OPTION(flags, OPT_SNAT);
if (!(addr = ether_aton(optarg)))
xtables_error(PARAMETER_PROBLEM, "Problem with specified --to-source mac");
memcpy(natinfo->mac, addr, ETH_ALEN);
break;
case NAT_S_TARGET:
{ unsigned int tmp;
EBT_CHECK_OPTION(flags, OPT_SNAT_TARGET);
if (ebt_fill_target(optarg, &tmp))
xtables_error(PARAMETER_PROBLEM, "Illegal --snat-target target");
natinfo->target = (natinfo->target & ~EBT_VERDICT_BITS) | (tmp & EBT_VERDICT_BITS);
}
break;
case NAT_S_ARP:
EBT_CHECK_OPTION(flags, OPT_SNAT_ARP);
natinfo->target ^= NAT_ARP_BIT;
break;
default:
return 0;
}
return 1;
}
static void brsnat_final_check(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
"You must specify proper arguments");
}
static void ebt_print_mac(const unsigned char *mac)
{
printf("%s", ether_ntoa((struct ether_addr *) mac));
}
static void brsnat_print(const void *ip, const struct xt_entry_target *target, int numeric)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
printf("--to-src ");
ebt_print_mac(natinfo->mac);
if (!(natinfo->target&NAT_ARP_BIT))
printf(" --snat-arp");
printf(" --snat-target %s", ebt_target_name((natinfo->target|~EBT_VERDICT_BITS)));
}
static const char* brsnat_verdict(int verdict)
{
switch (verdict) {
case EBT_ACCEPT: return "accept";
case EBT_DROP: return "drop";
case EBT_CONTINUE: return "continue";
case EBT_RETURN: return "return";
}
return "";
}
static int brsnat_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct ebt_nat_info *natinfo = (const void*)params->target->data;
xt_xlate_add(xl, "ether saddr set %s ",
ether_ntoa((struct ether_addr *)natinfo->mac));
/* NAT_ARP_BIT set -> no arp mangling, not set -> arp mangling (yes, its inverted) */
if (!(natinfo->target&NAT_ARP_BIT))
return 0;
xt_xlate_add(xl, "%s ", brsnat_verdict(natinfo->target | ~EBT_VERDICT_BITS));
return 1;
}
static struct xtables_target brsnat_target =
{
.name = "snat",
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_nat_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_nat_info)),
.help = brsnat_print_help,
.init = brsnat_init,
.parse = brsnat_parse,
.final_check = brsnat_final_check,
.print = brsnat_print,
.xlate = brsnat_xlate,
.extra_opts = brsnat_opts,
};
void _init(void)
{
xtables_register_target(&brsnat_target);
}
ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ --to-source de:ad:00:be:ee:ff
nft add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter
ebtables-translate -t nat -A POSTROUTING -o someport --to-src de:ad:00:be:ee:ff --snat-target CONTINUE
nft add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter
/* ebt_stp
*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
*
* July, 2003
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <netinet/ether.h>
#include <linux/netfilter_bridge/ebt_stp.h>
#include <xtables.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
#define STP_TYPE 'a'
#define STP_FLAGS 'b'
#define STP_ROOTPRIO 'c'
#define STP_ROOTADDR 'd'
#define STP_ROOTCOST 'e'
#define STP_SENDERPRIO 'f'
#define STP_SENDERADDR 'g'
#define STP_PORT 'h'
#define STP_MSGAGE 'i'
#define STP_MAXAGE 'j'
#define STP_HELLOTIME 'k'
#define STP_FWDD 'l'
#define STP_NUMOPS 12
static const struct option brstp_opts[] =
{
{ "stp-type" , required_argument, 0, STP_TYPE},
{ "stp-flags" , required_argument, 0, STP_FLAGS},
{ "stp-root-prio" , required_argument, 0, STP_ROOTPRIO},
{ "stp-root-addr" , required_argument, 0, STP_ROOTADDR},
{ "stp-root-cost" , required_argument, 0, STP_ROOTCOST},
{ "stp-sender-prio" , required_argument, 0, STP_SENDERPRIO},
{ "stp-sender-addr" , required_argument, 0, STP_SENDERADDR},
{ "stp-port" , required_argument, 0, STP_PORT},
{ "stp-msg-age" , required_argument, 0, STP_MSGAGE},
{ "stp-max-age" , required_argument, 0, STP_MAXAGE},
{ "stp-hello-time" , required_argument, 0, STP_HELLOTIME},
{ "stp-forward-delay", required_argument, 0, STP_FWDD},
{ 0 }
};
#define BPDU_TYPE_CONFIG 0
#define BPDU_TYPE_TCN 0x80
#define BPDU_TYPE_CONFIG_STRING "config"
#define BPDU_TYPE_TCN_STRING "tcn"
#define FLAG_TC 0x01
#define FLAG_TC_ACK 0x80
#define FLAG_TC_STRING "topology-change"
#define FLAG_TC_ACK_STRING "topology-change-ack"
static void brstp_print_help(void)
{
printf(
"stp options:\n"
"--stp-type type : BPDU type\n"
"--stp-flags flag : control flag\n"
"--stp-root-prio prio[:prio] : root priority (16-bit) range\n"
"--stp-root-addr address[/mask] : MAC address of root\n"
"--stp-root-cost cost[:cost] : root cost (32-bit) range\n"
"--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
"--stp-sender-addr address[/mask] : MAC address of sender\n"
"--stp-port port[:port] : port id (16-bit) range\n"
"--stp-msg-age age[:age] : message age timer (16-bit) range\n"
"--stp-max-age age[:age] : maximum age timer (16-bit) range\n"
"--stp-hello-time time[:time] : hello time timer (16-bit) range\n"
"--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
" Recognized BPDU type strings:\n"
" \"config\": configuration BPDU (=0)\n"
" \"tcn\" : topology change notification BPDU (=0x80)\n"
" Recognized control flag strings:\n"
" \"topology-change\" : topology change flag (0x01)\n"
" \"topology-change-ack\": topology change acknowledgement flag (0x80)");
}
static int parse_range(const char *portstring, void *lower, void *upper,
int bits, uint32_t min, uint32_t max)
{
char *buffer;
char *cp, *end;
uint32_t low_nr, upp_nr;
int ret = 0;
buffer = strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL) {
low_nr = strtoul(buffer, &end, 10);
if (*end || low_nr < min || low_nr > max) {
ret = -1;
goto out;
}
if (bits == 2) {
*(uint16_t *)lower = low_nr;
*(uint16_t *)upper = low_nr;
} else {
*(uint32_t *)lower = low_nr;
*(uint32_t *)upper = low_nr;
}
} else {
*cp = '\0';
cp++;
if (!*buffer)
low_nr = min;
else {
low_nr = strtoul(buffer, &end, 10);
if (*end || low_nr < min) {
ret = -1;
goto out;
}
}
if (!*cp)
upp_nr = max;
else {
upp_nr = strtoul(cp, &end, 10);
if (*end || upp_nr > max) {
ret = -1;
goto out;
}
}
if (upp_nr < low_nr) {
ret = -1;
goto out;
}
if (bits == 2) {
*(uint16_t *)lower = low_nr;
*(uint16_t *)upper = upp_nr;
} else {
*(uint32_t *)lower = low_nr;
*(uint32_t *)upper = upp_nr;
}
}
out:
free(buffer);
return ret;
}
static void print_range(unsigned int l, unsigned int u)
{
if (l == u)
printf("%u ", l);
else
printf("%u:%u ", l, u);
}
static int brstp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
{
char *p;
int i;
struct ether_addr *addr = NULL;
static const unsigned char mac_type_unicast[ETH_ALEN];
static const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
if (strcasecmp(from, "Unicast") == 0) {
memcpy(to, mac_type_unicast, ETH_ALEN);
memcpy(mask, msk_type_unicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Multicast") == 0) {
memcpy(to, mac_type_multicast, ETH_ALEN);
memcpy(mask, mac_type_multicast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "Broadcast") == 0) {
memcpy(to, mac_type_broadcast, ETH_ALEN);
memcpy(mask, mac_type_broadcast, ETH_ALEN);
return 0;
}
if (strcasecmp(from, "BGA") == 0) {
memcpy(to, mac_type_bridge_group, ETH_ALEN);
memcpy(mask, msk_type_bridge_group, ETH_ALEN);
return 0;
}
if ( (p = strrchr(from, '/')) != NULL) {
*p = '\0';
if (!(addr = ether_aton(p + 1)))
return -1;
memcpy(mask, addr, ETH_ALEN);
} else
memset(mask, 0xff, ETH_ALEN);
if (!(addr = ether_aton(from)))
return -1;
memcpy(to, addr, ETH_ALEN);
for (i = 0; i < ETH_ALEN; i++)
to[i] &= mask[i];
return 0;
}
static int
brstp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
unsigned int flag;
long int i;
char *end = NULL;
if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
return 0;
flag = 1 << (c - 'a');
EBT_CHECK_OPTION(flags, flag);
if (invert)
stpinfo->invflags |= flag;
stpinfo->bitmask |= flag;
switch (flag) {
case EBT_STP_TYPE:
i = strtol(optarg, &end, 0);
if (i < 0 || i > 255 || *end != '\0') {
if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
stpinfo->type = BPDU_TYPE_CONFIG;
else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
stpinfo->type = BPDU_TYPE_TCN;
else
xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument");
} else
stpinfo->type = i;
break;
case EBT_STP_FLAGS:
i = strtol(optarg, &end, 0);
if (i < 0 || i > 255 || *end != '\0') {
if (!strcasecmp(optarg, FLAG_TC_STRING))
stpinfo->config.flags = FLAG_TC;
else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
stpinfo->config.flags = FLAG_TC_ACK;
else
xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument");
} else
stpinfo->config.flags = i;
break;
case EBT_STP_ROOTPRIO:
if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
&(stpinfo->config.root_priou), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-prio range");
break;
case EBT_STP_ROOTCOST:
if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
&(stpinfo->config.root_costu), 4, 0, 0xffffffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-cost range");
break;
case EBT_STP_SENDERPRIO:
if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
&(stpinfo->config.sender_priou), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-prio range");
break;
case EBT_STP_PORT:
if (parse_range(argv[optind-1], &(stpinfo->config.portl),
&(stpinfo->config.portu), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-port-range");
break;
case EBT_STP_MSGAGE:
if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
&(stpinfo->config.msg_ageu), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-msg-age range");
break;
case EBT_STP_MAXAGE:
if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
&(stpinfo->config.max_ageu), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-max-age range");
break;
case EBT_STP_HELLOTIME:
if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
&(stpinfo->config.hello_timeu), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-hello-time range");
break;
case EBT_STP_FWDD:
if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
&(stpinfo->config.forward_delayu), 2, 0, 0xffff))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
break;
case EBT_STP_ROOTADDR:
if (brstp_get_mac_and_mask(argv[optind-1],
(unsigned char *)stpinfo->config.root_addr,
(unsigned char *)stpinfo->config.root_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
break;
case EBT_STP_SENDERADDR:
if (brstp_get_mac_and_mask(argv[optind-1],
(unsigned char *)stpinfo->config.sender_addr,
(unsigned char *)stpinfo->config.sender_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
break;
default:
xtables_error(PARAMETER_PROBLEM, "Unknown stp option");
}
return 1;
}
static void ebt_print_mac(const unsigned char *mac)
{
int j;
for (j = 0; j < ETH_ALEN; j++)
printf("%02x%s", mac[j],
(j==ETH_ALEN-1) ? "" : ":");
}
static bool mac_all_ones(const unsigned char *mac)
{
static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0;
}
static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
{
ebt_print_mac(mac);
if (!mac_all_ones(mask)) {
printf("/");
ebt_print_mac(mask);
}
}
static void brstp_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
const struct ebt_stp_config_info *c = &(stpinfo->config);
int i;
for (i = 0; i < STP_NUMOPS; i++) {
if (!(stpinfo->bitmask & (1 << i)))
continue;
printf("--%s %s", brstp_opts[i].name,
(stpinfo->invflags & (1 << i)) ? "! " : "");
if (EBT_STP_TYPE == (1 << i)) {
if (stpinfo->type == BPDU_TYPE_CONFIG)
printf("%s", BPDU_TYPE_CONFIG_STRING);
else if (stpinfo->type == BPDU_TYPE_TCN)
printf("%s", BPDU_TYPE_TCN_STRING);
else
printf("%d", stpinfo->type);
} else if (EBT_STP_FLAGS == (1 << i)) {
if (c->flags == FLAG_TC)
printf("%s", FLAG_TC_STRING);
else if (c->flags == FLAG_TC_ACK)
printf("%s", FLAG_TC_ACK_STRING);
else
printf("%d", c->flags);
} else if (EBT_STP_ROOTPRIO == (1 << i))
print_range(c->root_priol, c->root_priou);
else if (EBT_STP_ROOTADDR == (1 << i))
ebt_print_mac_and_mask((unsigned char *)c->root_addr,
(unsigned char*)c->root_addrmsk);
else if (EBT_STP_ROOTCOST == (1 << i))
print_range(c->root_costl, c->root_costu);
else if (EBT_STP_SENDERPRIO == (1 << i))
print_range(c->sender_priol, c->sender_priou);
else if (EBT_STP_SENDERADDR == (1 << i))
ebt_print_mac_and_mask((unsigned char *)c->sender_addr,
(unsigned char *)c->sender_addrmsk);
else if (EBT_STP_PORT == (1 << i))
print_range(c->portl, c->portu);
else if (EBT_STP_MSGAGE == (1 << i))
print_range(c->msg_agel, c->msg_ageu);
else if (EBT_STP_MAXAGE == (1 << i))
print_range(c->max_agel, c->max_ageu);
else if (EBT_STP_HELLOTIME == (1 << i))
print_range(c->hello_timel, c->hello_timeu);
else if (EBT_STP_FWDD == (1 << i))
print_range(c->forward_delayl, c->forward_delayu);
printf(" ");
}
}
static struct xtables_match brstp_match = {
.name = "stp",
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = sizeof(struct ebt_stp_info),
.help = brstp_print_help,
.parse = brstp_parse,
.print = brstp_print,
.extra_opts = brstp_opts,
};
void _init(void)
{
xtables_register_match(&brstp_match);
}
/* ebt_vlan
*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
* Nick Fedchik <nick@fedchik.org.ua>
* June, 2002
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
#include <ebtables/ethernetdb.h>
#include <linux/netfilter_bridge/ebt_vlan.h>
#include <linux/if_ether.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
#define NAME_VLAN_ID "id"
#define NAME_VLAN_PRIO "prio"
#define NAME_VLAN_ENCAP "encap"
#define VLAN_ID '1'
#define VLAN_PRIO '2'
#define VLAN_ENCAP '3'
static const struct option brvlan_opts[] = {
{"vlan-id" , required_argument, NULL, VLAN_ID},
{"vlan-prio" , required_argument, NULL, VLAN_PRIO},
{"vlan-encap", required_argument, NULL, VLAN_ENCAP},
XT_GETOPT_TABLEEND,
};
/*
* option inverse flags definition
*/
#define OPT_VLAN_ID 0x01
#define OPT_VLAN_PRIO 0x02
#define OPT_VLAN_ENCAP 0x04
#define OPT_VLAN_FLAGS (OPT_VLAN_ID | OPT_VLAN_PRIO | OPT_VLAN_ENCAP)
static void brvlan_print_help(void)
{
printf(
"vlan options:\n"
"--vlan-id [!] id : vlan-tagged frame identifier, 0,1-4096 (integer)\n"
"--vlan-prio [!] prio : Priority-tagged frame's user priority, 0-7 (integer)\n"
"--vlan-encap [!] encap : Encapsulated frame protocol (hexadecimal or name)\n");
}
static struct ethertypeent *vlan_getethertypeent(FILE *etherf, const char *name)
{
static struct ethertypeent et_ent;
char *e, *found_name;
char line[1024];
while ((e = fgets(line, sizeof(line), etherf))) {
char *endptr, *cp;
if (*e == '#')
continue;
cp = strpbrk(e, "#\n");
if (cp == NULL)
continue;
*cp = '\0';
found_name = e;
cp = strpbrk(e, " \t");
if (cp == NULL)
continue;
*cp++ = '\0';
while (*cp == ' ' || *cp == '\t')
cp++;
e = strpbrk(cp, " \t");
if (e != NULL)
*e++ = '\0';
et_ent.e_ethertype = strtol(cp, &endptr, 16);
if (*endptr != '\0' ||
(et_ent.e_ethertype < ETH_ZLEN || et_ent.e_ethertype > 0xFFFF))
continue; // skip invalid etherproto type entry
if (strcasecmp(found_name, name) == 0)
return (&et_ent);
if (e != NULL) {
cp = e;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
e = cp;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
if (strcasecmp(e, name) == 0)
return (&et_ent);
e = cp;
}
}
}
return NULL;
}
static struct ethertypeent *brvlan_getethertypebyname(const char *name)
{
struct ethertypeent *e;
FILE *etherf;
etherf = fopen(_PATH_ETHERTYPES, "r");
e = vlan_getethertypeent(etherf, name);
fclose(etherf);
return (e);
}
static int
brvlan_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data;
struct ethertypeent *ethent;
char *end;
struct ebt_vlan_info local;
switch (c) {
case VLAN_ID:
EBT_CHECK_OPTION(flags, OPT_VLAN_ID);
if (invert)
vlaninfo->invflags |= EBT_VLAN_ID;
local.id = strtoul(optarg, &end, 10);
if (local.id > 4094 || *end != '\0')
xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-id range ('%s')", optarg);
vlaninfo->id = local.id;
vlaninfo->bitmask |= EBT_VLAN_ID;
break;
case VLAN_PRIO:
EBT_CHECK_OPTION(flags, OPT_VLAN_PRIO);
if (invert)
vlaninfo->invflags |= EBT_VLAN_PRIO;
local.prio = strtoul(optarg, &end, 10);
if (local.prio >= 8 || *end != '\0')
xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-prio range ('%s')", optarg);
vlaninfo->prio = local.prio;
vlaninfo->bitmask |= EBT_VLAN_PRIO;
break;
case VLAN_ENCAP:
EBT_CHECK_OPTION(flags, OPT_VLAN_ENCAP);
if (invert)
vlaninfo->invflags |= EBT_VLAN_ENCAP;
local.encap = strtoul(optarg, &end, 16);
if (*end != '\0') {
ethent = brvlan_getethertypebyname(optarg);
if (ethent == NULL)
xtables_error(PARAMETER_PROBLEM, "Unknown --vlan-encap value ('%s')", optarg);
local.encap = ethent->e_ethertype;
}
if (local.encap < ETH_ZLEN)
xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-encap range ('%s')", optarg);
vlaninfo->encap = htons(local.encap);
vlaninfo->bitmask |= EBT_VLAN_ENCAP;
break;
default:
return 0;
}
return 1;
}
static void brvlan_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
if (vlaninfo->bitmask & EBT_VLAN_ID) {
printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id);
}
if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio);
}
if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "");
printf("%4.4X ", ntohs(vlaninfo->encap));
}
}
static int brvlan_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ebt_vlan_info *vlaninfo = (const void*)params->match->data;
if (vlaninfo->bitmask & EBT_VLAN_ID)
xt_xlate_add(xl, "vlan id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "!= " : "", vlaninfo->id);
if (vlaninfo->bitmask & EBT_VLAN_PRIO)
xt_xlate_add(xl, "vlan pcp %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "!= " : "", vlaninfo->prio);
if (vlaninfo->bitmask & EBT_VLAN_ENCAP)
xt_xlate_add(xl, "vlan type %s0x%4.4x ", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "!= " : "", ntohs(vlaninfo->encap));
return 1;
}
static struct xtables_match brvlan_match = {
.name = "vlan",
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_vlan_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_vlan_info)),
.help = brvlan_print_help,
.parse = brvlan_parse,
.print = brvlan_print,
.xlate = brvlan_xlate,
.extra_opts = brvlan_opts,
};
void _init(void)
{
xtables_register_match(&brvlan_match);
}
ebtables-translate -A INPUT -p 802_1Q --vlan-id 42
nft add rule bridge filter INPUT vlan id 42 counter
ebtables-translate -A INPUT -p 802_1Q --vlan-prio ! 1
nft add rule bridge filter INPUT vlan pcp != 1 counter
ebtables-translate -A INPUT -p 802_1Q --vlan-encap ip
nft add rule bridge filter INPUT vlan type 0x0800 counter
ebtables-translate -A INPUT -p 802_1Q --vlan-encap ipv6 ! --vlan-id 1
nft add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter
...@@ -34,6 +34,15 @@ static void DNAT_help(void) ...@@ -34,6 +34,15 @@ static void DNAT_help(void)
"[--random] [--persistent]\n"); "[--random] [--persistent]\n");
} }
static void DNAT_help_v2(void)
{
printf(
"DNAT target options:\n"
" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
" Address to map destination to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry DNAT_opts[] = { static const struct xt_option_entry DNAT_opts[] = {
{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI}, .flags = XTOPT_MAND | XTOPT_MULTI},
...@@ -44,7 +53,7 @@ static const struct xt_option_entry DNAT_opts[] = { ...@@ -44,7 +53,7 @@ static const struct xt_option_entry DNAT_opts[] = {
/* Ranges expected in network order. */ /* Ranges expected in network order. */
static void static void
parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev)
{ {
char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
const struct in6_addr *ip; const struct in6_addr *ip;
...@@ -109,6 +118,20 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) ...@@ -109,6 +118,20 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
"Port range `%s' funky\n", colon+1); "Port range `%s' funky\n", colon+1);
range->min_proto.tcp.port = htons(port); range->min_proto.tcp.port = htons(port);
range->max_proto.tcp.port = htons(maxport); range->max_proto.tcp.port = htons(maxport);
if (rev >= 2) {
char *slash = strchr(dash, '/');
if (slash) {
int baseport;
baseport = atoi(slash + 1);
if (baseport <= 0 || baseport > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", slash+1);
range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
range->base_proto.tcp.port = htons(baseport);
}
}
} }
/* Starts with colon or [] colon? No IP info...*/ /* Starts with colon or [] colon? No IP info...*/
if (colon == arg || colon == arg+2) { if (colon == arg || colon == arg+2) {
...@@ -144,10 +167,10 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) ...@@ -144,10 +167,10 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
return; return;
} }
static void DNAT_parse(struct xt_option_call *cb) static void _DNAT_parse(struct xt_option_call *cb,
struct nf_nat_range2 *range, int rev)
{ {
const struct ip6t_entry *entry = cb->xt_entry; const struct ip6t_entry *entry = cb->xt_entry;
struct nf_nat_range *range = cb->data;
int portok; int portok;
if (entry->ipv6.proto == IPPROTO_TCP || if (entry->ipv6.proto == IPPROTO_TCP ||
...@@ -166,7 +189,7 @@ static void DNAT_parse(struct xt_option_call *cb) ...@@ -166,7 +189,7 @@ static void DNAT_parse(struct xt_option_call *cb)
xtables_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"DNAT: Multiple --to-destination not supported"); "DNAT: Multiple --to-destination not supported");
} }
parse_to(cb->arg, portok, range); parse_to(cb->arg, portok, range, rev);
cb->xflags |= F_X_TO_DEST; cb->xflags |= F_X_TO_DEST;
break; break;
case O_PERSISTENT: case O_PERSISTENT:
...@@ -175,16 +198,40 @@ static void DNAT_parse(struct xt_option_call *cb) ...@@ -175,16 +198,40 @@ static void DNAT_parse(struct xt_option_call *cb)
} }
} }
static void DNAT_fcheck(struct xt_fcheck_call *cb) static void DNAT_parse(struct xt_option_call *cb)
{
struct nf_nat_range *range_v1 = (void *)cb->data;
struct nf_nat_range2 range = {};
memcpy(&range, range_v1, sizeof(*range_v1));
_DNAT_parse(cb, &range, 1);
memcpy(range_v1, &range, sizeof(*range_v1));
}
static void DNAT_parse_v2(struct xt_option_call *cb)
{
_DNAT_parse(cb, (struct nf_nat_range2 *)cb->data, 2);
}
static void _DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags)
{ {
static const unsigned int f = F_TO_DEST | F_RANDOM; static const unsigned int f = F_TO_DEST | F_RANDOM;
struct nf_nat_range *mr = cb->data;
if ((cb->xflags & f) == f) if ((cb->xflags & f) == f)
mr->flags |= NF_NAT_RANGE_PROTO_RANDOM; *flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void DNAT_fcheck(struct xt_fcheck_call *cb)
{
_DNAT_fcheck(cb, &((struct nf_nat_range *)cb->data)->flags);
} }
static void print_range(const struct nf_nat_range *range) static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
{
_DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags);
}
static void print_range(const struct nf_nat_range2 *range, int rev)
{ {
if (range->flags & NF_NAT_RANGE_MAP_IPS) { if (range->flags & NF_NAT_RANGE_MAP_IPS) {
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
...@@ -201,36 +248,63 @@ static void print_range(const struct nf_nat_range *range) ...@@ -201,36 +248,63 @@ static void print_range(const struct nf_nat_range *range)
printf("%hu", ntohs(range->min_proto.tcp.port)); printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port) if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port)); printf("-%hu", ntohs(range->max_proto.tcp.port));
if (rev >= 2 && (range->flags & NF_NAT_RANGE_PROTO_OFFSET))
printf("/%hu", ntohs(range->base_proto.tcp.port));
} }
} }
static void DNAT_print(const void *ip, const struct xt_entry_target *target, static void _DNAT_print(const struct nf_nat_range2 *range, int rev)
int numeric)
{ {
const struct nf_nat_range *range = (const void *)target->data;
printf(" to:"); printf(" to:");
print_range(range); print_range(range, rev);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random"); printf(" random");
if (range->flags & NF_NAT_RANGE_PERSISTENT) if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent"); printf(" persistent");
} }
static void DNAT_save(const void *ip, const struct xt_entry_target *target) static void DNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{ {
const struct nf_nat_range *range = (const void *)target->data; const struct nf_nat_range *range_v1 = (const void *)target->data;
struct nf_nat_range2 range = {};
memcpy(&range, range_v1, sizeof(*range_v1));
_DNAT_print(&range, 1);
}
static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
int numeric)
{
_DNAT_print((const struct nf_nat_range2 *)target->data, 2);
}
static void _DNAT_save(const struct nf_nat_range2 *range, int rev)
{
printf(" --to-destination "); printf(" --to-destination ");
print_range(range); print_range(range, rev);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random"); printf(" --random");
if (range->flags & NF_NAT_RANGE_PERSISTENT) if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent"); printf(" --persistent");
} }
static void print_range_xlate(const struct nf_nat_range *range, static void DNAT_save(const void *ip, const struct xt_entry_target *target)
struct xt_xlate *xl) {
const struct nf_nat_range *range_v1 = (const void *)target->data;
struct nf_nat_range2 range = {};
memcpy(&range, range_v1, sizeof(*range_v1));
_DNAT_save(&range, 1);
}
static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
{
_DNAT_save((const struct nf_nat_range2 *)target->data, 2);
}
static void print_range_xlate(const struct nf_nat_range2 *range,
struct xt_xlate *xl, int rev)
{ {
bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED; bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
...@@ -257,15 +331,14 @@ static void print_range_xlate(const struct nf_nat_range *range, ...@@ -257,15 +331,14 @@ static void print_range_xlate(const struct nf_nat_range *range,
} }
} }
static int DNAT_xlate(struct xt_xlate *xl, static int _DNAT_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params) const struct nf_nat_range2 *range, int rev)
{ {
const struct nf_nat_range *range = (const void *)params->target->data;
bool sep_need = false; bool sep_need = false;
const char *sep = " "; const char *sep = " ";
xt_xlate_add(xl, "dnat to "); xt_xlate_add(xl, "dnat to ");
print_range_xlate(range, xl); print_range_xlate(range, xl, rev);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
xt_xlate_add(xl, " random"); xt_xlate_add(xl, " random");
sep_need = true; sep_need = true;
...@@ -279,23 +352,60 @@ static int DNAT_xlate(struct xt_xlate *xl, ...@@ -279,23 +352,60 @@ static int DNAT_xlate(struct xt_xlate *xl,
return 1; return 1;
} }
static struct xtables_target dnat_tg_reg = { static int DNAT_xlate(struct xt_xlate *xl,
.name = "DNAT", const struct xt_xlate_tg_params *params)
.version = XTABLES_VERSION, {
.family = NFPROTO_IPV6, const struct nf_nat_range *range_v1 = (const void *)params->target->data;
.revision = 1, struct nf_nat_range2 range = {};
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), memcpy(&range, range_v1, sizeof(*range_v1));
.help = DNAT_help, _DNAT_xlate(xl, &range, 1);
.x6_parse = DNAT_parse,
.x6_fcheck = DNAT_fcheck, return 1;
.print = DNAT_print, }
.save = DNAT_save,
.x6_options = DNAT_opts, static int DNAT_xlate_v2(struct xt_xlate *xl,
.xlate = DNAT_xlate, const struct xt_xlate_tg_params *params)
{
_DNAT_xlate(xl, (const struct nf_nat_range2 *)params->target->data, 2);
return 1;
}
static struct xtables_target dnat_tg_reg[] = {
{
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.revision = 1,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = DNAT_help,
.print = DNAT_print,
.save = DNAT_save,
.x6_parse = DNAT_parse,
.x6_fcheck = DNAT_fcheck,
.x6_options = DNAT_opts,
.xlate = DNAT_xlate,
},
{
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.revision = 2,
.size = XT_ALIGN(sizeof(struct nf_nat_range2)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
.help = DNAT_help_v2,
.print = DNAT_print_v2,
.save = DNAT_save_v2,
.x6_parse = DNAT_parse_v2,
.x6_fcheck = DNAT_fcheck_v2,
.x6_options = DNAT_opts,
.xlate = DNAT_xlate_v2,
},
}; };
void _init(void) void _init(void)
{ {
xtables_register_target(&dnat_tg_reg); xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
} }
ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80
nft add rule ip6 nat prerouting iifname eth1 tcp dport 8080 counter dnat to [fec0::1234]:80 nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80
ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20
nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20
......
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80 ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80
nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:80 nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20 ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20
nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:1-20 nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random
nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:123 random nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent
nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent
...@@ -6,17 +6,13 @@ ...@@ -6,17 +6,13 @@
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
#include "libxt_icmp.h"
enum { enum {
O_ICMPV6_TYPE = 0, O_ICMPV6_TYPE = 0,
}; };
struct icmpv6_names { static const struct xt_icmp_names icmpv6_codes[] = {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
};
static const struct icmpv6_names icmpv6_codes[] = {
{ "destination-unreachable", 1, 0, 0xFF }, { "destination-unreachable", 1, 0, 0xFF },
{ "no-route", 1, 0, 0 }, { "no-route", 1, 0, 0 },
{ "communication-prohibited", 1, 1, 1 }, { "communication-prohibited", 1, 1, 1 },
...@@ -58,34 +54,14 @@ static const struct icmpv6_names icmpv6_codes[] = { ...@@ -58,34 +54,14 @@ static const struct icmpv6_names icmpv6_codes[] = {
}; };
static void
print_icmpv6types(void)
{
unsigned int i;
printf("Valid ICMPv6 Types:");
for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) {
if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
&& (icmpv6_codes[i].code_max
== icmpv6_codes[i-1].code_max))
printf(" (%s)", icmpv6_codes[i].name);
else
printf("\n %s", icmpv6_codes[i].name);
}
else
printf("\n%s", icmpv6_codes[i].name);
}
printf("\n");
}
static void icmp6_help(void) static void icmp6_help(void)
{ {
printf( printf(
"icmpv6 match options:\n" "icmpv6 match options:\n"
"[!] --icmpv6-type typename match icmpv6 type\n" "[!] --icmpv6-type typename match icmpv6 type\n"
" (or numeric type or type/code)\n"); " (or numeric type or type/code)\n");
print_icmpv6types(); printf("Valid ICMPv6 Types:");
xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
} }
static const struct xt_option_entry icmp6_opts[] = { static const struct xt_option_entry icmp6_opts[] = {
......
...@@ -22,6 +22,9 @@ enum { ...@@ -22,6 +22,9 @@ enum {
O_SRH_LAST_GT, O_SRH_LAST_GT,
O_SRH_LAST_LT, O_SRH_LAST_LT,
O_SRH_TAG, O_SRH_TAG,
O_SRH_PSID,
O_SRH_NSID,
O_SRH_LSID,
}; };
static void srh_help(void) static void srh_help(void)
...@@ -38,7 +41,10 @@ static void srh_help(void) ...@@ -38,7 +41,10 @@ static void srh_help(void)
"[!] --srh-last-entry-eq last_entry Last Entry value of SRH\n" "[!] --srh-last-entry-eq last_entry Last Entry value of SRH\n"
"[!] --srh-last-entry-gt last_entry Last Entry value of SRH\n" "[!] --srh-last-entry-gt last_entry Last Entry value of SRH\n"
"[!] --srh-last-entry-lt last_entry Last Entry value of SRH\n" "[!] --srh-last-entry-lt last_entry Last Entry value of SRH\n"
"[!] --srh-tag tag Tag value of SRH\n"); "[!] --srh-tag tag Tag value of SRH\n"
"[!] --srh-psid addr[/mask] SRH previous SID\n"
"[!] --srh-nsid addr[/mask] SRH next SID\n"
"[!] --srh-lsid addr[/mask] SRH Last SID\n");
} }
#define s struct ip6t_srh #define s struct ip6t_srh
...@@ -69,6 +75,40 @@ static const struct xt_option_entry srh_opts[] = { ...@@ -69,6 +75,40 @@ static const struct xt_option_entry srh_opts[] = {
}; };
#undef s #undef s
#define s struct ip6t_srh1
static const struct xt_option_entry srh1_opts[] = {
{ .name = "srh-next-hdr", .id = O_SRH_NEXTHDR, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, next_hdr)},
{ .name = "srh-hdr-len-eq", .id = O_SRH_LEN_EQ, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
{ .name = "srh-hdr-len-gt", .id = O_SRH_LEN_GT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
{ .name = "srh-hdr-len-lt", .id = O_SRH_LEN_LT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)},
{ .name = "srh-segs-left-eq", .id = O_SRH_SEGS_EQ, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
{ .name = "srh-segs-left-gt", .id = O_SRH_SEGS_GT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
{ .name = "srh-segs-left-lt", .id = O_SRH_SEGS_LT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)},
{ .name = "srh-last-entry-eq", .id = O_SRH_LAST_EQ, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
{ .name = "srh-last-entry-gt", .id = O_SRH_LAST_GT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
{ .name = "srh-last-entry-lt", .id = O_SRH_LAST_LT, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)},
{ .name = "srh-tag", .id = O_SRH_TAG, .type = XTTYPE_UINT16,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, tag)},
{ .name = "srh-psid", .id = O_SRH_PSID, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_INVERT},
{ .name = "srh-nsid", .id = O_SRH_NSID, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_INVERT},
{ .name = "srh-lsid", .id = O_SRH_LSID, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_INVERT},
{ }
};
#undef s
static void srh_init(struct xt_entry_match *m) static void srh_init(struct xt_entry_match *m)
{ {
struct ip6t_srh *srhinfo = (void *)m->data; struct ip6t_srh *srhinfo = (void *)m->data;
...@@ -77,6 +117,20 @@ static void srh_init(struct xt_entry_match *m) ...@@ -77,6 +117,20 @@ static void srh_init(struct xt_entry_match *m)
srhinfo->mt_invflags = 0; srhinfo->mt_invflags = 0;
} }
static void srh1_init(struct xt_entry_match *m)
{
struct ip6t_srh1 *srhinfo = (void *)m->data;
srhinfo->mt_flags = 0;
srhinfo->mt_invflags = 0;
memset(srhinfo->psid_addr.s6_addr, 0, sizeof(srhinfo->psid_addr.s6_addr));
memset(srhinfo->nsid_addr.s6_addr, 0, sizeof(srhinfo->nsid_addr.s6_addr));
memset(srhinfo->lsid_addr.s6_addr, 0, sizeof(srhinfo->lsid_addr.s6_addr));
memset(srhinfo->psid_msk.s6_addr, 0, sizeof(srhinfo->psid_msk.s6_addr));
memset(srhinfo->nsid_msk.s6_addr, 0, sizeof(srhinfo->nsid_msk.s6_addr));
memset(srhinfo->lsid_msk.s6_addr, 0, sizeof(srhinfo->lsid_msk.s6_addr));
}
static void srh_parse(struct xt_option_call *cb) static void srh_parse(struct xt_option_call *cb)
{ {
struct ip6t_srh *srhinfo = cb->data; struct ip6t_srh *srhinfo = cb->data;
...@@ -141,6 +195,91 @@ static void srh_parse(struct xt_option_call *cb) ...@@ -141,6 +195,91 @@ static void srh_parse(struct xt_option_call *cb)
} }
} }
static void srh1_parse(struct xt_option_call *cb)
{
struct ip6t_srh1 *srhinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SRH_NEXTHDR:
srhinfo->mt_flags |= IP6T_SRH_NEXTHDR;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_NEXTHDR;
break;
case O_SRH_LEN_EQ:
srhinfo->mt_flags |= IP6T_SRH_LEN_EQ;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_EQ;
break;
case O_SRH_LEN_GT:
srhinfo->mt_flags |= IP6T_SRH_LEN_GT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_GT;
break;
case O_SRH_LEN_LT:
srhinfo->mt_flags |= IP6T_SRH_LEN_LT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_LT;
break;
case O_SRH_SEGS_EQ:
srhinfo->mt_flags |= IP6T_SRH_SEGS_EQ;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_EQ;
break;
case O_SRH_SEGS_GT:
srhinfo->mt_flags |= IP6T_SRH_SEGS_GT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_GT;
break;
case O_SRH_SEGS_LT:
srhinfo->mt_flags |= IP6T_SRH_SEGS_LT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_LT;
break;
case O_SRH_LAST_EQ:
srhinfo->mt_flags |= IP6T_SRH_LAST_EQ;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_EQ;
break;
case O_SRH_LAST_GT:
srhinfo->mt_flags |= IP6T_SRH_LAST_GT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_GT;
break;
case O_SRH_LAST_LT:
srhinfo->mt_flags |= IP6T_SRH_LAST_LT;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_LT;
break;
case O_SRH_TAG:
srhinfo->mt_flags |= IP6T_SRH_TAG;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_TAG;
break;
case O_SRH_PSID:
srhinfo->mt_flags |= IP6T_SRH_PSID;
srhinfo->psid_addr = cb->val.haddr.in6;
srhinfo->psid_msk = cb->val.hmask.in6;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_PSID;
break;
case O_SRH_NSID:
srhinfo->mt_flags |= IP6T_SRH_NSID;
srhinfo->nsid_addr = cb->val.haddr.in6;
srhinfo->nsid_msk = cb->val.hmask.in6;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_NSID;
break;
case O_SRH_LSID:
srhinfo->mt_flags |= IP6T_SRH_LSID;
srhinfo->lsid_addr = cb->val.haddr.in6;
srhinfo->lsid_msk = cb->val.hmask.in6;
if (cb->invert)
srhinfo->mt_invflags |= IP6T_SRH_INV_LSID;
break;
}
}
static void srh_print(const void *ip, const struct xt_entry_match *match, static void srh_print(const void *ip, const struct xt_entry_match *match,
int numeric) int numeric)
{ {
...@@ -182,6 +321,58 @@ static void srh_print(const void *ip, const struct xt_entry_match *match, ...@@ -182,6 +321,58 @@ static void srh_print(const void *ip, const struct xt_entry_match *match,
srhinfo->tag); srhinfo->tag);
} }
static void srh1_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct ip6t_srh1 *srhinfo = (struct ip6t_srh1 *)match->data;
printf(" srh");
if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
printf(" next-hdr:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR ? "!" : "",
srhinfo->next_hdr);
if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
printf(" hdr-len-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ ? "!" : "",
srhinfo->hdr_len);
if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
printf(" hdr-len-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT ? "!" : "",
srhinfo->hdr_len);
if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
printf(" hdr-len-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT ? "!" : "",
srhinfo->hdr_len);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
printf(" segs-left-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ ? "!" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
printf(" segs-left-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT ? "!" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
printf(" segs-left-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT ? "!" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
printf(" last-entry-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ ? "!" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
printf(" last-entry-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT ? "!" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
printf(" last-entry-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT ? "!" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_TAG)
printf(" tag:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_TAG ? "!" : "",
srhinfo->tag);
if (srhinfo->mt_flags & IP6T_SRH_PSID)
printf(" psid %s %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_PSID ? "!" : "",
xtables_ip6addr_to_numeric(&srhinfo->psid_addr),
xtables_ip6mask_to_cidr(&srhinfo->psid_msk));
if (srhinfo->mt_flags & IP6T_SRH_NSID)
printf(" nsid %s %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_NSID ? "!" : "",
xtables_ip6addr_to_numeric(&srhinfo->nsid_addr),
xtables_ip6mask_to_cidr(&srhinfo->nsid_msk));
if (srhinfo->mt_flags & IP6T_SRH_LSID)
printf(" lsid %s %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_LSID ? "!" : "",
xtables_ip6addr_to_numeric(&srhinfo->lsid_addr),
xtables_ip6mask_to_cidr(&srhinfo->lsid_msk));
}
static void srh_save(const void *ip, const struct xt_entry_match *match) static void srh_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data; const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data;
...@@ -221,22 +412,90 @@ static void srh_save(const void *ip, const struct xt_entry_match *match) ...@@ -221,22 +412,90 @@ static void srh_save(const void *ip, const struct xt_entry_match *match)
srhinfo->tag); srhinfo->tag);
} }
static struct xtables_match srh_mt6_reg = { static void srh1_save(const void *ip, const struct xt_entry_match *match)
.name = "srh", {
.version = XTABLES_VERSION, const struct ip6t_srh1 *srhinfo = (struct ip6t_srh1 *)match->data;
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_srh)), if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
.userspacesize = XT_ALIGN(sizeof(struct ip6t_srh)), printf("%s --srh-next-hdr %u", (srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR) ? " !" : "",
.help = srh_help, srhinfo->next_hdr);
.init = srh_init, if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
.print = srh_print, printf("%s --srh-hdr-len-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ) ? " !" : "",
.save = srh_save, srhinfo->hdr_len);
.x6_parse = srh_parse, if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
.x6_options = srh_opts, printf("%s --srh-hdr-len-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT) ? " !" : "",
srhinfo->hdr_len);
if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
printf("%s --srh-hdr-len-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT) ? " !" : "",
srhinfo->hdr_len);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
printf("%s --srh-segs-left-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ) ? " !" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
printf("%s --srh-segs-left-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT) ? " !" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
printf("%s --srh-segs-left-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT) ? " !" : "",
srhinfo->segs_left);
if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
printf("%s --srh-last-entry-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ) ? " !" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
printf("%s --srh-last-entry-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT) ? " !" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
printf("%s --srh-last-entry-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT) ? " !" : "",
srhinfo->last_entry);
if (srhinfo->mt_flags & IP6T_SRH_TAG)
printf("%s --srh-tag %u", (srhinfo->mt_invflags & IP6T_SRH_INV_TAG) ? " !" : "",
srhinfo->tag);
if (srhinfo->mt_flags & IP6T_SRH_PSID)
printf("%s --srh-psid %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_PSID ? " !" : "",
xtables_ip6addr_to_numeric(&srhinfo->psid_addr),
xtables_ip6mask_to_cidr(&srhinfo->psid_msk));
if (srhinfo->mt_flags & IP6T_SRH_NSID)
printf("%s --srh-nsid %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_NSID ? " !" : "",
xtables_ip6addr_to_numeric(&srhinfo->nsid_addr),
xtables_ip6mask_to_cidr(&srhinfo->nsid_msk));
if (srhinfo->mt_flags & IP6T_SRH_LSID)
printf("%s --srh-lsid %s/%u", srhinfo->mt_invflags & IP6T_SRH_INV_LSID ? " !" : "",
xtables_ip6addr_to_numeric(&srhinfo->lsid_addr),
xtables_ip6mask_to_cidr(&srhinfo->lsid_msk));
}
static struct xtables_match srh_mt6_reg[] = {
{
.name = "srh",
.version = XTABLES_VERSION,
.revision = 0,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_srh)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_srh)),
.help = srh_help,
.init = srh_init,
.print = srh_print,
.save = srh_save,
.x6_parse = srh_parse,
.x6_options = srh_opts,
},
{
.name = "srh",
.version = XTABLES_VERSION,
.revision = 1,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_srh1)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_srh1)),
.help = srh_help,
.init = srh1_init,
.print = srh1_print,
.save = srh1_save,
.x6_parse = srh1_parse,
.x6_options = srh1_opts,
}
}; };
void void
_init(void) _init(void)
{ {
xtables_register_match(&srh_mt6_reg); xtables_register_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
} }
...@@ -35,6 +35,15 @@ static void DNAT_help(void) ...@@ -35,6 +35,15 @@ static void DNAT_help(void)
"[--random] [--persistent]\n"); "[--random] [--persistent]\n");
} }
static void DNAT_help_v2(void)
{
printf(
"DNAT target options:\n"
" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
" Address to map destination to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry DNAT_opts[] = { static const struct xt_option_entry DNAT_opts[] = {
{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI}, .flags = XTOPT_MAND | XTOPT_MULTI},
...@@ -287,22 +296,260 @@ static int DNAT_xlate(struct xt_xlate *xl, ...@@ -287,22 +296,260 @@ static int DNAT_xlate(struct xt_xlate *xl,
return 1; return 1;
} }
static struct xtables_target dnat_tg_reg = { static void
.name = "DNAT", parse_to_v2(const char *orig_arg, int portok, struct nf_nat_range2 *range)
.version = XTABLES_VERSION, {
.family = NFPROTO_IPV4, char *arg, *colon, *dash, *error;
.size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), const struct in_addr *ip;
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
.help = DNAT_help, arg = strdup(orig_arg);
.x6_parse = DNAT_parse, if (arg == NULL)
.x6_fcheck = DNAT_fcheck, xtables_error(RESOURCE_PROBLEM, "strdup");
.print = DNAT_print,
.save = DNAT_save, colon = strchr(arg, ':');
.x6_options = DNAT_opts, if (colon) {
.xlate = DNAT_xlate, int port;
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon+1);
if (port <= 0 || port > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", colon+1);
error = strchr(colon+1, ':');
if (error)
xtables_error(PARAMETER_PROBLEM,
"Invalid port:port syntax - use dash\n");
dash = strchr(colon, '-');
if (!dash) {
range->min_proto.tcp.port
= range->max_proto.tcp.port
= htons(port);
} else {
int maxport;
char *slash;
maxport = atoi(dash + 1);
if (maxport <= 0 || maxport > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", dash+1);
if (maxport < port)
/* People are stupid. */
xtables_error(PARAMETER_PROBLEM,
"Port range `%s' funky\n", colon+1);
range->min_proto.tcp.port = htons(port);
range->max_proto.tcp.port = htons(maxport);
slash = strchr(dash, '/');
if (slash) {
int baseport;
baseport = atoi(slash + 1);
if (baseport <= 0 || baseport > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", slash+1);
range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
range->base_proto.tcp.port = htons(baseport);
}
}
/* Starts with a colon? No IP info...*/
if (colon == arg) {
free(arg);
return;
}
*colon = '\0';
}
range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(arg, '-');
if (colon && dash && dash > colon)
dash = NULL;
if (dash)
*dash = '\0';
ip = xtables_numeric_to_ipaddr(arg);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
arg);
range->min_addr.in = *ip;
if (dash) {
ip = xtables_numeric_to_ipaddr(dash+1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
range->max_addr.in = *ip;
} else
range->max_addr = range->min_addr;
free(arg);
return;
}
static void DNAT_parse_v2(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct nf_nat_range2 *range = cb->data;
int portok;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_DEST:
if (cb->xflags & F_X_TO_DEST) {
xtables_error(PARAMETER_PROBLEM,
"DNAT: Multiple --to-destination not supported");
}
parse_to_v2(cb->arg, portok, range);
cb->xflags |= F_X_TO_DEST;
break;
case O_PERSISTENT:
range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_DEST | F_RANDOM;
struct nf_nat_range2 *range = cb->data;
if ((cb->xflags & f) == f)
range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void print_range_v2(const struct nf_nat_range2 *range)
{
if (range->flags & NF_NAT_RANGE_MAP_IPS) {
printf("%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
if (memcmp(&range->min_addr, &range->max_addr,
sizeof(range->min_addr)))
printf("-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
}
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(":");
printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port));
if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
printf("/%hu", ntohs(range->base_proto.tcp.port));
}
}
static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range2 *range = (const void *)target->data;
printf(" to:");
print_range_v2(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_range2 *range = (const void *)target->data;
printf(" --to-destination ");
print_range_v2(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
static void print_range_xlate_v2(const struct nf_nat_range2 *range,
struct xt_xlate *xl)
{
if (range->flags & NF_NAT_RANGE_MAP_IPS) {
xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
if (memcmp(&range->min_addr, &range->max_addr,
sizeof(range->min_addr))) {
xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
}
}
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
xt_xlate_add(xl, "-%hu", ntohs(range->max_proto.tcp.port));
if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
xt_xlate_add(xl, ";%hu", ntohs(range->base_proto.tcp.port));
}
}
static int DNAT_xlate_v2(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct nf_nat_range2 *range = (const void *)params->target->data;
bool sep_need = false;
const char *sep = " ";
xt_xlate_add(xl, "dnat to ");
print_range_xlate_v2(range, xl);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
xt_xlate_add(xl, " random");
sep_need = true;
}
if (range->flags & NF_NAT_RANGE_PERSISTENT) {
if (sep_need)
sep = ",";
xt_xlate_add(xl, "%spersistent", sep);
}
return 1;
}
static struct xtables_target dnat_tg_reg[] = {
{
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.revision = 0,
.size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
.help = DNAT_help,
.print = DNAT_print,
.save = DNAT_save,
.x6_parse = DNAT_parse,
.x6_fcheck = DNAT_fcheck,
.x6_options = DNAT_opts,
.xlate = DNAT_xlate,
},
{
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.revision = 2,
.size = XT_ALIGN(sizeof(struct nf_nat_range2)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
.help = DNAT_help_v2,
.print = DNAT_print_v2,
.save = DNAT_save_v2,
.x6_parse = DNAT_parse_v2,
.x6_fcheck = DNAT_fcheck_v2,
.x6_options = DNAT_opts,
.xlate = DNAT_xlate_v2,
},
}; };
void _init(void) void _init(void)
{ {
xtables_register_target(&dnat_tg_reg); xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
} }
iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4
nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4
iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10
iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023
nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4:1-1023 nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023
iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random
nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 random nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random
iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent
nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 random,persistent nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4
nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6 iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4-1.2.3.6 nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6
iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023 iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
nft add rule ip nat postrouting oifname eth0 ip protocol tcp counter snat to 1.2.3.4:1-1023 nft add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random
nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 random nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent
nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 random,persistent nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <limits.h> /* INT_MAX in ip6_tables.h */ #include <limits.h> /* INT_MAX in ip6_tables.h */
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include "libxt_icmp.h"
/* special hack for icmp-type 'any': /* special hack for icmp-type 'any':
* Up to kernel <=2.4.20 the problem was: * Up to kernel <=2.4.20 the problem was:
* '-p icmp ' matches all icmp packets * '-p icmp ' matches all icmp packets
...@@ -17,13 +19,7 @@ enum { ...@@ -17,13 +19,7 @@ enum {
O_ICMP_TYPE = 0, O_ICMP_TYPE = 0,
}; };
struct icmp_names { static const struct xt_icmp_names icmp_codes[] = {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
};
static const struct icmp_names icmp_codes[] = {
{ "any", 0xFF, 0, 0xFF }, { "any", 0xFF, 0, 0xFF },
{ "echo-reply", 0, 0, 0xFF }, { "echo-reply", 0, 0, 0xFF },
/* Alias */ { "pong", 0, 0, 0xFF }, /* Alias */ { "pong", 0, 0, 0xFF },
...@@ -78,34 +74,14 @@ static const struct icmp_names icmp_codes[] = { ...@@ -78,34 +74,14 @@ static const struct icmp_names icmp_codes[] = {
{ "address-mask-reply", 18, 0, 0xFF } { "address-mask-reply", 18, 0, 0xFF }
}; };
static void
print_icmptypes(void)
{
unsigned int i;
printf("Valid ICMP Types:");
for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i) {
if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
&& (icmp_codes[i].code_max
== icmp_codes[i-1].code_max))
printf(" (%s)", icmp_codes[i].name);
else
printf("\n %s", icmp_codes[i].name);
}
else
printf("\n%s", icmp_codes[i].name);
}
printf("\n");
}
static void icmp_help(void) static void icmp_help(void)
{ {
printf( printf(
"icmp match options:\n" "icmp match options:\n"
"[!] --icmp-type typename match icmp type\n" "[!] --icmp-type typename match icmp type\n"
"[!] --icmp-type type[/code] (or numeric type or type/code)\n"); "[!] --icmp-type type[/code] (or numeric type or type/code)\n");
print_icmptypes(); printf("Valid ICMP Types:");
xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
} }
static const struct xt_option_entry icmp_opts[] = { static const struct xt_option_entry icmp_opts[] = {
......
...@@ -28,61 +28,23 @@ static const struct xt_option_entry realm_opts[] = { ...@@ -28,61 +28,23 @@ static const struct xt_option_entry realm_opts[] = {
XTOPT_TABLEEND, XTOPT_TABLEEND,
}; };
/* array of realms from /etc/iproute2/rt_realms */ static const char f_realms[] = "/etc/iproute2/rt_realms";
/* array of realms from f_realms[] */
static struct xtables_lmap *realms; static struct xtables_lmap *realms;
static void realm_init(struct xt_entry_match *m)
{
const char file[] = "/etc/iproute2/rt_realms";
realms = xtables_lmap_init(file);
if (realms == NULL && errno != ENOENT)
fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
}
static void realm_parse(struct xt_option_call *cb) static void realm_parse(struct xt_option_call *cb)
{ {
struct xt_realm_info *realminfo = cb->data; struct xt_realm_info *ri = cb->data;
int id; unsigned int id, mask;
char *end;
xtables_option_parse(cb); xtables_option_parse(cb);
realminfo->id = strtoul(cb->arg, &end, 0); xtables_parse_val_mask(cb, &id, &mask, realms);
if (end != cb->arg && (*end == '/' || *end == '\0')) {
if (*end == '/')
realminfo->mask = strtoul(end+1, &end, 0);
else
realminfo->mask = 0xffffffff;
if (*end != '\0' || end == cb->arg)
xtables_error(PARAMETER_PROBLEM,
"Bad realm value \"%s\"", cb->arg);
} else {
id = xtables_lmap_name2id(realms, cb->arg);
if (id == -1)
xtables_error(PARAMETER_PROBLEM,
"Realm \"%s\" not found", cb->arg);
realminfo->id = id;
realminfo->mask = 0xffffffff;
}
if (cb->invert)
realminfo->invert = 1;
}
static void ri->id = id;
print_realm(unsigned long id, unsigned long mask, int numeric) ri->mask = mask;
{
const char *name = NULL;
if (mask != 0xffffffff) if (cb->invert)
printf(" 0x%lx/0x%lx", id, mask); ri->invert = 1;
else {
if (numeric == 0)
name = xtables_lmap_id2name(realms, id);
if (name)
printf(" %s", name);
else
printf(" 0x%lx", id);
}
} }
static void realm_print(const void *ip, const struct xt_entry_match *match, static void realm_print(const void *ip, const struct xt_entry_match *match,
...@@ -94,7 +56,7 @@ static void realm_print(const void *ip, const struct xt_entry_match *match, ...@@ -94,7 +56,7 @@ static void realm_print(const void *ip, const struct xt_entry_match *match,
printf(" !"); printf(" !");
printf(" realm"); printf(" realm");
print_realm(ri->id, ri->mask, numeric); xtables_print_val_mask(ri->id, ri->mask, numeric ? NULL : realms);
} }
static void realm_save(const void *ip, const struct xt_entry_match *match) static void realm_save(const void *ip, const struct xt_entry_match *match)
...@@ -105,7 +67,7 @@ static void realm_save(const void *ip, const struct xt_entry_match *match) ...@@ -105,7 +67,7 @@ static void realm_save(const void *ip, const struct xt_entry_match *match)
printf(" !"); printf(" !");
printf(" --realm"); printf(" --realm");
print_realm(ri->id, ri->mask, 0); xtables_print_val_mask(ri->id, ri->mask, realms);
} }
static void static void
...@@ -151,7 +113,6 @@ static struct xtables_match realm_mt_reg = { ...@@ -151,7 +113,6 @@ static struct xtables_match realm_mt_reg = {
.size = XT_ALIGN(sizeof(struct xt_realm_info)), .size = XT_ALIGN(sizeof(struct xt_realm_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_realm_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_realm_info)),
.help = realm_help, .help = realm_help,
.init = realm_init,
.print = realm_print, .print = realm_print,
.save = realm_save, .save = realm_save,
.x6_parse = realm_parse, .x6_parse = realm_parse,
...@@ -161,5 +122,10 @@ static struct xtables_match realm_mt_reg = { ...@@ -161,5 +122,10 @@ static struct xtables_match realm_mt_reg = {
void _init(void) void _init(void)
{ {
realms = xtables_lmap_init(f_realms);
if (realms == NULL && errno != ENOENT)
fprintf(stderr, "Warning: %s: %s\n", f_realms,
strerror(errno));
xtables_register_match(&realm_mt_reg); xtables_register_match(&realm_mt_reg);
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment