Commit c2234165 authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

Merge tag 'upstream/1.6.1'

Upstream version 1.6.1
parents 475b9a99 f1f129da
:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
*mangle
-j DSCP --set-dscp 0;=;OK
-j DSCP --set-dscp 0x3f;=;OK
-j DSCP --set-dscp -1;;FAIL
-j DSCP --set-dscp 0x40;;FAIL
-j DSCP --set-dscp 0x3f --set-dscp-class CS0;;FAIL
-j DSCP --set-dscp-class CS0;-j DSCP --set-dscp 0x00;OK
-j DSCP --set-dscp-class BE;-j DSCP --set-dscp 0x00;OK
-j DSCP --set-dscp-class EF;-j DSCP --set-dscp 0x2e;OK
-j DSCP;;FAIL
:INPUT,FORWARD,OUTPUT
-j HMARK;;FAIL
-j HMARK --hmark-src-prefix 32 --hmark-rnd 0x00000004 --hmark-mod 42;=;OK
-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-spi-mask 0x00000004 --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
-j HMARK --hmark-src-prefix 1 --hmark-dst-prefix 2 --hmark-sport-mask 0x0003 --hmark-dport-mask 0x0004 --hmark-proto-mask 0x05 --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
# cannot mix in spi mask:
-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct --hmark-spi-mask 4;;FAIL
:INPUT,FORWARD,OUTPUT
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
:INPUT,FORWARD,OUTPUT
-j LED;;FAIL
-j LED --led-trigger-id "foo";=;OK
-j LED --led-trigger-id "foo" --led-delay 42 --led-always-blink;=;OK
:INPUT,FORWARD,OUTPUT
-j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK
-j MARK --set-xmark 0;=;OK
-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK
-j MARK --set-xmark 4294967296;;FAIL
-j MARK --set-xmark -1;;FAIL
-j MARK;;FAIL
:INPUT,FORWARD,OUTPUT
-j NFLOG --nflog-group 1;=;OK
-j NFLOG --nflog-group 65535;=;OK
-j NFLOG --nflog-group 65536;;FAIL
-j NFLOG --nflog-group 0;-j NFLOG;OK
-j NFLOG --nflog-range 1;=;OK
-j NFLOG --nflog-range 4294967295;=;OK
-j NFLOG --nflog-range 4294967296;;FAIL
-j NFLOG --nflog-range -1;;FAIL
-j NFLOG --nflog-size 0;=;OK
-j NFLOG --nflog-size 1;=;OK
-j NFLOG --nflog-size 4294967295;=;OK
-j NFLOG --nflog-size 4294967296;;FAIL
-j NFLOG --nflog-size -1;;FAIL
# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
-j NFLOG --nflog-threshold 1;=;OK
# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
# -j NFLOG --nflog-threshold 0;;FAIL
-j NFLOG --nflog-threshold 65535;=;OK
-j NFLOG --nflog-threshold 65536;;FAIL
-j NFLOG;=;OK
:INPUT,FORWARD,OUTPUT
-j NFQUEUE;=;OK
-j NFQUEUE --queue-num 0;=;OK
-j NFQUEUE --queue-num 65535;=;OK
-j NFQUEUE --queue-num 65536;;FAIL
-j NFQUEUE --queue-num -1;;FAIL
# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1?
# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535
# -j NFQUEUE --queue-balance 0:65535;=;OK
-j NFQUEUE --queue-balance 0:65536;;FAIL
-j NFQUEUE --queue-balance -1:65535;;FAIL
-j NFQUEUE --queue-num 10 --queue-bypass;=;OK
-j NFQUEUE --queue-balance 0:6 --queue-cpu-fanout --queue-bypass;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
-j NFQUEUE --queue-bypass --queue-balance 0:6 --queue-cpu-fanout;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
-j NFQUEUE --queue-balance 0:6 --queue-bypass;=;OK
-j NFQUEUE --queue-bypass;-j NFQUEUE --queue-num 0 --queue-bypass;OK
:PREROUTING,OUTPUT
*raw
# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
#-j NOTRACK;=;OK
:INPUT,FORWARD,OUTPUT
-j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms;=;OK
:INPUT,FORWARD,OUTPUT
# fails: foo does not exist
-j SET --add-set foo src,dst;;FAIL
:INPUT,FORWARD
-j SYNPROXY --sack-perm --timestamp --mss 1460 --wscale 9;;FAIL
-p tcp -m tcp --dport 42 -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 9 --mss 1460;=;OK
:FORWARD,OUTPUT,POSTROUTING
*mangle
-j TCPMSS;;FAIL
-p tcp -j TCPMSS --set-mss 42;;FAIL
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK
:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
*mangle
-j TCPOPTSTRIP;;FAIL
-p tcp -j TCPOPTSTRIP;=;OK
-p tcp -j TCPOPTSTRIP --strip-options 2,3,4,5,6,7;=;OK
-p tcp -j TCPOPTSTRIP --strip-options 0;;FAIL
-p tcp -j TCPOPTSTRIP --strip-options 1;;FAIL
-p tcp -j TCPOPTSTRIP --strip-options 1,2;;FAIL
:INPUT,FORWARD,OUTPUT
-j TEE --gateway 1.1.1.1;=;OK
-j TEE ! --gateway 1.1.1.1;;FAIL
-j TEE;;FAIL
:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
*mangle
-j TOS --set-tos 0x1f;=;OK
-j TOS --set-tos 0x1f/0x1f;=;OK
# maximum TOS is 0x1f (5 bits)
# ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff
# -j TOS --set-tos 0xff;;FAIL
-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK
-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK
-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK
-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK
-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK
-j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK
-j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK
-j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK
-j TOS;;FAIL
:PREROUTING
*mangle
-j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;;FAIL
-p udp -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK
-p tcp -m tcp --dport 2342 -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK
:PREROUTING,OUTPUT
*raw
-j TRACE;=;OK
:INPUT,FORWARD,OUTPUT
-m addrtype;;FAIL
-m addrtype --src-type wrong;;FAIL
-m addrtype --src-type UNSPEC;=;OK
-m addrtype --dst-type UNSPEC;=;OK
-m addrtype --src-type LOCAL --dst-type LOCAL;=;OK
-m addrtype --dst-type UNSPEC;=;OK
-m addrtype --limit-iface-in;;FAIL
-m addrtype --limit-iface-out;;FAIL
-m addrtype --limit-iface-in --limit-iface-out;;FAIL
-m addrtype --src-type LOCAL --limit-iface-in --limit-iface-out;;FAIL
:INPUT
-m addrtype --src-type LOCAL --limit-iface-in;=;OK
-m addrtype --dst-type LOCAL --limit-iface-in;=;OK
:OUTPUT
-m addrtype --src-type LOCAL --limit-iface-out;=;OK
-m addrtype --dst-type LOCAL --limit-iface-out;=;OK
......@@ -16,11 +16,17 @@
#include <sys/types.h>
#include <unistd.h>
#include <xtables.h>
#include "config.h"
#ifdef HAVE_LINUX_BPF_H
#include <linux/bpf.h>
#endif
#define BCODE_FILE_MAX_LEN_B 1024
enum {
O_BCODE_STDIN = 0,
O_OBJ_PINNED = 1,
};
static void bpf_help(void)
......@@ -28,7 +34,16 @@ static void bpf_help(void)
printf(
"bpf match options:\n"
"--bytecode <program> : a bpf program as generated by\n"
" `nfbpf_compiler RAW <filter>`\n");
" $(nfbpf_compile RAW '<filter>')\n");
}
static void bpf_help_v1(void)
{
printf(
"bpf match options:\n"
"--bytecode <program> : a bpf program as generated by\n"
" $(nfbpf_compile RAW '<filter>')\n"
"--object-pinned <bpf object> : a path to a pinned BPF object in bpf fs\n");
}
static const struct xt_option_entry bpf_opts[] = {
......@@ -36,23 +51,47 @@ static const struct xt_option_entry bpf_opts[] = {
XTOPT_TABLEEND,
};
static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
const char separator)
static const struct xt_option_entry bpf_opts_v1[] = {
{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
{.name = "object-pinned" , .id = O_OBJ_PINNED, .type = XTTYPE_STRING,
.flags = XTOPT_PUT, XTOPT_POINTER(struct xt_bpf_info_v1, path)},
XTOPT_TABLEEND,
};
static int bpf_obj_get(const char *filepath)
{
struct xt_bpf_info *bi = (void *) cb->data;
#if defined HAVE_LINUX_BPF_H && defined __NR_bpf
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = (__u64) filepath;
return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
#else
xtables_error(OTHER_PROBLEM,
"No bpf header, kernel headers too old?\n");
return -EINVAL;
#endif
}
static void bpf_parse_string(struct sock_filter *pc, __u16 *lenp, __u16 len_max,
const char *bpf_program)
{
const char separator = ',';
const char *token;
char sp;
int i;
__u16 len;
/* parse head: length. */
if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 ||
if (sscanf(bpf_program, "%hu%c", &len, &sp) != 2 ||
sp != separator)
xtables_error(PARAMETER_PROBLEM,
"bpf: error parsing program length");
if (!bi->bpf_program_num_elem)
if (!len)
xtables_error(PARAMETER_PROBLEM,
"bpf: illegal zero length program");
if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR)
if (len > len_max)
xtables_error(PARAMETER_PROBLEM,
"bpf: number of instructions exceeds maximum");
......@@ -60,62 +99,108 @@ static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
i = 0;
token = bpf_program;
while ((token = strchr(token, separator)) && (++token)[0]) {
if (i >= bi->bpf_program_num_elem)
if (i >= len)
xtables_error(PARAMETER_PROBLEM,
"bpf: real program length exceeds"
" the encoded length parameter");
if (sscanf(token, "%hu %hhu %hhu %u,",
&bi->bpf_program[i].code,
&bi->bpf_program[i].jt,
&bi->bpf_program[i].jf,
&bi->bpf_program[i].k) != 4)
&pc->code, &pc->jt, &pc->jf, &pc->k) != 4)
xtables_error(PARAMETER_PROBLEM,
"bpf: error at instr %d", i);
i++;
pc++;
}
if (i != bi->bpf_program_num_elem)
if (i != len)
xtables_error(PARAMETER_PROBLEM,
"bpf: parsed program length is less than the"
" encoded length parameter");
*lenp = len;
}
static void bpf_parse_obj_pinned(struct xt_bpf_info_v1 *bi,
const char *filepath)
{
bi->fd = bpf_obj_get(filepath);
if (bi->fd < 0)
xtables_error(PARAMETER_PROBLEM,
"bpf: failed to get bpf object");
/* Cannot close bi->fd explicitly. Rely on exit */
if (fcntl(bi->fd, F_SETFD, FD_CLOEXEC) == -1) {
xtables_error(OTHER_PROBLEM,
"Could not set close on exec: %s\n",
strerror(errno));
}
}
static void bpf_parse(struct xt_option_call *cb)
{
struct xt_bpf_info *bi = (void *) cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_BCODE_STDIN:
bpf_parse_string(cb, cb->arg, ',');
bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
ARRAY_SIZE(bi->bpf_program), cb->arg);
break;
default:
xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
}
}
static void bpf_print_code(const void *ip, const struct xt_entry_match *match)
static void bpf_parse_v1(struct xt_option_call *cb)
{
const struct xt_bpf_info *info = (void *) match->data;
int i;
struct xt_bpf_info_v1 *bi = (void *) cb->data;
for (i = 0; i < info->bpf_program_num_elem-1; i++)
printf("%hu %hhu %hhu %u,", info->bpf_program[i].code,
info->bpf_program[i].jt,
info->bpf_program[i].jf,
info->bpf_program[i].k);
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_BCODE_STDIN:
bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
ARRAY_SIZE(bi->bpf_program), cb->arg);
bi->mode = XT_BPF_MODE_BYTECODE;
break;
case O_OBJ_PINNED:
bpf_parse_obj_pinned(bi, cb->arg);
bi->mode = XT_BPF_MODE_FD_PINNED;
break;
default:
xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
}
}
printf("%hu %hhu %hhu %u", info->bpf_program[i].code,
info->bpf_program[i].jt,
info->bpf_program[i].jf,
info->bpf_program[i].k);
static void bpf_print_code(const struct sock_filter *pc, __u16 len, char tail)
{
for (; len; len--, pc++)
printf("%hu %hhu %hhu %u%c",
pc->code, pc->jt, pc->jf, pc->k,
len > 1 ? ',' : tail);
}
static void bpf_save_code(const struct sock_filter *pc, __u16 len)
{
printf(" --bytecode \"%hu,", len);
bpf_print_code(pc, len, '\"');
}
static void bpf_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_bpf_info *info = (void *) match->data;
printf(" --bytecode \"%hu,", info->bpf_program_num_elem);
bpf_print_code(ip, match);
printf("\"");
bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
}
static void bpf_save_v1(const void *ip, const struct xt_entry_match *match)
{
const struct xt_bpf_info_v1 *info = (void *) match->data;
if (info->mode == XT_BPF_MODE_BYTECODE)
bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
else if (info->mode == XT_BPF_MODE_FD_PINNED)
printf(" --object-pinned %s", info->path);
else
xtables_error(OTHER_PROBLEM, "unknown bpf mode");
}
static void bpf_fcheck(struct xt_fcheck_call *cb)
......@@ -125,17 +210,47 @@ static void bpf_fcheck(struct xt_fcheck_call *cb)
"bpf: missing --bytecode parameter");
}
static void bpf_fcheck_v1(struct xt_fcheck_call *cb)
{
const unsigned int bit_bcode = 1 << O_BCODE_STDIN;
const unsigned int bit_pinned = 1 << O_OBJ_PINNED;
unsigned int flags;
flags = cb->xflags & (bit_bcode | bit_pinned);
if (flags != bit_bcode && flags != bit_pinned)
xtables_error(PARAMETER_PROBLEM,
"bpf: one of --bytecode or --pinned is required");
}
static void bpf_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_bpf_info *info = (void *) match->data;
printf("match bpf ");
return bpf_print_code(ip, match);
bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
}
static struct xtables_match bpf_match = {
static void bpf_print_v1(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_bpf_info_v1 *info = (void *) match->data;
printf("match bpf ");
if (info->mode == XT_BPF_MODE_BYTECODE)
bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
else if (info->mode == XT_BPF_MODE_FD_PINNED)
printf("pinned %s", info->path);
else
printf("unknown");
}
static struct xtables_match bpf_matches[] = {
{
.family = NFPROTO_UNSPEC,
.name = "bpf",
.version = XTABLES_VERSION,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_bpf_info)),
.userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
.help = bpf_help,
......@@ -144,9 +259,24 @@ static struct xtables_match bpf_match = {
.x6_parse = bpf_parse,
.x6_fcheck = bpf_fcheck,
.x6_options = bpf_opts,
},
{
.family = NFPROTO_UNSPEC,
.name = "bpf",
.version = XTABLES_VERSION,
.revision = 1,
.size = XT_ALIGN(sizeof(struct xt_bpf_info_v1)),
.userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info_v1, filter)),
.help = bpf_help_v1,
.print = bpf_print_v1,
.save = bpf_save_v1,
.x6_parse = bpf_parse_v1,
.x6_fcheck = bpf_fcheck_v1,
.x6_options = bpf_opts_v1,
},
};
void _init(void)
{
xtables_register_match(&bpf_match);
xtables_register_matches(bpf_matches, ARRAY_SIZE(bpf_matches));
}
Match using Linux Socket Filter. Expects a BPF program in decimal format. This
is the format generated by the \fBnfbpf_compile\fP utility.
Match using Linux Socket Filter. Expects a path to an eBPF object or a cBPF
program in decimal format.
.TP
\fB\-\-object\-pinned\fP \fIpath\fP
Pass a path to a pinned eBPF object.
.PP
Applications load eBPF programs into the kernel with the bpf() system call and
BPF_PROG_LOAD command and can pin them in a virtual filesystem with BPF_OBJ_PIN.
To use a pinned object in iptables, mount the bpf filesystem using
.IP
mount \-t bpf bpf ${BPF_MOUNT}
.PP
then insert the filter in iptables by path:
.IP
iptables \-A OUTPUT \-m bpf \-\-object\-pinned ${BPF_MOUNT}/{PINNED_PATH} \-j ACCEPT
.TP
\fB\-\-bytecode\fP \fIcode\fP
Pass the BPF byte code format (described in the example below).
Pass the BPF byte code format as generated by the \fBnfbpf_compile\fP utility.
.PP
The code format is similar to the output of the tcpdump -ddd command: one line
that stores the number of instructions, followed by one line for each
......
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