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

Imported Upstream version 1.4.21

parents
/* Shared library add-on to iptables for ECN, $Version$
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This program is distributed under the terms of GNU GPL v2, 1991
*
* libipt_ECN.c borrowed heavily from libipt_DSCP.c
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_ECN.h>
enum {
O_ECN_TCP_REMOVE = 0,
O_ECN_TCP_CWR,
O_ECN_TCP_ECE,
O_ECN_IP_ECT,
F_ECN_TCP_REMOVE = 1 << O_ECN_TCP_REMOVE,
F_ECN_TCP_CWR = 1 << O_ECN_TCP_CWR,
F_ECN_TCP_ECE = 1 << O_ECN_TCP_ECE,
};
static void ECN_help(void)
{
printf(
"ECN target options\n"
" --ecn-tcp-remove Remove all ECN bits from TCP header\n");
}
#if 0
"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
" --ecn-ip-ect Set the IPv4 ECT codepoint (0 to 3)\n"
" --ecn-tcp-cwr Set the IPv4 CWR bit (0 or 1)\n"
" --ecn-tcp-ece Set the IPv4 ECE bit (0 or 1)\n",
#endif
static const struct xt_option_entry ECN_opts[] = {
{.name = "ecn-tcp-remove", .id = O_ECN_TCP_REMOVE, .type = XTTYPE_NONE,
.excl = F_ECN_TCP_CWR | F_ECN_TCP_ECE},
{.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_UINT8,
.min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
{.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_UINT8,
.min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
{.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8,
.min = 0, .max = 3},
XTOPT_TABLEEND,
};
static void ECN_parse(struct xt_option_call *cb)
{
struct ipt_ECN_info *einfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_ECN_TCP_REMOVE:
einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
einfo->proto.tcp.ece = 0;
einfo->proto.tcp.cwr = 0;
break;
case O_ECN_TCP_CWR:
einfo->operation |= IPT_ECN_OP_SET_CWR;
einfo->proto.tcp.cwr = cb->val.u8;
break;
case O_ECN_TCP_ECE:
einfo->operation |= IPT_ECN_OP_SET_ECE;
einfo->proto.tcp.ece = cb->val.u8;
break;
case O_ECN_IP_ECT:
einfo->operation |= IPT_ECN_OP_SET_IP;
einfo->ip_ect = cb->val.u8;
break;
}
}
static void ECN_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
xtables_error(PARAMETER_PROBLEM,
"ECN target: An operation is required");
}
static void ECN_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_ECN_info *einfo =
(const struct ipt_ECN_info *)target->data;
printf(" ECN");
if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
&& einfo->proto.tcp.ece == 0
&& einfo->proto.tcp.cwr == 0)
printf(" TCP remove");
else {
if (einfo->operation & IPT_ECN_OP_SET_ECE)
printf(" ECE=%u", einfo->proto.tcp.ece);
if (einfo->operation & IPT_ECN_OP_SET_CWR)
printf(" CWR=%u", einfo->proto.tcp.cwr);
if (einfo->operation & IPT_ECN_OP_SET_IP)
printf(" ECT codepoint=%u", einfo->ip_ect);
}
}
static void ECN_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_ECN_info *einfo =
(const struct ipt_ECN_info *)target->data;
if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
&& einfo->proto.tcp.ece == 0
&& einfo->proto.tcp.cwr == 0)
printf(" --ecn-tcp-remove");
else {
if (einfo->operation & IPT_ECN_OP_SET_ECE)
printf(" --ecn-tcp-ece %d", einfo->proto.tcp.ece);
if (einfo->operation & IPT_ECN_OP_SET_CWR)
printf(" --ecn-tcp-cwr %d", einfo->proto.tcp.cwr);
if (einfo->operation & IPT_ECN_OP_SET_IP)
printf(" --ecn-ip-ect %d", einfo->ip_ect);
}
}
static struct xtables_target ecn_tg_reg = {
.name = "ECN",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_ECN_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ECN_info)),
.help = ECN_help,
.print = ECN_print,
.save = ECN_save,
.x6_parse = ECN_parse,
.x6_fcheck = ECN_check,
.x6_options = ECN_opts,
};
void _init(void)
{
xtables_register_target(&ecn_tg_reg);
}
This target allows to selectively work around known ECN blackholes.
It can only be used in the mangle table.
.TP
\fB\-\-ecn\-tcp\-remove\fP
Remove all ECN bits from the TCP header. Of course, it can only be used
in conjunction with
\fB\-p tcp\fP.
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#define LOG_DEFAULT_LEVEL LOG_WARNING
#ifndef IPT_LOG_UID /* Old kernel */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#undef IPT_LOG_MASK
#define IPT_LOG_MASK 0x0f
#endif
enum {
O_LOG_LEVEL = 0,
O_LOG_PREFIX,
O_LOG_TCPSEQ,
O_LOG_TCPOPTS,
O_LOG_IPOPTS,
O_LOG_UID,
O_LOG_MAC,
};
static void LOG_help(void)
{
printf(
"LOG target options:\n"
" --log-level level Level of logging (numeric or see syslog.conf)\n"
" --log-prefix prefix Prefix log messages with this prefix.\n\n"
" --log-tcp-sequence Log TCP sequence numbers.\n\n"
" --log-tcp-options Log TCP options.\n\n"
" --log-ip-options Log IP options.\n\n"
" --log-uid Log UID owning the local socket.\n\n"
" --log-macdecode Decode MAC addresses and protocol.\n\n");
}
#define s struct ipt_log_info
static const struct xt_option_entry LOG_opts[] = {
{.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
.flags = XTOPT_PUT, XTOPT_POINTER(s, level)},
{.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
.flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1},
{.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE},
{.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE},
{.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE},
{.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE},
{.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
static void LOG_init(struct xt_entry_target *t)
{
struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
loginfo->level = LOG_DEFAULT_LEVEL;
}
struct ipt_log_names {
const char *name;
unsigned int level;
};
static const struct ipt_log_names ipt_log_names[]
= { { .name = "alert", .level = LOG_ALERT },
{ .name = "crit", .level = LOG_CRIT },
{ .name = "debug", .level = LOG_DEBUG },
{ .name = "emerg", .level = LOG_EMERG },
{ .name = "error", .level = LOG_ERR }, /* DEPRECATED */
{ .name = "info", .level = LOG_INFO },
{ .name = "notice", .level = LOG_NOTICE },
{ .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */
{ .name = "warning", .level = LOG_WARNING }
};
static void LOG_parse(struct xt_option_call *cb)
{
struct ipt_log_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LOG_PREFIX:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --log-prefix");
break;
case O_LOG_TCPSEQ:
info->logflags |= IPT_LOG_TCPSEQ;
break;
case O_LOG_TCPOPTS:
info->logflags |= IPT_LOG_TCPOPT;
break;
case O_LOG_IPOPTS:
info->logflags |= IPT_LOG_IPOPT;
break;
case O_LOG_UID:
info->logflags |= IPT_LOG_UID;
break;
case O_LOG_MAC:
info->logflags |= IPT_LOG_MACDECODE;
break;
}
}
static void LOG_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_log_info *loginfo
= (const struct ipt_log_info *)target->data;
unsigned int i = 0;
printf(" LOG");
if (numeric)
printf(" flags %u level %u",
loginfo->logflags, loginfo->level);
else {
for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i)
if (loginfo->level == ipt_log_names[i].level) {
printf(" level %s", ipt_log_names[i].name);
break;
}
if (i == ARRAY_SIZE(ipt_log_names))
printf(" UNKNOWN level %u", loginfo->level);
if (loginfo->logflags & IPT_LOG_TCPSEQ)
printf(" tcp-sequence");
if (loginfo->logflags & IPT_LOG_TCPOPT)
printf(" tcp-options");
if (loginfo->logflags & IPT_LOG_IPOPT)
printf(" ip-options");
if (loginfo->logflags & IPT_LOG_UID)
printf(" uid");
if (loginfo->logflags & IPT_LOG_MACDECODE)
printf(" macdecode");
if (loginfo->logflags & ~(IPT_LOG_MASK))
printf(" unknown-flags");
}
if (strcmp(loginfo->prefix, "") != 0)
printf(" prefix \"%s\"", loginfo->prefix);
}
static void LOG_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_log_info *loginfo
= (const struct ipt_log_info *)target->data;
if (strcmp(loginfo->prefix, "") != 0) {
printf(" --log-prefix");
xtables_save_string(loginfo->prefix);
}
if (loginfo->level != LOG_DEFAULT_LEVEL)
printf(" --log-level %d", loginfo->level);
if (loginfo->logflags & IPT_LOG_TCPSEQ)
printf(" --log-tcp-sequence");
if (loginfo->logflags & IPT_LOG_TCPOPT)
printf(" --log-tcp-options");
if (loginfo->logflags & IPT_LOG_IPOPT)
printf(" --log-ip-options");
if (loginfo->logflags & IPT_LOG_UID)
printf(" --log-uid");
if (loginfo->logflags & IPT_LOG_MACDECODE)
printf(" --log-macdecode");
}
static struct xtables_target log_tg_reg = {
.name = "LOG",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_log_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)),
.help = LOG_help,
.init = LOG_init,
.print = LOG_print,
.save = LOG_save,
.x6_parse = LOG_parse,
.x6_options = LOG_opts,
};
void _init(void)
{
xtables_register_target(&log_tg_reg);
}
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#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_PORTS = 0,
O_RANDOM,
};
static void MASQUERADE_help(void)
{
printf(
"MASQUERADE target options:\n"
" --to-ports <port>[-<port>]\n"
" Port (range) to map to.\n"
" --random\n"
" Randomize source port.\n");
}
static const struct xt_option_entry MASQUERADE_opts[] = {
{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static void MASQUERADE_init(struct xt_entry_target *t)
{
struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr)
{
char *end;
unsigned int port, maxport;
mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
switch (*end) {
case '\0':
mr->range[0].min.tcp.port
= mr->range[0].max.tcp.port
= htons(port);
return;
case '-':
if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
break;
if (maxport < port)
break;
mr->range[0].min.tcp.port = htons(port);
mr->range[0].max.tcp.port = htons(maxport);
return;
default:
break;
}
xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
}
static void MASQUERADE_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
int portok;
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
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_PORTS:
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
parse_ports(cb->arg, mr);
break;
case O_RANDOM:
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void
MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" masq ports: ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
static void
MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports %hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
static struct xtables_target masquerade_tg_reg = {
.name = "MASQUERADE",
.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 = MASQUERADE_help,
.init = MASQUERADE_init,
.x6_parse = MASQUERADE_parse,
.print = MASQUERADE_print,
.save = MASQUERADE_save,
.x6_options = MASQUERADE_opts,
};
void _init(void)
{
xtables_register_target(&masquerade_tg_reg);
}
/* Shared library add-on to iptables to add MIRROR target support. */
#include <xtables.h>
static struct xtables_target mirror_tg_reg = {
.name = "MIRROR",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
};
void _init(void)
{
xtables_register_target(&mirror_tg_reg);
}
This is an experimental demonstration target which inverts the source
and destination fields in the IP header and retransmits the packet.
It is only valid in the
.BR INPUT ,
.B FORWARD
and
.B PREROUTING
chains, and user-defined chains which are only called from those
chains. Note that the outgoing packets are
.B NOT
seen by any packet filtering chains, connection tracking or NAT, to
avoid loops and other problems.
/* Shared library add-on to iptables to add static NAT support.
Author: Svenning Soerensen <svenning@post5.tele.dk>
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/nf_nat.h>
#define MODULENAME "NETMAP"
enum {
O_TO = 0,
};
static const struct xt_option_entry NETMAP_opts[] = {
{.name = "to", .id = O_TO, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND},
XTOPT_TABLEEND,
};
static void NETMAP_help(void)
{
printf(MODULENAME" target options:\n"
" --%s address[/mask]\n"
" Network address to map to.\n\n",
NETMAP_opts[0].name);
}
static int
netmask2bits(uint32_t netmask)
{
uint32_t bm;
int bits;
netmask = ntohl(netmask);
for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
bits++;
if (netmask)
return -1; /* holes in netmask */
return bits;
}
static void NETMAP_init(struct xt_entry_target *t)
{
struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
static void NETMAP_parse(struct xt_option_call *cb)
{
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
struct nf_nat_ipv4_range *range = &mr->range[0];
xtables_option_parse(cb);
range->flags |= NF_NAT_RANGE_MAP_IPS;
range->min_ip = cb->val.haddr.ip & cb->val.hmask.ip;
range->max_ip = range->min_ip | ~cb->val.hmask.ip;
}
static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
struct in_addr a;
int bits;
a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
a.s_addr = ~(r->min_ip ^ r->max_ip);
bits = netmask2bits(a.s_addr);
if (bits < 0)
printf("/%s", xtables_ipaddr_to_numeric(&a));
else
printf("/%d", bits);
}
static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
{
printf(" --%s ", NETMAP_opts[0].name);
NETMAP_print(ip, target, 0);
}
static struct xtables_target netmap_tg_reg = {
.name = MODULENAME,
.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 = NETMAP_help,
.init = NETMAP_init,
.x6_parse = NETMAP_parse,
.print = NETMAP_print,
.save = NETMAP_save,
.x6_options = NETMAP_opts,
};
void _init(void)
{
xtables_register_target(&netmap_tg_reg);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#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_PORTS = 0,
O_RANDOM,
F_TO_PORTS = 1 << O_TO_PORTS,
F_RANDOM = 1 << O_RANDOM,
};
static void REDIRECT_help(void)
{
printf(
"REDIRECT target options:\n"
" --to-ports <port>[-<port>]\n"
" Port (range) to map to.\n"
" [--random]\n");
}
static const struct xt_option_entry REDIRECT_opts[] = {
{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static void REDIRECT_init(struct xt_entry_target *t)
{
struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr)
{
char *end = "";
unsigned int port, maxport;
mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
(port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
switch (*end) {
case '\0':
mr->range[0].min.tcp.port
= mr->range[0].max.tcp.port
= htons(port);
return;
case '-':
if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
(maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
break;
if (maxport < port)
break;
mr->range[0].min.tcp.port = htons(port);
mr->range[0].max.tcp.port = htons(maxport);
return;
default:
break;
}
xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
}
static void REDIRECT_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->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_PORTS:
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
parse_ports(cb->arg, mr);
if (cb->xflags & F_RANDOM)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
case O_RANDOM:
if (cb->xflags & F_TO_PORTS)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" redir ports ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
}
static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
}
static struct xtables_target redirect_tg_reg = {
.name = "REDIRECT",
.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 = REDIRECT_help,
.init = REDIRECT_init,
.x6_parse = REDIRECT_parse,
.print = REDIRECT_print,
.save = REDIRECT_save,
.x6_options = REDIRECT_opts,
};
void _init(void)
{
xtables_register_target(&redirect_tg_reg);
}
/* Shared library add-on to iptables to add customized REJECT support.
*
* (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
#include <linux/version.h>
/* If we are compiling against a kernel that does not support
* IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
* The result will be a plain DROP of the packet instead of
* reject. -- Maciej Soltysiak <solt@dns.toxicfilms.tv>
*/
#ifndef IPT_ICMP_ADMIN_PROHIBITED
#define IPT_ICMP_ADMIN_PROHIBITED IPT_TCP_RESET + 1
#endif
struct reject_names {
const char *name;
const char *alias;
enum ipt_reject_with with;
const char *desc;
};
enum {
O_REJECT_WITH = 0,
};
static const struct reject_names reject_table[] = {
{"icmp-net-unreachable", "net-unreach",
IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
{"icmp-host-unreachable", "host-unreach",
IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
{"icmp-proto-unreachable", "proto-unreach",
IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
{"icmp-port-unreachable", "port-unreach",
IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
#if 0
{"echo-reply", "echoreply",
IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
#endif
{"icmp-net-prohibited", "net-prohib",
IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
{"icmp-host-prohibited", "host-prohib",
IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
{"tcp-reset", "tcp-rst",
IPT_TCP_RESET, "TCP RST packet"},
{"icmp-admin-prohibited", "admin-prohib",
IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
};
static void
print_reject_types(void)
{
unsigned int i;
printf("Valid reject types:\n");
for (i = 0; i < ARRAY_SIZE(reject_table); ++i) {
printf(" %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
printf(" %-25s\talias\n", reject_table[i].alias);
}
printf("\n");
}
static void REJECT_help(void)
{
printf(
"REJECT target options:\n"
"--reject-with type drop input packet and send back\n"
" a reply packet according to type:\n");
print_reject_types();
printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
}
static const struct xt_option_entry REJECT_opts[] = {
{.name = "reject-with", .id = O_REJECT_WITH, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
static void REJECT_init(struct xt_entry_target *t)
{
struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
/* default */
reject->with = IPT_ICMP_PORT_UNREACHABLE;
}
static void REJECT_parse(struct xt_option_call *cb)
{
struct ipt_reject_info *reject = cb->data;
unsigned int i;
xtables_option_parse(cb);
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (strncasecmp(reject_table[i].name,
cb->arg, strlen(cb->arg)) == 0 ||
strncasecmp(reject_table[i].alias,
cb->arg, strlen(cb->arg)) == 0) {
reject->with = reject_table[i].with;
return;
}
/* This due to be dropped late in 2.4 pre-release cycle --RR */
if (strncasecmp("echo-reply", cb->arg, strlen(cb->arg)) == 0 ||
strncasecmp("echoreply", cb->arg, strlen(cb->arg)) == 0)
fprintf(stderr, "--reject-with echo-reply no longer"
" supported\n");
xtables_error(PARAMETER_PROBLEM,
"unknown reject type \"%s\"", cb->arg);
}
static void REJECT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_reject_info *reject
= (const struct ipt_reject_info *)target->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (reject_table[i].with == reject->with)
break;
printf(" reject-with %s", reject_table[i].name);
}
static void REJECT_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_reject_info *reject
= (const struct ipt_reject_info *)target->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (reject_table[i].with == reject->with)
break;
printf(" --reject-with %s", reject_table[i].name);
}
static struct xtables_target reject_tg_reg = {
.name = "REJECT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_reject_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_reject_info)),
.help = REJECT_help,
.init = REJECT_init,
.print = REJECT_print,
.save = REJECT_save,
.x6_parse = REJECT_parse,
.x6_options = REJECT_opts,
};
void _init(void)
{
xtables_register_target(&reject_tg_reg);
}
This is used to send back an error packet in response to the matched
packet: otherwise it is equivalent to
.B DROP
so it is a terminating TARGET, ending rule traversal.
This target is only valid in the
.BR INPUT ,
.B FORWARD
and
.B OUTPUT
chains, and user-defined chains which are only called from those
chains. The following option controls the nature of the error packet
returned:
.TP
\fB\-\-reject\-with\fP \fItype\fP
The type given can be
\fBicmp\-net\-unreachable\fP,
\fBicmp\-host\-unreachable\fP,
\fBicmp\-port\-unreachable\fP,
\fBicmp\-proto\-unreachable\fP,
\fBicmp\-net\-prohibited\fP,
\fBicmp\-host\-prohibited\fP, or
\fBicmp\-admin\-prohibited\fP (*),
which return the appropriate ICMP error message (\fBicmp\-port\-unreachable\fP is
the default). The option
\fBtcp\-reset\fP
can be used on rules which only match the TCP protocol: this causes a
TCP RST packet to be sent back. This is mainly useful for blocking
.I ident
(113/tcp) probes which frequently occur when sending mail to broken mail
hosts (which won't accept your mail otherwise).
.PP
(*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter_ipv4/ipt_SAME.h>
enum {
O_TO_ADDR = 0,
O_NODST,
O_RANDOM,
F_TO_ADDR = 1 << O_TO_ADDR,
F_RANDOM = 1 << O_RANDOM,
};
static void SAME_help(void)
{
printf(
"SAME target options:\n"
" --to <ipaddr>-<ipaddr>\n"
" Addresses to map source to.\n"
" May be specified more than\n"
" once for multiple ranges.\n"
" --nodst\n"
" Don't use destination-ip in\n"
" source selection\n"
" --random\n"
" Randomize source port\n");
}
static const struct xt_option_entry SAME_opts[] = {
{.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING,
.flags = XTOPT_MAND},
{.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
/* Parses range of IPs */
static void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range)
{
char *dash, *arg;
const struct in_addr *ip;
arg = strdup(orig_arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(arg, '-');
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;
if (dash)
if (range->min_ip > range->max_ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
arg, dash+1);
free(arg);
}
static void SAME_parse(struct xt_option_call *cb)
{
struct ipt_same_info *mr = cb->data;
unsigned int count;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_ADDR:
if (mr->rangesize == IPT_SAME_MAX_RANGE)
xtables_error(PARAMETER_PROBLEM,
"Too many ranges specified, maximum "
"is %i ranges.\n",
IPT_SAME_MAX_RANGE);
parse_to(cb->arg, &mr->range[mr->rangesize]);
mr->rangesize++;
break;
case O_NODST:
mr->info |= IPT_SAME_NODST;
break;
case O_RANDOM:
for (count=0; count < mr->rangesize; count++)
mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void SAME_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_ADDR | F_RANDOM;
struct ipt_same_info *mr = cb->data;
unsigned int count;
if ((cb->xflags & f) == f)
for (count = 0; count < mr->rangesize; ++count)
mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void SAME_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
unsigned int count;
const struct ipt_same_info *mr = (const void *)target->data;
int random_selection = 0;
printf(" same:");
for (count = 0; count < mr->rangesize; count++) {
const struct nf_nat_ipv4_range *r = &mr->range[count];
struct in_addr a;
a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
a.s_addr = r->max_ip;
if (r->min_ip != r->max_ip)
printf("-%s", xtables_ipaddr_to_numeric(&a));
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
random_selection = 1;
}
if (mr->info & IPT_SAME_NODST)
printf(" nodst");
if (random_selection)
printf(" random");
}
static void SAME_save(const void *ip, const struct xt_entry_target *target)
{
unsigned int count;
const struct ipt_same_info *mr = (const void *)target->data;
int random_selection = 0;
for (count = 0; count < mr->rangesize; count++) {
const struct nf_nat_ipv4_range *r = &mr->range[count];
struct in_addr a;
a.s_addr = r->min_ip;
printf(" --to %s", xtables_ipaddr_to_numeric(&a));
a.s_addr = r->max_ip;
if (r->min_ip != r->max_ip)
printf("-%s", xtables_ipaddr_to_numeric(&a));
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
random_selection = 1;
}
if (mr->info & IPT_SAME_NODST)
printf(" --nodst");
if (random_selection)
printf(" --random");
}
static struct xtables_target same_tg_reg = {
.name = "SAME",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_same_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
.help = SAME_help,
.x6_parse = SAME_parse,
.x6_fcheck = SAME_fcheck,
.print = SAME_print,
.save = SAME_save,
.x6_options = SAME_opts,
};
void _init(void)
{
xtables_register_target(&same_tg_reg);
}
Similar to SNAT/DNAT depending on chain: it takes a range of addresses
(`\-\-to 1.2.3.4\-1.2.3.7') and gives a client the same
source-/destination-address for each connection.
.PP
N.B.: The DNAT target's \fB\-\-persistent\fP option replaced the SAME target.
.TP
\fB\-\-to\fP \fIipaddr\fP[\fB\-\fP\fIipaddr\fP]
Addresses to map source to. May be specified more than once for
multiple ranges.
.TP
\fB\-\-nodst\fP
Don't use the destination-ip in the calculations when selecting the
new source-ip
.TP
\fB\-\-random\fP
Port mapping will be forcibly randomized to avoid attacks based on
port prediction (kernel >= 2.6.21).
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <iptables.h>
#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_SRC = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_SRC,
F_TO_SRC = 1 << O_TO_SRC,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_SRC = 1 << O_X_TO_SRC,
};
/* Source 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 SNAT_help(void)
{
printf(
"SNAT target options:\n"
" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map source to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry SNAT_opts[] = {
{.name = "to-source", .id = O_TO_SRC, .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 SNAT_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_SRC:
if (cb->xflags & F_X_TO_SRC) {
if (!kernel_version)
get_kernel_version();
if (kernel_version > LINUX_VERSION(2, 6, 10))
xtables_error(PARAMETER_PROBLEM,
"SNAT: Multiple --to-source not supported");
}
*cb->target = parse_to(cb->arg, portok, info);
cb->xflags |= F_X_TO_SRC;
break;
case O_PERSISTENT:
info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
static void SNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_SRC | 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 SNAT_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 SNAT_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-source ");
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 snat_tg_reg = {
.name = "SNAT",
.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 = SNAT_help,
.x6_parse = SNAT_parse,
.x6_fcheck = SNAT_fcheck,
.print = SNAT_print,
.save = SNAT_save,
.x6_options = SNAT_opts,
};
void _init(void)
{
xtables_register_target(&snat_tg_reg);
}
/* Shared library add-on to iptables for the TTL target
* (C) 2000 by Harald Welte <laforge@gnumonks.org>
*
* This program is distributed under the terms of GNU GPL
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_TTL.h>
enum {
O_TTL_SET = 0,
O_TTL_INC,
O_TTL_DEC,
F_TTL_SET = 1 << O_TTL_SET,
F_TTL_INC = 1 << O_TTL_INC,
F_TTL_DEC = 1 << O_TTL_DEC,
F_ANY = F_TTL_SET | F_TTL_INC | F_TTL_DEC,
};
#define s struct ipt_TTL_info
static const struct xt_option_entry TTL_opts[] = {
{.name = "ttl-set", .type = XTTYPE_UINT8, .id = O_TTL_SET,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl)},
{.name = "ttl-dec", .type = XTTYPE_UINT8, .id = O_TTL_DEC,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl),
.min = 1},
{.name = "ttl-inc", .type = XTTYPE_UINT8, .id = O_TTL_INC,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl),
.min = 1},
XTOPT_TABLEEND,
};
#undef s
static void TTL_help(void)
{
printf(
"TTL target options\n"
" --ttl-set value Set TTL to <value 0-255>\n"
" --ttl-dec value Decrement TTL by <value 1-255>\n"
" --ttl-inc value Increment TTL by <value 1-255>\n");
}
static void TTL_parse(struct xt_option_call *cb)
{
struct ipt_TTL_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TTL_SET:
info->mode = IPT_TTL_SET;
break;
case O_TTL_DEC:
info->mode = IPT_TTL_DEC;
break;
case O_TTL_INC:
info->mode = IPT_TTL_INC;
break;
}
}
static void TTL_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_ANY))
xtables_error(PARAMETER_PROBLEM,
"TTL: You must specify an action");
}
static void TTL_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_TTL_info *info =
(struct ipt_TTL_info *) target->data;
switch (info->mode) {
case IPT_TTL_SET:
printf(" --ttl-set");
break;
case IPT_TTL_DEC:
printf(" --ttl-dec");
break;
case IPT_TTL_INC:
printf(" --ttl-inc");
break;
}
printf(" %u", info->ttl);
}
static void TTL_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_TTL_info *info =
(struct ipt_TTL_info *) target->data;
printf(" TTL ");
switch (info->mode) {
case IPT_TTL_SET:
printf("set to");
break;
case IPT_TTL_DEC:
printf("decrement by");
break;
case IPT_TTL_INC:
printf("increment by");
break;
}
printf(" %u", info->ttl);
}
static struct xtables_target ttl_tg_reg = {
.name = "TTL",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_TTL_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_TTL_info)),
.help = TTL_help,
.print = TTL_print,
.save = TTL_save,
.x6_parse = TTL_parse,
.x6_fcheck = TTL_check,
.x6_options = TTL_opts,
};
void _init(void)
{
xtables_register_target(&ttl_tg_reg);
}
This is used to modify the IPv4 TTL header field. The TTL field determines
how many hops (routers) a packet can traverse until it's time to live is
exceeded.
.PP
Setting or incrementing the TTL field can potentially be very dangerous,
so it should be avoided at any cost. This target is only valid in
.B mangle
table.
.PP
.B Don't ever set or increment the value on packets that leave your local network!
.TP
\fB\-\-ttl\-set\fP \fIvalue\fP
Set the TTL value to `value'.
.TP
\fB\-\-ttl\-dec\fP \fIvalue\fP
Decrement the TTL value `value' times.
.TP
\fB\-\-ttl\-inc\fP \fIvalue\fP
Increment the TTL value `value' times.
/* Shared library add-on to iptables to add ULOG support.
*
* (C) 2000 by Harald Welte <laforge@gnumonks.org>
*
* multipart netlink support based on ideas by Sebastian Zander
* <zander@fokus.gmd.de>
*
* This software is released under the terms of GNU GPL
*
* libipt_ULOG.c,v 1.7 2001/01/30 11:55:02 laforge Exp
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
/* For 64bit kernel / 32bit userspace */
#include <linux/netfilter_ipv4/ipt_ULOG.h>
enum {
O_ULOG_NLGROUP = 0,
O_ULOG_PREFIX,
O_ULOG_CPRANGE,
O_ULOG_QTHR,
};
static void ULOG_help(void)
{
printf("ULOG target options:\n"
" --ulog-nlgroup nlgroup NETLINK group used for logging\n"
" --ulog-cprange size Bytes of each packet to be passed\n"
" --ulog-qthreshold Threshold of in-kernel queue\n"
" --ulog-prefix prefix Prefix log messages with this prefix.\n");
}
static const struct xt_option_entry ULOG_opts[] = {
{.name = "ulog-nlgroup", .id = O_ULOG_NLGROUP, .type = XTTYPE_UINT8,
.min = 1, .max = 32},
{.name = "ulog-prefix", .id = O_ULOG_PREFIX, .type = XTTYPE_STRING,
.flags = XTOPT_PUT, XTOPT_POINTER(struct ipt_ulog_info, prefix),
.min = 1},
{.name = "ulog-cprange", .id = O_ULOG_CPRANGE, .type = XTTYPE_UINT64},
{.name = "ulog-qthreshold", .id = O_ULOG_QTHR, .type = XTTYPE_UINT64,
.min = 1, .max = ULOG_MAX_QLEN},
XTOPT_TABLEEND,
};
static void ULOG_init(struct xt_entry_target *t)
{
struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) t->data;
loginfo->nl_group = ULOG_DEFAULT_NLGROUP;
loginfo->qthreshold = ULOG_DEFAULT_QTHRESHOLD;
}
static void ULOG_parse(struct xt_option_call *cb)
{
struct ipt_ulog_info *loginfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_ULOG_NLGROUP:
loginfo->nl_group = 1 << (cb->val.u8 - 1);
break;
case O_ULOG_PREFIX:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --ulog-prefix");
break;
case O_ULOG_CPRANGE:
loginfo->copy_range = cb->val.u64;
break;
case O_ULOG_QTHR:
loginfo->qthreshold = cb->val.u64;
break;
}
}
static void ULOG_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_ulog_info *loginfo
= (const struct ipt_ulog_info *) target->data;
if (strcmp(loginfo->prefix, "") != 0) {
fputs(" --ulog-prefix", stdout);
xtables_save_string(loginfo->prefix);
}
if (loginfo->nl_group != ULOG_DEFAULT_NLGROUP)
printf(" --ulog-nlgroup %d", ffs(loginfo->nl_group));
if (loginfo->copy_range)
printf(" --ulog-cprange %u", (unsigned int)loginfo->copy_range);
if (loginfo->qthreshold != ULOG_DEFAULT_QTHRESHOLD)
printf(" --ulog-qthreshold %u", (unsigned int)loginfo->qthreshold);
}
static void ULOG_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_ulog_info *loginfo
= (const struct ipt_ulog_info *) target->data;
printf(" ULOG ");
printf("copy_range %u nlgroup %d", (unsigned int)loginfo->copy_range,
ffs(loginfo->nl_group));
if (strcmp(loginfo->prefix, "") != 0)
printf(" prefix \"%s\"", loginfo->prefix);
printf(" queue_threshold %u", (unsigned int)loginfo->qthreshold);
}
static struct xtables_target ulog_tg_reg = {
.name = "ULOG",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_ulog_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ulog_info)),
.help = ULOG_help,
.init = ULOG_init,
.print = ULOG_print,
.save = ULOG_save,
.x6_parse = ULOG_parse,
.x6_options = ULOG_opts,
};
void _init(void)
{
xtables_register_target(&ulog_tg_reg);
}
This is the deprecated ipv4-only predecessor of the NFLOG target.
It provides userspace logging of matching packets. When this
target is set for a rule, the Linux kernel will multicast this packet
through a
.IR netlink
socket. One or more userspace processes may then subscribe to various
multicast groups and receive the packets.
Like LOG, this is a "non-terminating target", i.e. rule traversal
continues at the next rule.
.TP
\fB\-\-ulog\-nlgroup\fP \fInlgroup\fP
This specifies the netlink group (1-32) to which the packet is sent.
Default value is 1.
.TP
\fB\-\-ulog\-prefix\fP \fIprefix\fP
Prefix log messages with the specified prefix; up to 32 characters
long, and useful for distinguishing messages in the logs.
.TP
\fB\-\-ulog\-cprange\fP \fIsize\fP
Number of bytes to be copied to userspace. A value of 0 always copies
the entire packet, regardless of its size. Default is 0.
.TP
\fB\-\-ulog\-qthreshold\fP \fIsize\fP
Number of packet to queue inside kernel. Setting this value to, e.g. 10
accumulates ten packets inside the kernel and transmits them as one
netlink multipart message to userspace. Default is 1 (for backwards
compatibility).
.br
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_ah.h>
enum {
O_AHSPI = 0,
};
static void ah_help(void)
{
printf(
"ah match options:\n"
"[!] --ahspi spi[:spi]\n"
" match spi (range)\n");
}
static const struct xt_option_entry ah_opts[] = {
{.name = "ahspi", .id = O_AHSPI, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct ipt_ah, spis)},
XTOPT_TABLEEND,
};
static void ah_parse(struct xt_option_call *cb)
{
struct ipt_ah *ahinfo = cb->data;
xtables_option_parse(cb);
if (cb->nvals == 1)
ahinfo->spis[1] = ahinfo->spis[0];
if (cb->invert)
ahinfo->invflags |= IPT_AH_INV_SPI;
}
static void
print_spis(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 ah_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_ah *ah = (struct ipt_ah *)match->data;
printf(" ah ");
print_spis("spi", ah->spis[0], ah->spis[1],
ah->invflags & IPT_AH_INV_SPI);
if (ah->invflags & ~IPT_AH_INV_MASK)
printf(" Unknown invflags: 0x%X",
ah->invflags & ~IPT_AH_INV_MASK);
}
static void ah_save(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_ah *ahinfo = (struct ipt_ah *)match->data;
if (!(ahinfo->spis[0] == 0
&& ahinfo->spis[1] == 0xFFFFFFFF)) {
printf("%s --ahspi ",
(ahinfo->invflags & IPT_AH_INV_SPI) ? " !" : "");
if (ahinfo->spis[0]
!= ahinfo->spis[1])
printf("%u:%u",
ahinfo->spis[0],
ahinfo->spis[1]);
else
printf("%u",
ahinfo->spis[0]);
}
}
static struct xtables_match ah_mt_reg = {
.name = "ah",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_ah)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ah)),
.help = ah_help,
.print = ah_print,
.save = ah_save,
.x6_parse = ah_parse,
.x6_options = ah_opts,
};
void
_init(void)
{
xtables_register_match(&ah_mt_reg);
}
This module matches the SPIs in Authentication header of IPsec packets.
.TP
[\fB!\fP] \fB\-\-ahspi\fP \fIspi\fP[\fB:\fP\fIspi\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_ipv4/ip_tables.h>
/* special hack for icmp-type 'any':
* Up to kernel <=2.4.20 the problem was:
* '-p icmp ' matches all icmp packets
* '-p icmp -m icmp' matches _only_ ICMP type 0 :(
* This is now fixed by initializing the field * to icmp type 0xFF
* See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37
*/
enum {
O_ICMP_TYPE = 0,
};
struct icmp_names {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
};
static const struct icmp_names icmp_codes[] = {
{ "any", 0xFF, 0, 0xFF },
{ "echo-reply", 0, 0, 0xFF },
/* Alias */ { "pong", 0, 0, 0xFF },
{ "destination-unreachable", 3, 0, 0xFF },
{ "network-unreachable", 3, 0, 0 },
{ "host-unreachable", 3, 1, 1 },
{ "protocol-unreachable", 3, 2, 2 },
{ "port-unreachable", 3, 3, 3 },
{ "fragmentation-needed", 3, 4, 4 },
{ "source-route-failed", 3, 5, 5 },
{ "network-unknown", 3, 6, 6 },
{ "host-unknown", 3, 7, 7 },
{ "network-prohibited", 3, 9, 9 },
{ "host-prohibited", 3, 10, 10 },
{ "TOS-network-unreachable", 3, 11, 11 },
{ "TOS-host-unreachable", 3, 12, 12 },
{ "communication-prohibited", 3, 13, 13 },
{ "host-precedence-violation", 3, 14, 14 },
{ "precedence-cutoff", 3, 15, 15 },
{ "source-quench", 4, 0, 0xFF },
{ "redirect", 5, 0, 0xFF },
{ "network-redirect", 5, 0, 0 },
{ "host-redirect", 5, 1, 1 },
{ "TOS-network-redirect", 5, 2, 2 },
{ "TOS-host-redirect", 5, 3, 3 },
{ "echo-request", 8, 0, 0xFF },
/* Alias */ { "ping", 8, 0, 0xFF },
{ "router-advertisement", 9, 0, 0xFF },
{ "router-solicitation", 10, 0, 0xFF },
{ "time-exceeded", 11, 0, 0xFF },
/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
{ "ttl-zero-during-transit", 11, 0, 0 },
{ "ttl-zero-during-reassembly", 11, 1, 1 },
{ "parameter-problem", 12, 0, 0xFF },
{ "ip-header-bad", 12, 0, 0 },
{ "required-option-missing", 12, 1, 1 },
{ "timestamp-request", 13, 0, 0xFF },
{ "timestamp-reply", 14, 0, 0xFF },
{ "address-mask-request", 17, 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)
{
printf(
"icmp match options:\n"
"[!] --icmp-type typename match icmp type\n"
"[!] --icmp-type type[/code] (or numeric type or type/code)\n");
print_icmptypes();
}
static const struct xt_option_entry icmp_opts[] = {
{.name = "icmp-type", .id = O_ICMP_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void
parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[])
{
static const unsigned int limit = ARRAY_SIZE(icmp_codes);
unsigned int match = limit;
unsigned int i;
for (i = 0; i < limit; i++) {
if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
== 0) {
if (match != limit)
xtables_error(PARAMETER_PROBLEM,
"Ambiguous ICMP type `%s':"
" `%s' or `%s'?",
icmptype,
icmp_codes[match].name,
icmp_codes[i].name);
match = i;
}
}
if (match != limit) {
*type = icmp_codes[match].type;
code[0] = icmp_codes[match].code_min;
code[1] = icmp_codes[match].code_max;
} else {
char *slash;
char buffer[strlen(icmptype) + 1];
unsigned int number;
strcpy(buffer, icmptype);
slash = strchr(buffer, '/');
if (slash)
*slash = '\0';
if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMP type `%s'\n", buffer);
*type = number;
if (slash) {
if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMP code `%s'\n",
slash+1);
code[0] = code[1] = number;
} else {
code[0] = 0;
code[1] = 0xFF;
}
}
}
static void icmp_init(struct xt_entry_match *m)
{
struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
icmpinfo->type = 0xFF;
icmpinfo->code[1] = 0xFF;
}
static void icmp_parse(struct xt_option_call *cb)
{
struct ipt_icmp *icmpinfo = cb->data;
xtables_option_parse(cb);
parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
if (cb->invert)
icmpinfo->invflags |= IPT_ICMP_INV;
}
static void print_icmptype(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(icmp_codes); ++i)
if (icmp_codes[i].type == type
&& icmp_codes[i].code_min == code_min
&& icmp_codes[i].code_max == code_max)
break;
if (i != ARRAY_SIZE(icmp_codes)) {
printf(" %s%s",
invert ? "!" : "",
icmp_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 icmp_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
printf(" icmp");
print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
icmp->invflags & IPT_ICMP_INV,
numeric);
if (icmp->invflags & ~IPT_ICMP_INV)
printf(" Unknown invflags: 0x%X",
icmp->invflags & ~IPT_ICMP_INV);
}
static void icmp_save(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
if (icmp->invflags & IPT_ICMP_INV)
printf(" !");
/* special hack for 'any' case */
if (icmp->type == 0xFF) {
printf(" --icmp-type any");
} else {
printf(" --icmp-type %u", icmp->type);
if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
printf("/%u", icmp->code[0]);
}
}
static struct xtables_match icmp_mt_reg = {
.name = "icmp",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_icmp)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_icmp)),
.help = icmp_help,
.init = icmp_init,
.print = icmp_print,
.save = icmp_save,
.x6_parse = icmp_parse,
.x6_options = icmp_opts,
};
void _init(void)
{
xtables_register_match(&icmp_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