For now it can only match sockets with IP(V6)_TRANSPARENT socket option set. Example: table inet sockin { chain sockchain { type filter hook prerouting priority -150; policy accept; socket transparent 1 mark set 0x00000001 nftrace set 1 counter packets 0 bytes 0 accept } } Signed-off-by: Máté Eckl <ecklm94@xxxxxxxxx> --- include/expression.h | 7 ++++ include/linux/netfilter/nf_tables.h | 28 ++++++++++++++ include/socket.h | 24 ++++++++++++ src/Makefile.am | 1 + src/evaluate.c | 7 ++++ src/netlink_delinearize.c | 17 +++++++++ src/netlink_linearize.c | 14 +++++++ src/parser_bison.y | 17 +++++++++ src/scanner.l | 3 ++ src/socket.c | 58 +++++++++++++++++++++++++++++ 10 files changed, 176 insertions(+) create mode 100644 include/socket.h create mode 100644 src/socket.c diff --git a/include/expression.h b/include/expression.h index 15af35e..2bb51e5 100644 --- a/include/expression.h +++ b/include/expression.h @@ -24,6 +24,7 @@ * @EXPR_PAYLOAD: payload expression * @EXPR_EXTHDR: exthdr expression * @EXPR_META: meta expression + * @EXPR_SOCKET: socket expression * @EXPR_CT: conntrack expression * @EXPR_CONCAT: concatenation * @EXPR_LIST: list of expressions @@ -50,6 +51,7 @@ enum expr_types { EXPR_PAYLOAD, EXPR_EXTHDR, EXPR_META, + EXPR_SOCKET, EXPR_CT, EXPR_CONCAT, EXPR_LIST, @@ -188,6 +190,7 @@ enum expr_flags { #include <rt.h> #include <hash.h> #include <ct.h> +#include <socket.h> /** * struct expr @@ -296,6 +299,10 @@ struct expr { enum nft_meta_keys key; enum proto_bases base; } meta; + struct { + /* SOCKET */ + enum nft_socket_keys key; + } socket; struct { /* EXPR_RT */ enum nft_rt_keys key; diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 9c71f02..96ab315 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -904,6 +904,34 @@ enum nft_rt_attributes { }; #define NFTA_RT_MAX (__NFTA_RT_MAX - 1) +/** + * enum nft_socket_attributes - nf_tables socket expression netlink attributes + * + * @NFTA_SOCKET_KEY: socket key to match + * @NFTA_SOCKET_DREG: destination register + */ +enum nft_socket_attributes { + NFTA_SOCKET_UNSPEC, + + NFTA_SOCKET_KEY, + NFTA_SOCKET_DREG, + + __NFTA_SOCKET_MAX +}; +#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) + +/* + * enum nft_socket_keys - nf_tables socket expression keys + * + * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option_ + */ +enum nft_socket_keys { + NFT_SOCKET_TRANSPARENT, + + __NFT_SOCKET_MAX +}; +#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) + /** * enum nft_ct_keys - nf_tables ct expression keys * diff --git a/include/socket.h b/include/socket.h new file mode 100644 index 0000000..a2ae9f1 --- /dev/null +++ b/include/socket.h @@ -0,0 +1,24 @@ +#ifndef NFTABLES_SOCKET_H +#define NFTABLES_SOCKET_H + +//#include <parser.h> + +/** + * struct rt_template - template for routing expressions + * + * @token: parser token for the expression + * @dtype: data type of the expression + * @len: length of the expression + * @byteorder: byteorder + */ +struct socket_template { + const char *token; + const struct datatype *dtype; + unsigned int len; + enum byteorder byteorder; +}; + +extern struct expr *socket_expr_alloc(const struct location *loc, + enum nft_socket_keys key); + +#endif /* NFTABLES_SOCKET_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 6db31c8..a4ad8cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -55,6 +55,7 @@ libnftables_la_SOURCES = \ services.c \ mergesort.c \ tcpopt.c \ + socket.c \ libnftables.c # yacc and lex generate dirty code diff --git a/src/evaluate.c b/src/evaluate.c index 4eb36e2..56fea26 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1712,6 +1712,11 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp) return expr_evaluate_primary(ctx, exprp); } +static int expr_evaluate_socket(struct eval_ctx *ctx, struct expr **exprp) +{ + return expr_evaluate_primary(ctx, exprp); +} + static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp) { struct expr *new = expr_clone((*exprp)->sym->expr); @@ -1749,6 +1754,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr) return expr_evaluate_primary(ctx, expr); case EXPR_META: return expr_evaluate_meta(ctx, expr); + case EXPR_SOCKET: + return expr_evaluate_socket(ctx, expr); case EXPR_FIB: return expr_evaluate_fib(ctx, expr); case EXPR_PAYLOAD: diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 8f4035a..639c102 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -615,6 +615,21 @@ static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx, netlink_set_register(ctx, dreg, expr); } +static void netlink_parse_socket(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + enum nft_registers dreg; + uint32_t key; + struct expr * expr; + + key = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_KEY); + expr = socket_expr_alloc(loc, key); + + dreg = netlink_parse_register(nle, NFTNL_EXPR_SOCKET_DREG); + netlink_set_register(ctx, dreg, expr); +} + static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) @@ -1292,6 +1307,7 @@ static const struct { { .name = "payload", .parse = netlink_parse_payload }, { .name = "exthdr", .parse = netlink_parse_exthdr }, { .name = "meta", .parse = netlink_parse_meta }, + { .name = "socket", .parse = netlink_parse_socket }, { .name = "rt", .parse = netlink_parse_rt }, { .name = "ct", .parse = netlink_parse_ct }, { .name = "counter", .parse = netlink_parse_counter }, @@ -1976,6 +1992,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) case EXPR_VERDICT: case EXPR_NUMGEN: case EXPR_FIB: + case EXPR_SOCKET: break; case EXPR_HASH: if (expr->hash.expr) diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 2ab8acc..05a1dbd 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -207,6 +207,18 @@ static void netlink_gen_rt(struct netlink_linearize_ctx *ctx, nftnl_rule_add_expr(ctx->nlr, nle); } +static void netlink_gen_socket(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("socket"); + netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg); + nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key); + nftnl_rule_add_expr(ctx->nlr, nle); +} + static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) @@ -694,6 +706,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx, return netlink_gen_hash(ctx, expr, dreg); case EXPR_FIB: return netlink_gen_fib(ctx, expr, dreg); + case EXPR_SOCKET: + return netlink_gen_socket(ctx, expr, dreg); default: BUG("unknown expression type %s\n", expr->ops->name); } diff --git a/src/parser_bison.y b/src/parser_bison.y index 0e3ee84..529224e 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -189,6 +189,9 @@ int nft_lex(void *, void *, void *); %token FIB "fib" +%token SOCKET "socket" +%token TRANSPARENT "transparent" + %token HOOK "hook" %token DEVICE "device" %token DEVICES "devices" @@ -692,6 +695,10 @@ int nft_lex(void *, void *, void *); %destructor { expr_free($$); } meta_expr %type <val> meta_key meta_key_qualified meta_key_unqualified numgen_type +%type <expr> socket_expr +%destructor { expr_free($$); } socket_expr +%type<val> socket_key + %type <val> nf_key_proto %type <expr> rt_expr @@ -2863,6 +2870,7 @@ primary_expr : symbol_expr { $$ = $1; } | exthdr_expr { $$ = $1; } | exthdr_exists_expr { $$ = $1; } | meta_expr { $$ = $1; } + | socket_expr { $$ = $1; } | rt_expr { $$ = $1; } | ct_expr { $$ = $1; } | numgen_expr { $$ = $1; } @@ -3540,6 +3548,15 @@ meta_stmt : META meta_key SET stmt_expr } ; +socket_expr : SOCKET socket_key + { + $$ = socket_expr_alloc(&@$, $2); + } + ; + +socket_key : TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; } + ; + offset_opt : /* empty */ { $$ = 0; } | OFFSET NUM { $$ = $2; } ; diff --git a/src/scanner.l b/src/scanner.l index 6a861cf..416bd27 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -258,6 +258,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "ruleset" { return RULESET; } "trace" { return TRACE; } +"socket" { return SOCKET; } +"transparent" { return TRANSPARENT;} + "accept" { return ACCEPT; } "drop" { return DROP; } "continue" { return CONTINUE; } diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..735deec --- /dev/null +++ b/src/socket.c @@ -0,0 +1,58 @@ +/* + * Socket expression/statement related definition and types. + * + * Copyright (c) 2018 Máté Eckl <ecklm94@xxxxxxxxx> + * + * 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. + */ + +#include <nftables.h> +#include <expression.h> +#include <socket.h> + +const struct socket_template socket_templates[] = { + [NFT_SOCKET_TRANSPARENT] = {.token = "transparent", + .dtype = &integer_type, + .len = 1 * BITS_PER_BYTE, + .byteorder = BYTEORDER_HOST_ENDIAN, + } +}; + +static void socket_expr_print(const struct expr *expr, struct output_ctx *octx) +{ + nft_print(octx, "socket %s", socket_templates[expr->socket.key].token); +} + +static bool socket_expr_cmp(const struct expr *e1, const struct expr *e2) +{ + return e1->socket.key == e2->socket.key; +} + +static void socket_expr_clone(struct expr *new, const struct expr *expr) +{ + new->socket.key = expr->socket.key; +} + +static const struct expr_ops socket_expr_ops = { + .type = EXPR_SOCKET, + .name = "socket", + .print = socket_expr_print, + .cmp = socket_expr_cmp, + .clone = socket_expr_clone, +}; + +struct expr *socket_expr_alloc(const struct location *loc, enum nft_socket_keys key) +{ + const struct socket_template *tmpl = &socket_templates[key]; + struct expr *expr; + + expr = expr_alloc(loc, &socket_expr_ops, tmpl->dtype, + tmpl->byteorder, tmpl->len); + expr->socket.key = key; + + return expr; +} + + -- ecklm -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html