Commit 7e95a8db authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

Imported Upstream version 1.4.21

parents
This module matches the parameters in Destination Options header
.TP
[\fB!\fP] \fB\-\-dst\-len\fP \fIlength\fP
Total length of this header in octets.
.TP
\fB\-\-dst\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
numeric type of option and the length of the option data in octets.
/* Shared library add-on to ip6tables to add EUI64 address checking support. */
#include <xtables.h>
static struct xtables_match eui64_mt6_reg = {
.name = "eui64",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(int)),
.userspacesize = XT_ALIGN(sizeof(int)),
};
void _init(void)
{
xtables_register_match(&eui64_mt6_reg);
}
This module matches the EUI-64 part of a stateless autoconfigured IPv6 address.
It compares the EUI-64 derived from the source MAC address in Ethernet frame
with the lower 64 bits of the IPv6 source address. But "Universal/Local"
bit is not compared. This module doesn't match other link layer frame, and
is only valid in the
.BR PREROUTING ,
.BR INPUT
and
.BR FORWARD
chains.
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_frag.h>
enum {
O_FRAGID = 0,
O_FRAGLEN,
O_FRAGRES,
O_FRAGFIRST,
O_FRAGMORE,
O_FRAGLAST,
F_FRAGMORE = 1 << O_FRAGMORE,
F_FRAGLAST = 1 << O_FRAGLAST,
};
static void frag_help(void)
{
printf(
"frag match options:\n"
"[!] --fragid id[:id] match the id (range)\n"
"[!] --fraglen length total length of this header\n"
" --fragres check the reserved field too\n"
" --fragfirst matches on the first fragment\n"
" [--fragmore|--fraglast] there are more fragments or this\n"
" is the last one\n");
}
#define s struct ip6t_frag
static const struct xt_option_entry frag_opts[] = {
{.name = "fragid", .id = O_FRAGID, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, ids)},
{.name = "fraglen", .id = O_FRAGLEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
{.name = "fragres", .id = O_FRAGRES, .type = XTTYPE_NONE},
{.name = "fragfirst", .id = O_FRAGFIRST, .type = XTTYPE_NONE},
{.name = "fragmore", .id = O_FRAGMORE, .type = XTTYPE_NONE,
.excl = F_FRAGLAST},
{.name = "fraglast", .id = O_FRAGLAST, .type = XTTYPE_NONE,
.excl = F_FRAGMORE},
XTOPT_TABLEEND,
};
#undef s
static void frag_init(struct xt_entry_match *m)
{
struct ip6t_frag *fraginfo = (void *)m->data;
fraginfo->ids[1] = ~0U;
}
static void frag_parse(struct xt_option_call *cb)
{
struct ip6t_frag *fraginfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_FRAGID:
if (cb->nvals == 1)
fraginfo->ids[1] = fraginfo->ids[0];
if (cb->invert)
fraginfo->invflags |= IP6T_FRAG_INV_IDS;
/*
* Note however that IP6T_FRAG_IDS is not tested by anything,
* so it is merely here for completeness.
*/
fraginfo->flags |= IP6T_FRAG_IDS;
break;
case O_FRAGLEN:
/*
* As of Linux 3.0, the kernel does not check for
* fraglen at all.
*/
if (cb->invert)
fraginfo->invflags |= IP6T_FRAG_INV_LEN;
fraginfo->flags |= IP6T_FRAG_LEN;
break;
case O_FRAGRES:
fraginfo->flags |= IP6T_FRAG_RES;
break;
case O_FRAGFIRST:
fraginfo->flags |= IP6T_FRAG_FST;
break;
case O_FRAGMORE:
fraginfo->flags |= IP6T_FRAG_MF;
break;
case O_FRAGLAST:
fraginfo->flags |= IP6T_FRAG_NMF;
break;
}
}
static void
print_ids(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFFFFFFFF || invert) {
printf("%s", name);
if (min == max)
printf(":%s%u", inv, min);
else
printf("s:%s%u:%u", inv, min, max);
}
}
static void frag_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_frag *frag = (struct ip6t_frag *)match->data;
printf(" frag ");
print_ids("id", frag->ids[0], frag->ids[1],
frag->invflags & IP6T_FRAG_INV_IDS);
if (frag->flags & IP6T_FRAG_LEN) {
printf(" length:%s%u",
frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "",
frag->hdrlen);
}
if (frag->flags & IP6T_FRAG_RES)
printf(" reserved");
if (frag->flags & IP6T_FRAG_FST)
printf(" first");
if (frag->flags & IP6T_FRAG_MF)
printf(" more");
if (frag->flags & IP6T_FRAG_NMF)
printf(" last");
if (frag->invflags & ~IP6T_FRAG_INV_MASK)
printf(" Unknown invflags: 0x%X",
frag->invflags & ~IP6T_FRAG_INV_MASK);
}
static void frag_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data;
if (!(fraginfo->ids[0] == 0
&& fraginfo->ids[1] == 0xFFFFFFFF)) {
printf("%s --fragid ",
(fraginfo->invflags & IP6T_FRAG_INV_IDS) ? " !" : "");
if (fraginfo->ids[0]
!= fraginfo->ids[1])
printf("%u:%u",
fraginfo->ids[0],
fraginfo->ids[1]);
else
printf("%u",
fraginfo->ids[0]);
}
if (fraginfo->flags & IP6T_FRAG_LEN) {
printf("%s --fraglen %u",
(fraginfo->invflags & IP6T_FRAG_INV_LEN) ? " !" : "",
fraginfo->hdrlen);
}
if (fraginfo->flags & IP6T_FRAG_RES)
printf(" --fragres");
if (fraginfo->flags & IP6T_FRAG_FST)
printf(" --fragfirst");
if (fraginfo->flags & IP6T_FRAG_MF)
printf(" --fragmore");
if (fraginfo->flags & IP6T_FRAG_NMF)
printf(" --fraglast");
}
static struct xtables_match frag_mt6_reg = {
.name = "frag",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_frag)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)),
.help = frag_help,
.init = frag_init,
.print = frag_print,
.save = frag_save,
.x6_parse = frag_parse,
.x6_options = frag_opts,
};
void
_init(void)
{
xtables_register_match(&frag_mt6_reg);
}
This module matches the parameters in Fragment header.
.TP
[\fB!\fP] \fB\-\-fragid\fP \fIid\fP[\fB:\fP\fIid\fP]
Matches the given Identification or range of it.
.TP
[\fB!\fP] \fB\-\-fraglen\fP \fIlength\fP
This option cannot be used with kernel version 2.6.10 or later. The length of
Fragment header is static and this option doesn't make sense.
.TP
\fB\-\-fragres\fP
Matches if the reserved fields are filled with zero.
.TP
\fB\-\-fragfirst\fP
Matches on the first fragment.
.TP
\fB\-\-fragmore\fP
Matches if there are more fragments.
.TP
\fB\-\-fraglast\fP
Matches if this is the last fragment.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define DEBUG 0
enum {
O_HBH_LEN = 0,
O_HBH_OPTS,
};
static void hbh_help(void)
{
printf(
"hbh match options:\n"
"[!] --hbh-len length total length of this header\n"
" --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
" Options and its length (list, max: %d)\n",
IP6T_OPTS_OPTSNR);
}
static const struct xt_option_entry hbh_opts[] = {
{.name = "hbh-len", .id = O_HBH_LEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct ip6t_opts, hdrlen)},
{.name = "hbh-opts", .id = O_HBH_OPTS, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
static uint32_t
parse_opts_num(const char *idstr, const char *typestr)
{
unsigned long int id;
char* ep;
id = strtoul(idstr,&ep,0) ;
if ( idstr == ep ) {
xtables_error(PARAMETER_PROBLEM,
"hbh: no valid digits in %s `%s'", typestr, idstr);
}
if ( id == ULONG_MAX && errno == ERANGE ) {
xtables_error(PARAMETER_PROBLEM,
"%s `%s' specified too big: would overflow",
typestr, idstr);
}
if ( *idstr != '\0' && *ep != '\0' ) {
xtables_error(PARAMETER_PROBLEM,
"hbh: error parsing %s `%s'", typestr, idstr);
}
return id;
}
static int
parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
buffer = strdup(optsstr);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
{
next=strchr(cp, ',');
if (next) *next++='\0';
range = strchr(cp, ':');
if (range) {
if (i == IP6T_OPTS_OPTSNR-1)
xtables_error(PARAMETER_PROBLEM,
"too many ports specified");
*range++ = '\0';
}
opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
if (range) {
if (opts[i] == 0)
xtables_error(PARAMETER_PROBLEM, "PAD0 has not got length");
opts[i] |= parse_opts_num(range, "length") & 0xFF;
} else {
opts[i] |= (0x00FF);
}
#if DEBUG
printf("opts str: %s %s\n", cp, range);
printf("opts opt: %04X\n", opts[i]);
#endif
}
if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
free(buffer);
#if DEBUG
printf("addr nr: %d\n", i);
#endif
return i;
}
static void hbh_parse(struct xt_option_call *cb)
{
struct ip6t_opts *optinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HBH_LEN:
if (cb->invert)
optinfo->invflags |= IP6T_OPTS_INV_LEN;
optinfo->flags |= IP6T_OPTS_LEN;
break;
case O_HBH_OPTS:
optinfo->optsnr = parse_options(cb->arg, optinfo->opts);
optinfo->flags |= IP6T_OPTS_OPTS;
break;
}
}
static void
print_options(unsigned int optsnr, uint16_t *optsp)
{
unsigned int i;
for(i=0; i<optsnr; i++){
printf("%c", (i==0)?' ':',');
printf("%d", (optsp[i] & 0xFF00)>>8);
if ((optsp[i] & 0x00FF) != 0x00FF){
printf(":%d", (optsp[i] & 0x00FF));
}
}
}
static void hbh_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
printf(" hbh");
if (optinfo->flags & IP6T_OPTS_LEN) {
printf(" length");
printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
printf("%u", optinfo->hdrlen);
}
if (optinfo->flags & IP6T_OPTS_OPTS) printf(" opts");
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
printf(" Unknown invflags: 0x%X",
optinfo->invflags & ~IP6T_OPTS_INV_MASK);
}
static void hbh_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
if (optinfo->flags & IP6T_OPTS_LEN) {
printf("%s --hbh-len %u",
(optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "",
optinfo->hdrlen);
}
if (optinfo->flags & IP6T_OPTS_OPTS)
printf(" --hbh-opts");
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
}
static struct xtables_match hbh_mt6_reg = {
.name = "hbh",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_opts)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)),
.help = hbh_help,
.print = hbh_print,
.save = hbh_save,
.x6_parse = hbh_parse,
.x6_options = hbh_opts,
};
void
_init(void)
{
xtables_register_match(&hbh_mt6_reg);
}
This module matches the parameters in Hop-by-Hop Options header
.TP
[\fB!\fP] \fB\-\-hbh\-len\fP \fIlength\fP
Total length of this header in octets.
.TP
\fB\-\-hbh\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
numeric type of option and the length of the option data in octets.
/*
* IPv6 Hop Limit matching module
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl match
* This program is released under the terms of GNU GPL
* Cleanups by Stephane Ouellette <ouellettes@videotron.ca>
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
enum {
O_HL_EQ = 0,
O_HL_LT,
O_HL_GT,
F_HL_EQ = 1 << O_HL_EQ,
F_HL_LT = 1 << O_HL_LT,
F_HL_GT = 1 << O_HL_GT,
F_ANY = F_HL_EQ | F_HL_LT | F_HL_GT,
};
static void hl_help(void)
{
printf(
"hl match options:\n"
"[!] --hl-eq value Match hop limit value\n"
" --hl-lt value Match HL < value\n"
" --hl-gt value Match HL > value\n");
}
static void hl_parse(struct xt_option_call *cb)
{
struct ip6t_hl_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HL_EQ:
info->mode = cb->invert ? IP6T_HL_NE : IP6T_HL_EQ;
break;
case O_HL_LT:
info->mode = IP6T_HL_LT;
break;
case O_HL_GT:
info->mode = IP6T_HL_GT;
break;
}
}
static void hl_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_ANY))
xtables_error(PARAMETER_PROBLEM,
"HL match: You must specify one of "
"`--hl-eq', `--hl-lt', `--hl-gt'");
}
static void hl_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
static const char *const op[] = {
[IP6T_HL_EQ] = "==",
[IP6T_HL_NE] = "!=",
[IP6T_HL_LT] = "<",
[IP6T_HL_GT] = ">" };
const struct ip6t_hl_info *info =
(struct ip6t_hl_info *) match->data;
printf(" HL match HL %s %u", op[info->mode], info->hop_limit);
}
static void hl_save(const void *ip, const struct xt_entry_match *match)
{
static const char *const op[] = {
[IP6T_HL_EQ] = "--hl-eq",
[IP6T_HL_NE] = "! --hl-eq",
[IP6T_HL_LT] = "--hl-lt",
[IP6T_HL_GT] = "--hl-gt" };
const struct ip6t_hl_info *info =
(struct ip6t_hl_info *) match->data;
printf(" %s %u", op[info->mode], info->hop_limit);
}
#define s struct ip6t_hl_info
static const struct xt_option_entry hl_opts[] = {
{.name = "hl-lt", .id = O_HL_LT, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl-gt", .id = O_HL_GT, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl-eq", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
XTOPT_TABLEEND,
};
#undef s
static struct xtables_match hl_mt6_reg = {
.name = "hl",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_hl_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_hl_info)),
.help = hl_help,
.print = hl_print,
.save = hl_save,
.x6_parse = hl_parse,
.x6_fcheck = hl_check,
.x6_options = hl_opts,
};
void _init(void)
{
xtables_register_match(&hl_mt6_reg);
}
This module matches the Hop Limit field in the IPv6 header.
.TP
[\fB!\fP] \fB\-\-hl\-eq\fP \fIvalue\fP
Matches if Hop Limit equals \fIvalue\fP.
.TP
\fB\-\-hl\-lt\fP \fIvalue\fP
Matches if Hop Limit is less than \fIvalue\fP.
.TP
\fB\-\-hl\-gt\fP \fIvalue\fP
Matches if Hop Limit is greater than \fIvalue\fP.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip6_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
enum {
O_ICMPV6_TYPE = 0,
};
struct icmpv6_names {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
};
static const struct icmpv6_names icmpv6_codes[] = {
{ "destination-unreachable", 1, 0, 0xFF },
{ "no-route", 1, 0, 0 },
{ "communication-prohibited", 1, 1, 1 },
{ "address-unreachable", 1, 3, 3 },
{ "port-unreachable", 1, 4, 4 },
{ "packet-too-big", 2, 0, 0xFF },
{ "time-exceeded", 3, 0, 0xFF },
/* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
{ "ttl-zero-during-transit", 3, 0, 0 },
{ "ttl-zero-during-reassembly", 3, 1, 1 },
{ "parameter-problem", 4, 0, 0xFF },
{ "bad-header", 4, 0, 0 },
{ "unknown-header-type", 4, 1, 1 },
{ "unknown-option", 4, 2, 2 },
{ "echo-request", 128, 0, 0xFF },
/* Alias */ { "ping", 128, 0, 0xFF },
{ "echo-reply", 129, 0, 0xFF },
/* Alias */ { "pong", 129, 0, 0xFF },
{ "router-solicitation", 133, 0, 0xFF },
{ "router-advertisement", 134, 0, 0xFF },
{ "neighbour-solicitation", 135, 0, 0xFF },
/* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
{ "neighbour-advertisement", 136, 0, 0xFF },
/* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
{ "redirect", 137, 0, 0xFF },
};
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)
{
printf(
"icmpv6 match options:\n"
"[!] --icmpv6-type typename match icmpv6 type\n"
" (or numeric type or type/code)\n");
print_icmpv6types();
}
static const struct xt_option_entry icmp6_opts[] = {
{.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void
parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[])
{
static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
unsigned int match = limit;
unsigned int i;
for (i = 0; i < limit; i++) {
if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
== 0) {
if (match != limit)
xtables_error(PARAMETER_PROBLEM,
"Ambiguous ICMPv6 type `%s':"
" `%s' or `%s'?",
icmpv6type,
icmpv6_codes[match].name,
icmpv6_codes[i].name);
match = i;
}
}
if (match != limit) {
*type = icmpv6_codes[match].type;
code[0] = icmpv6_codes[match].code_min;
code[1] = icmpv6_codes[match].code_max;
} else {
char *slash;
char buffer[strlen(icmpv6type) + 1];
unsigned int number;
strcpy(buffer, icmpv6type);
slash = strchr(buffer, '/');
if (slash)
*slash = '\0';
if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMPv6 type `%s'\n", buffer);
*type = number;
if (slash) {
if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMPv6 code `%s'\n",
slash+1);
code[0] = code[1] = number;
} else {
code[0] = 0;
code[1] = 0xFF;
}
}
}
static void icmp6_init(struct xt_entry_match *m)
{
struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
icmpv6info->code[1] = 0xFF;
}
static void icmp6_parse(struct xt_option_call *cb)
{
struct ip6t_icmp *icmpv6info = cb->data;
xtables_option_parse(cb);
parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
if (cb->invert)
icmpv6info->invflags |= IP6T_ICMP_INV;
}
static void print_icmpv6type(uint8_t type,
uint8_t code_min, uint8_t code_max,
int invert,
int numeric)
{
if (!numeric) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
if (icmpv6_codes[i].type == type
&& icmpv6_codes[i].code_min == code_min
&& icmpv6_codes[i].code_max == code_max)
break;
if (i != ARRAY_SIZE(icmpv6_codes)) {
printf(" %s%s",
invert ? "!" : "",
icmpv6_codes[i].name);
return;
}
}
if (invert)
printf(" !");
printf("type %u", type);
if (code_min == code_max)
printf(" code %u", code_min);
else if (code_min != 0 || code_max != 0xFF)
printf(" codes %u-%u", code_min, code_max);
}
static void icmp6_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
printf(" ipv6-icmp");
print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
icmpv6->invflags & IP6T_ICMP_INV,
numeric);
if (icmpv6->invflags & ~IP6T_ICMP_INV)
printf(" Unknown invflags: 0x%X",
icmpv6->invflags & ~IP6T_ICMP_INV);
}
static void icmp6_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
if (icmpv6->invflags & IP6T_ICMP_INV)
printf(" !");
printf(" --icmpv6-type %u", icmpv6->type);
if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
printf("/%u", icmpv6->code[0]);
}
static struct xtables_match icmp6_mt6_reg = {
.name = "icmp6",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_icmp)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)),
.help = icmp6_help,
.init = icmp6_init,
.print = icmp6_print,
.save = icmp6_save,
.x6_parse = icmp6_parse,
.x6_options = icmp6_opts,
};
void _init(void)
{
xtables_register_match(&icmp6_mt6_reg);
}
This extension can be used if `\-\-protocol ipv6\-icmp' or `\-\-protocol icmpv6' is
specified. It provides the following option:
.TP
[\fB!\fP] \fB\-\-icmpv6\-type\fP \fItype\fP[\fB/\fP\fIcode\fP]|\fItypename\fP
This allows specification of the ICMPv6 type, which can be a numeric
ICMPv6
.IR type ,
.IR type
and
.IR code ,
or one of the ICMPv6 type names shown by the command
.nf
ip6tables \-p ipv6\-icmp \-h
.fi
/* ipv6header match - matches IPv6 packets based
on whether they contain certain headers */
/* Original idea: Brad Chapman
* Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
enum {
O_HEADER = 0,
O_SOFT,
};
/* A few hardcoded protocols for 'all' and in case the user has no
* /etc/protocols */
struct pprot {
char *name;
uint8_t num;
};
struct numflag {
uint8_t proto;
uint8_t flag;
};
static const struct pprot chain_protos[] = {
{ "hop-by-hop", IPPROTO_HOPOPTS },
{ "protocol", IPPROTO_RAW },
{ "hop", IPPROTO_HOPOPTS },
{ "dst", IPPROTO_DSTOPTS },
{ "route", IPPROTO_ROUTING },
{ "frag", IPPROTO_FRAGMENT },
{ "auth", IPPROTO_AH },
{ "esp", IPPROTO_ESP },
{ "none", IPPROTO_NONE },
{ "prot", IPPROTO_RAW },
{ "0", IPPROTO_HOPOPTS },
{ "60", IPPROTO_DSTOPTS },
{ "43", IPPROTO_ROUTING },
{ "44", IPPROTO_FRAGMENT },
{ "51", IPPROTO_AH },
{ "50", IPPROTO_ESP },
{ "59", IPPROTO_NONE },
{ "255", IPPROTO_RAW },
/* { "all", 0 }, */
};
static const struct numflag chain_flags[] = {
{ IPPROTO_HOPOPTS, MASK_HOPOPTS },
{ IPPROTO_DSTOPTS, MASK_DSTOPTS },
{ IPPROTO_ROUTING, MASK_ROUTING },
{ IPPROTO_FRAGMENT, MASK_FRAGMENT },
{ IPPROTO_AH, MASK_AH },
{ IPPROTO_ESP, MASK_ESP },
{ IPPROTO_NONE, MASK_NONE },
{ IPPROTO_RAW, MASK_PROTO },
};
static const char *
proto_to_name(uint8_t proto, int nolookup)
{
unsigned int i;
if (proto && !nolookup) {
const struct protoent *pent = getprotobynumber(proto);
if (pent)
return pent->p_name;
}
for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
if (chain_protos[i].num == proto)
return chain_protos[i].name;
return NULL;
}
static uint16_t
name_to_proto(const char *s)
{
unsigned int proto=0;
const struct protoent *pent;
if ((pent = getprotobyname(s)))
proto = pent->p_proto;
else {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
if (strcmp(s, chain_protos[i].name) == 0) {
proto = chain_protos[i].num;
break;
}
if (i == ARRAY_SIZE(chain_protos))
xtables_error(PARAMETER_PROBLEM,
"unknown header `%s' specified",
s);
}
return proto;
}
static unsigned int
add_proto_to_mask(int proto){
unsigned int i=0, flag=0;
for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
if (proto == chain_flags[i].proto){
flag = chain_flags[i].flag;
break;
}
if (i == ARRAY_SIZE(chain_flags))
xtables_error(PARAMETER_PROBLEM,
"unknown header `%d' specified",
proto);
return flag;
}
static void ipv6header_help(void)
{
printf(
"ipv6header match options:\n"
"[!] --header headers Type of header to match, by name\n"
" names: hop,dst,route,frag,auth,esp,none,proto\n"
" long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
" ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
" numbers: 0,60,43,44,51,50,59\n"
"--soft The header CONTAINS the specified extensions\n");
}
static const struct xt_option_entry ipv6header_opts[] = {
{.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
{.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static unsigned int
parse_header(const char *flags) {
unsigned int ret = 0;
char *ptr;
char *buffer;
buffer = strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
ret |= add_proto_to_mask(name_to_proto(ptr));
free(buffer);
return ret;
}
static void ipv6header_parse(struct xt_option_call *cb)
{
struct ip6t_ipv6header_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HEADER:
if (!(info->matchflags = parse_header(cb->arg)))
xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
if (cb->invert)
info->invflags |= 0xFF;
break;
case O_SOFT:
info->modeflag |= 0xFF;
break;
}
}
static void
print_header(uint8_t flags){
int have_flag = 0;
while (flags) {
unsigned int i;
for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
if (have_flag)
printf(",");
printf("%s", proto_to_name(chain_flags[i].proto,0));
have_flag = 1;
flags &= ~chain_flags[i].flag;
}
if (!have_flag)
printf("NONE");
}
static void ipv6header_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
printf(" ipv6header");
if (info->matchflags || info->invflags) {
printf(" flags:%s", info->invflags ? "!" : "");
if (numeric)
printf("0x%02X", info->matchflags);
else {
print_header(info->matchflags);
}
}
if (info->modeflag)
printf(" soft");
}
static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
printf("%s --header ", info->invflags ? " !" : "");
print_header(info->matchflags);
if (info->modeflag)
printf(" --soft");
}
static struct xtables_match ipv6header_mt6_reg = {
.name = "ipv6header",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
.help = ipv6header_help,
.print = ipv6header_print,
.save = ipv6header_save,
.x6_parse = ipv6header_parse,
.x6_options = ipv6header_opts,
};
void _init(void)
{
xtables_register_match(&ipv6header_mt6_reg);
}
This module matches IPv6 extension headers and/or upper layer header.
.TP
\fB\-\-soft\fP
Matches if the packet includes \fBany\fP of the headers specified with
\fB\-\-header\fP.
.TP
[\fB!\fP] \fB\-\-header\fP \fIheader\fP[\fB,\fP\fIheader\fP...]
Matches the packet which EXACTLY includes all specified headers. The headers
encapsulated with ESP header are out of scope.
Possible \fIheader\fP types can be:
.TP
\fBhop\fP|\fBhop\-by\-hop\fP
Hop-by-Hop Options header
.TP
\fBdst\fP
Destination Options header
.TP
\fBroute\fP
Routing header
.TP
\fBfrag\fP
Fragment header
.TP
\fBauth\fP
Authentication header
.TP
\fBesp\fP
Encapsulating Security Payload header
.TP
\fBnone\fP
No Next header which matches 59 in the 'Next Header field' of IPv6 header or
any IPv6 extension headers
.TP
\fBproto\fP
which matches any upper layer protocol header. A protocol name from
/etc/protocols and numeric value also allowed. The number 255 is equivalent to
\fBproto\fP.
/* Shared library add-on to ip6tables to add mobility header support. */
/*
* Copyright (C)2006 USAGI/WIDE Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Author:
* Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
*
* Based on libip6t_{icmpv6,udp}.c
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_mh.h>
enum {
O_MH_TYPE = 0,
};
struct mh_name {
const char *name;
uint8_t type;
};
static const struct mh_name mh_names[] = {
{ "binding-refresh-request", 0, },
/* Alias */ { "brr", 0, },
{ "home-test-init", 1, },
/* Alias */ { "hoti", 1, },
{ "careof-test-init", 2, },
/* Alias */ { "coti", 2, },
{ "home-test", 3, },
/* Alias */ { "hot", 3, },
{ "careof-test", 4, },
/* Alias */ { "cot", 4, },
{ "binding-update", 5, },
/* Alias */ { "bu", 5, },
{ "binding-acknowledgement", 6, },
/* Alias */ { "ba", 6, },
{ "binding-error", 7, },
/* Alias */ { "be", 7, },
};
static void print_types_all(void)
{
unsigned int i;
printf("Valid MH types:");
for (i = 0; i < ARRAY_SIZE(mh_names); ++i) {
if (i && mh_names[i].type == mh_names[i-1].type)
printf(" (%s)", mh_names[i].name);
else
printf("\n%s", mh_names[i].name);
}
printf("\n");
}
static void mh_help(void)
{
printf(
"mh match options:\n"
"[!] --mh-type type[:type] match mh type\n");
print_types_all();
}
static void mh_init(struct xt_entry_match *m)
{
struct ip6t_mh *mhinfo = (struct ip6t_mh *)m->data;
mhinfo->types[1] = 0xFF;
}
static unsigned int name_to_type(const char *name)
{
int namelen = strlen(name);
static const unsigned int limit = ARRAY_SIZE(mh_names);
unsigned int match = limit;
unsigned int i;
for (i = 0; i < limit; i++) {
if (strncasecmp(mh_names[i].name, name, namelen) == 0) {
int len = strlen(mh_names[i].name);
if (match == limit || len == namelen)
match = i;
}
}
if (match != limit) {
return mh_names[match].type;
} else {
unsigned int number;
if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid MH type `%s'\n", name);
return number;
}
}
static void parse_mh_types(const char *mhtype, uint8_t *types)
{
char *buffer;
char *cp;
buffer = strdup(mhtype);
if ((cp = strchr(buffer, ':')) == NULL)
types[0] = types[1] = name_to_type(buffer);
else {
*cp = '\0';
cp++;
types[0] = buffer[0] ? name_to_type(buffer) : 0;
types[1] = cp[0] ? name_to_type(cp) : 0xFF;
if (types[0] > types[1])
xtables_error(PARAMETER_PROBLEM,
"Invalid MH type range (min > max)");
}
free(buffer);
}
static void mh_parse(struct xt_option_call *cb)
{
struct ip6t_mh *mhinfo = cb->data;
xtables_option_parse(cb);
parse_mh_types(cb->arg, mhinfo->types);
if (cb->invert)
mhinfo->invflags |= IP6T_MH_INV_TYPE;
}
static const char *type_to_name(uint8_t type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(mh_names); ++i)
if (mh_names[i].type == type)
return mh_names[i].name;
return NULL;
}
static void print_type(uint8_t type, int numeric)
{
const char *name;
if (numeric || !(name = type_to_name(type)))
printf("%u", type);
else
printf("%s", name);
}
static void print_types(uint8_t min, uint8_t max, int invert, int numeric)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFF || invert) {
printf(" ");
if (min == max) {
printf("%s", inv);
print_type(min, numeric);
} else {
printf("%s", inv);
print_type(min, numeric);
printf(":");
print_type(max, numeric);
}
}
}
static void mh_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
printf(" mh");
print_types(mhinfo->types[0], mhinfo->types[1],
mhinfo->invflags & IP6T_MH_INV_TYPE,
numeric);
if (mhinfo->invflags & ~IP6T_MH_INV_MASK)
printf(" Unknown invflags: 0x%X",
mhinfo->invflags & ~IP6T_MH_INV_MASK);
}
static void mh_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF)
return;
if (mhinfo->invflags & IP6T_MH_INV_TYPE)
printf(" !");
if (mhinfo->types[0] != mhinfo->types[1])
printf(" --mh-type %u:%u", mhinfo->types[0], mhinfo->types[1]);
else
printf(" --mh-type %u", mhinfo->types[0]);
}
static const struct xt_option_entry mh_opts[] = {
{.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
static struct xtables_match mh_mt6_reg = {
.name = "mh",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_mh)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_mh)),
.help = mh_help,
.init = mh_init,
.x6_parse = mh_parse,
.print = mh_print,
.save = mh_save,
.x6_options = mh_opts,
};
void _init(void)
{
xtables_register_match(&mh_mt6_reg);
}
This extension is loaded if `\-\-protocol ipv6\-mh' or `\-\-protocol mh' is
specified. It provides the following option:
.TP
[\fB!\fP] \fB\-\-mh\-type\fP \fItype\fP[\fB:\fP\fItype\fP]
This allows specification of the Mobility Header(MH) type, which can be
a numeric MH
.IR type ,
.IR type
or one of the MH type names shown by the command
.nf
ip6tables \-p mh \-h
.fi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_rt.h>
#include <arpa/inet.h>
enum {
O_RT_TYPE = 0,
O_RT_SEGSLEFT,
O_RT_LEN,
O_RT0RES,
O_RT0ADDRS,
O_RT0NSTRICT,
F_RT_TYPE = 1 << O_RT_TYPE,
F_RT0ADDRS = 1 << O_RT0ADDRS,
};
static void rt_help(void)
{
printf(
"rt match options:\n"
"[!] --rt-type type match the type\n"
"[!] --rt-segsleft num[:num] match the Segments Left field (range)\n"
"[!] --rt-len length total length of this header\n"
" --rt-0-res check the reserved field too (type 0)\n"
" --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
" --rt-0-not-strict List of Type=0 addresses not a strict list\n",
IP6T_RT_HOPS);
}
#define s struct ip6t_rt
static const struct xt_option_entry rt_opts[] = {
{.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)},
{.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
{.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
{.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE},
{.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING},
{.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
static const char *
addr_to_numeric(const struct in6_addr *addrp)
{
static char buf[50+1];
return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
}
static struct in6_addr *
numeric_to_addr(const char *num)
{
static struct in6_addr ap;
int err;
if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
return &ap;
#ifdef DEBUG
fprintf(stderr, "\nnumeric2addr: %d\n", err);
#endif
xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
return (struct in6_addr *)NULL;
}
static int
parse_addresses(const char *addrstr, struct in6_addr *addrp)
{
char *buffer, *cp, *next;
unsigned int i;
buffer = strdup(addrstr);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
{
next=strchr(cp, ',');
if (next) *next++='\0';
memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
#if DEBUG
printf("addr str: %s\n", cp);
printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
#endif
}
if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
free(buffer);
#if DEBUG
printf("addr nr: %d\n", i);
#endif
return i;
}
static void rt_parse(struct xt_option_call *cb)
{
struct ip6t_rt *rtinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_RT_TYPE:
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_TYP;
rtinfo->flags |= IP6T_RT_TYP;
break;
case O_RT_SEGSLEFT:
if (cb->nvals == 1)
rtinfo->segsleft[1] = rtinfo->segsleft[0];
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_SGS;
rtinfo->flags |= IP6T_RT_SGS;
break;
case O_RT_LEN:
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_LEN;
rtinfo->flags |= IP6T_RT_LEN;
break;
case O_RT0RES:
if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
rtinfo->invflags & IP6T_RT_INV_TYP)
xtables_error(PARAMETER_PROBLEM,
"`--rt-type 0' required before `--rt-0-res'");
rtinfo->flags |= IP6T_RT_RES;
break;
case O_RT0ADDRS:
if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
rtinfo->invflags & IP6T_RT_INV_TYP)
xtables_error(PARAMETER_PROBLEM,
"`--rt-type 0' required before `--rt-0-addrs'");
rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs);
rtinfo->flags |= IP6T_RT_FST;
break;
case O_RT0NSTRICT:
if (!(cb->xflags & F_RT0ADDRS))
xtables_error(PARAMETER_PROBLEM,
"`--rt-0-addr ...' required before `--rt-0-not-strict'");
rtinfo->flags |= IP6T_RT_FST_NSTRICT;
break;
}
}
static void
print_nums(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFFFFFFFF || invert) {
printf(" %s", name);
if (min == max) {
printf(":%s", inv);
printf("%u", min);
} else {
printf("s:%s", inv);
printf("%u",min);
printf(":");
printf("%u",max);
}
}
}
static void
print_addresses(unsigned int addrnr, struct in6_addr *addrp)
{
unsigned int i;
for(i=0; i<addrnr; i++){
printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
}
}
static void rt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
printf(" rt");
if (rtinfo->flags & IP6T_RT_TYP)
printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
rtinfo->rt_type);
print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
rtinfo->invflags & IP6T_RT_INV_SGS);
if (rtinfo->flags & IP6T_RT_LEN) {
printf(" length");
printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
printf("%u", rtinfo->hdrlen);
}
if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
printf(" Unknown invflags: 0x%X",
rtinfo->invflags & ~IP6T_RT_INV_MASK);
}
static void rt_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
if (rtinfo->flags & IP6T_RT_TYP) {
printf("%s --rt-type %u",
(rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
rtinfo->rt_type);
}
if (!(rtinfo->segsleft[0] == 0
&& rtinfo->segsleft[1] == 0xFFFFFFFF)) {
printf("%s --rt-segsleft ",
(rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
if (rtinfo->segsleft[0]
!= rtinfo->segsleft[1])
printf("%u:%u",
rtinfo->segsleft[0],
rtinfo->segsleft[1]);
else
printf("%u",
rtinfo->segsleft[0]);
}
if (rtinfo->flags & IP6T_RT_LEN) {
printf("%s --rt-len %u",
(rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
rtinfo->hdrlen);
}
if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
}
static struct xtables_match rt_mt6_reg = {
.name = "rt",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_rt)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
.help = rt_help,
.x6_parse = rt_parse,
.print = rt_print,
.save = rt_save,
.x6_options = rt_opts,
};
void
_init(void)
{
xtables_register_match(&rt_mt6_reg);
}
Match on IPv6 routing header
.TP
[\fB!\fP] \fB\-\-rt\-type\fP \fItype\fP
Match the type (numeric).
.TP
[\fB!\fP] \fB\-\-rt\-segsleft\fP \fInum\fP[\fB:\fP\fInum\fP]
Match the `segments left' field (range).
.TP
[\fB!\fP] \fB\-\-rt\-len\fP \fIlength\fP
Match the length of this header.
.TP
\fB\-\-rt\-0\-res\fP
Match the reserved field, too (type=0)
.TP
\fB\-\-rt\-0\-addrs\fP \fIaddr\fP[\fB,\fP\fIaddr\fP...]
Match type=0 addresses (list).
.TP
\fB\-\-rt\-0\-not\-strict\fP
List of type=0 addresses is not a strict list.
/* Shared library add-on to iptables to add CLUSTERIP target support.
* (C) 2003 by Harald Welte <laforge@gnumonks.org>
*
* Development of this code was funded by SuSE AG, http://www.suse.com/
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <stddef.h>
#if defined(__GLIBC__) && __GLIBC__ == 2
#include <net/ethernet.h>
#else
#include <linux/if_ether.h>
#endif
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
enum {
O_NEW = 0,
O_HASHMODE,
O_CLUSTERMAC,
O_TOTAL_NODES,
O_LOCAL_NODE,
O_HASH_INIT,
F_NEW = 1 << O_NEW,
F_HASHMODE = 1 << O_HASHMODE,
F_CLUSTERMAC = 1 << O_CLUSTERMAC,
F_TOTAL_NODES = 1 << O_TOTAL_NODES,
F_LOCAL_NODE = 1 << O_LOCAL_NODE,
F_FULL = F_NEW | F_HASHMODE | F_CLUSTERMAC |
F_TOTAL_NODES | F_LOCAL_NODE,
};
static void CLUSTERIP_help(void)
{
printf(
"CLUSTERIP target options:\n"
" --new Create a new ClusterIP\n"
" --hashmode <mode> Specify hashing mode\n"
" sourceip\n"
" sourceip-sourceport\n"
" sourceip-sourceport-destport\n"
" --clustermac <mac> Set clusterIP MAC address\n"
" --total-nodes <num> Set number of total nodes in cluster\n"
" --local-node <num> Set the local node number\n"
" --hash-init <num> Set init value of the Jenkins hash\n");
}
#define s struct ipt_clusterip_tgt_info
static const struct xt_option_entry CLUSTERIP_opts[] = {
{.name = "new", .id = O_NEW, .type = XTTYPE_NONE},
{.name = "hashmode", .id = O_HASHMODE, .type = XTTYPE_STRING,
.also = O_NEW},
{.name = "clustermac", .id = O_CLUSTERMAC, .type = XTTYPE_ETHERMAC,
.also = O_NEW, .flags = XTOPT_PUT, XTOPT_POINTER(s, clustermac)},
{.name = "total-nodes", .id = O_TOTAL_NODES, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, num_total_nodes),
.also = O_NEW, .max = CLUSTERIP_MAX_NODES},
{.name = "local-node", .id = O_LOCAL_NODE, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, local_nodes[0]),
.also = O_NEW, .max = CLUSTERIP_MAX_NODES},
{.name = "hash-init", .id = O_HASH_INIT, .type = XTTYPE_UINT32,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hash_initval),
.also = O_NEW, .max = UINT_MAX},
XTOPT_TABLEEND,
};
#undef s
static void CLUSTERIP_parse(struct xt_option_call *cb)
{
struct ipt_clusterip_tgt_info *cipinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_NEW:
cipinfo->flags |= CLUSTERIP_FLAG_NEW;
break;
case O_HASHMODE:
if (strcmp(cb->arg, "sourceip") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP;
else if (strcmp(cb->arg, "sourceip-sourceport") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT;
else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
else
xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
cb->arg);
break;
case O_CLUSTERMAC:
if (!(cipinfo->clustermac[0] & 0x01))
xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
break;
case O_LOCAL_NODE:
cipinfo->num_local_nodes = 1;
break;
}
}
static void CLUSTERIP_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
return;
if ((cb->xflags & F_FULL) == F_FULL)
return;
xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
}
static const char *hashmode2str(enum clusterip_hashmode mode)
{
const char *retstr;
switch (mode) {
case CLUSTERIP_HASHMODE_SIP:
retstr = "sourceip";
break;
case CLUSTERIP_HASHMODE_SIP_SPT:
retstr = "sourceip-sourceport";
break;
case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
retstr = "sourceip-sourceport-destport";
break;
default:
retstr = "unknown-error";
break;
}
return retstr;
}
static const char *mac2str(const uint8_t mac[ETH_ALEN])
{
static char buf[ETH_ALEN*3];
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return buf;
}
static void CLUSTERIP_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct ipt_clusterip_tgt_info *cipinfo =
(const struct ipt_clusterip_tgt_info *)target->data;
if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
printf(" CLUSTERIP");
return;
}
printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u",
hashmode2str(cipinfo->hash_mode),
mac2str(cipinfo->clustermac),
cipinfo->num_total_nodes,
cipinfo->local_nodes[0],
cipinfo->hash_initval);
}
static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_clusterip_tgt_info *cipinfo =
(const struct ipt_clusterip_tgt_info *)target->data;
/* if this is not a new entry, we don't need to save target
* parameters */
if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW))
return;
printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
hashmode2str(cipinfo->hash_mode),
mac2str(cipinfo->clustermac),
cipinfo->num_total_nodes,
cipinfo->local_nodes[0],
cipinfo->hash_initval);
}
static struct xtables_target clusterip_tg_reg = {
.name = "CLUSTERIP",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
.userspacesize = offsetof(struct ipt_clusterip_tgt_info, config),
.help = CLUSTERIP_help,
.x6_parse = CLUSTERIP_parse,
.x6_fcheck = CLUSTERIP_check,
.print = CLUSTERIP_print,
.save = CLUSTERIP_save,
.x6_options = CLUSTERIP_opts,
};
void _init(void)
{
xtables_register_target(&clusterip_tg_reg);
}
This module allows you to configure a simple cluster of nodes that share
a certain IP and MAC address without an explicit load balancer in front of
them. Connections are statically distributed between the nodes in this
cluster.
.TP
\fB\-\-new\fP
Create a new ClusterIP. You always have to set this on the first rule
for a given ClusterIP.
.TP
\fB\-\-hashmode\fP \fImode\fP
Specify the hashing mode. Has to be one of
\fBsourceip\fP, \fBsourceip\-sourceport\fP, \fBsourceip\-sourceport\-destport\fP.
.TP
\fB\-\-clustermac\fP \fImac\fP
Specify the ClusterIP MAC address. Has to be a link\-layer multicast address
.TP
\fB\-\-total\-nodes\fP \fInum\fP
Number of total nodes within this cluster.
.TP
\fB\-\-local\-node\fP \fInum\fP
Local node number within this cluster.
.TP
\fB\-\-hash\-init\fP \fIrnd\fP
Specify the random seed used for hash initialization.
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <iptables.h> /* get_kernel_version */
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
enum {
O_TO_DEST = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_DEST, /* hidden flag */
F_TO_DEST = 1 << O_TO_DEST,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_DEST = 1 << O_X_TO_DEST,
};
/* Dest NAT data consists of a multi-range, indicating where to map
to. */
struct ipt_natinfo
{
struct xt_entry_target t;
struct nf_nat_ipv4_multi_range_compat mr;
};
static void DNAT_help(void)
{
printf(
"DNAT target options:\n"
" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map destination to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry DNAT_opts[] = {
{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static struct ipt_natinfo *
append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range)
{
unsigned int size;
/* One rangesize already in struct ipt_natinfo */
size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
info = realloc(info, size);
if (!info)
xtables_error(OTHER_PROBLEM, "Out of memory\n");
info->t.u.target_size = size;
info->mr.range[info->mr.rangesize] = *range;
info->mr.rangesize++;
return info;
}
/* Ranges expected in network order. */
static struct xt_entry_target *
parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
{
struct nf_nat_ipv4_range range;
char *arg, *colon, *dash, *error;
const struct in_addr *ip;
arg = strdup(orig_arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
memset(&range, 0, sizeof(range));
colon = strchr(arg, ':');
if (colon) {
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.tcp.port
= range.max.tcp.port
= htons(port);
} else {
int maxport;
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.tcp.port = htons(port);
range.max.tcp.port = htons(maxport);
}
/* Starts with a colon? No IP info...*/
if (colon == arg) {
free(arg);
return &(append_range(info, &range)->t);
}
*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_ip = ip->s_addr;
if (dash) {
ip = xtables_numeric_to_ipaddr(dash+1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
range.max_ip = ip->s_addr;
} else
range.max_ip = range.min_ip;
free(arg);
return &(append_range(info, &range)->t);
}
static void DNAT_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct ipt_natinfo *info = (void *)(*cb->target);
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) {
if (!kernel_version)
get_kernel_version();
if (kernel_version > LINUX_VERSION(2, 6, 10))
xtables_error(PARAMETER_PROBLEM,
"DNAT: Multiple --to-destination not supported");
}
*cb->target = parse_to(cb->arg, portok, info);
cb->xflags |= F_X_TO_DEST;
break;
case O_PERSISTENT:
info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
static void DNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_DEST | F_RANDOM;
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
if ((cb->xflags & f) == f)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void print_range(const struct nf_nat_ipv4_range *r)
{
if (r->flags & NF_NAT_RANGE_MAP_IPS) {
struct in_addr a;
a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
if (r->max_ip != r->min_ip) {
a.s_addr = r->max_ip;
printf("-%s", xtables_ipaddr_to_numeric(&a));
}
}
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(":");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
}
static void DNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_natinfo *info = (const void *)target;
unsigned int i = 0;
printf(" to:");
for (i = 0; i < info->mr.rangesize; i++) {
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
}
static void DNAT_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_natinfo *info = (const void *)target;
unsigned int i = 0;
for (i = 0; i < info->mr.rangesize; i++) {
printf(" --to-destination ");
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
}
static struct xtables_target dnat_tg_reg = {
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.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,
.x6_parse = DNAT_parse,
.x6_fcheck = DNAT_fcheck,
.print = DNAT_print,
.save = DNAT_save,
.x6_options = DNAT_opts,
};
void _init(void)
{
xtables_register_target(&dnat_tg_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