From 5ca4eb30d62e0ab2768d64de5c70931292213338 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 21 Feb 2017 18:11:31 +0100 Subject: src: add initial ct helper support This adds initial support for defining conntrack helper objects which can then be assigned to connections using the objref infrastructure: table ip filter { ct helper ftp-standard { type "ftp" protocol tcp } chain y { tcp dport 21 ct helper set "ftp-standard" } } Signed-off-by: Florian Westphal Acked-by: Pablo Neira Ayuso --- src/ct.c | 10 ++++++++ src/netlink.c | 16 ++++++++++++ src/parser_bison.y | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/rule.c | 21 +++++++++++++++- src/statement.c | 10 +++++++- 5 files changed, 127 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ct.c b/src/ct.c index 83fceff6..fd8ca87a 100644 --- a/src/ct.c +++ b/src/ct.c @@ -353,6 +353,16 @@ struct error_record *ct_key_parse(const struct location *loc, const char *str, return error(loc, "syntax error, unexpected %s, known keys are %s", str, buf); } +struct error_record *ct_objtype_parse(const struct location *loc, const char *str, int *type) +{ + if (strcmp(str, "helper") == 0) { + *type = NFT_OBJECT_CT_HELPER; + return NULL; + } + + return error(loc, "unknown ct class '%s', want 'helper'", str); +} + struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key, int8_t direction) { diff --git a/src/netlink.c b/src/netlink.c index fb6d2876..6fbb67da 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -317,6 +317,15 @@ alloc_nftnl_obj(const struct handle *h, struct obj *obj) nftnl_obj_set_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS, obj->quota.flags); break; + case NFT_OBJECT_CT_HELPER: + nftnl_obj_set_str(nlo, NFTNL_OBJ_CT_HELPER_NAME, + obj->ct.helper_name); + nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO, + obj->ct.l4proto); + if (obj->ct.l3proto) + nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO, + obj->ct.l3proto); + break; default: BUG("Unknown type %d\n", obj->type); break; @@ -1814,6 +1823,13 @@ static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx, nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED); obj->quota.flags = nftnl_obj_get_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS); + break; + case NFT_OBJECT_CT_HELPER: + snprintf(obj->ct.helper_name, sizeof(obj->ct.helper_name), "%s", + nftnl_obj_get_str(nlo, NFTNL_OBJ_CT_HELPER_NAME)); + obj->ct.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO); + obj->ct.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO); + break; } obj->type = type; diff --git a/src/parser_bison.y b/src/parser_bison.y index 12a6e646..2cf732ce 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -136,6 +136,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) struct obj *obj; struct counter *counter; struct quota *quota; + struct ct *ct; const struct datatype *datatype; struct handle_spec handle_spec; struct position_spec position_spec; @@ -494,7 +495,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) %type map_block_alloc map_block %destructor { set_free($$); } map_block_alloc -%type obj_block_alloc counter_block quota_block +%type obj_block_alloc counter_block quota_block ct_block %destructor { obj_free($$); } obj_block_alloc %type stmt_list @@ -665,6 +666,10 @@ static void location_update(struct location *loc, struct location *rhs, int n) %destructor { expr_free($$); } exthdr_exists_expr %type exthdr_key +%type ct_l4protoname +%type ct_obj_kind +%destructor { xfree($$); } ct_obj_kind + %% input : /* empty */ @@ -1191,6 +1196,24 @@ table_block : /* empty */ { $$ = $-1; } list_add_tail(&$4->list, &$1->objs); $$ = $1; } + | table_block CT ct_obj_kind obj_identifier obj_block_alloc '{' ct_block '}' stmt_seperator + { + struct error_record *erec; + int type; + + erec = ct_objtype_parse(&@$, $3, &type); + if (erec != NULL) { + erec_queue(erec, state->msgs); + YYERROR; + } + + $5->location = @4; + $5->type = type; + handle_merge(&$5->handle, &$4); + handle_free(&$4); + list_add_tail(&$5->list, &$1->objs); + $$ = $1; + } ; chain_block_alloc : /* empty */ @@ -1385,6 +1408,16 @@ quota_block : /* empty */ { $$ = $-1; } } ; +ct_block : /* empty */ { $$ = $-1; } + | ct_block common_block + | ct_block stmt_seperator + | ct_block ct_config + { + $$ = $1; + } + ; + + type_identifier : STRING { $$ = $1; } | MARK { $$ = xstrdup("mark"); } | DSCP { $$ = xstrdup("dscp"); } @@ -2578,6 +2611,34 @@ quota_obj : quota_config } ; +ct_obj_kind : STRING { $$ = $1; } + ; + +ct_l4protoname : TCP { $$ = IPPROTO_TCP; } + | UDP { $$ = IPPROTO_UDP; } + ; + +ct_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_seperator + { + struct ct *ct; + int ret; + + ct = &$0->ct; + + ret = snprintf(ct->helper_name, sizeof(ct->helper_name), "%s", $2); + if (ret <= 0 || ret >= (int)sizeof(ct->helper_name)) { + erec_queue(error(&@2, "invalid name '%s', max length is %u\n", $2, (int)sizeof(ct->helper_name)), state->msgs); + YYERROR; + } + + ct->l4proto = $4; + } + | L3PROTOCOL family_spec_explicit stmt_seperator + { + $0->ct.l3proto = $2; + } + ; + relational_expr : expr /* implicit */ rhs_expr { $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2); @@ -3037,7 +3098,16 @@ ct_stmt : CT ct_key SET expr YYERROR; } - $$ = ct_stmt_alloc(&@$, key, -1, $4); + switch (key) { + case NFT_CT_HELPER: + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_CT_HELPER; + $$->objref.expr = $4; + break; + default: + $$ = ct_stmt_alloc(&@$, key, -1, $4); + break; + } } | CT STRING ct_key_dir_optional SET expr { diff --git a/src/rule.c b/src/rule.c index 056d5ce8..17c20f35 100644 --- a/src/rule.c +++ b/src/rule.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1172,6 +1173,16 @@ struct obj *obj_lookup(const struct table *table, const char *name, return NULL; } +static void print_proto_name_proto(uint8_t l4) +{ + const struct protoent *p = getprotobynumber(l4); + + if (p) + printf("%s\n", p->p_name); + else + printf("%d\n", l4); +} + static void obj_print_data(const struct obj *obj, struct print_fmt_options *opts) { @@ -1202,6 +1213,13 @@ static void obj_print_data(const struct obj *obj, } } break; + case NFT_OBJECT_CT_HELPER: { + printf("ct helper %s {\n", obj->handle.obj); + printf("\t\ttype \"%s\" protocol ", obj->ct.helper_name); + print_proto_name_proto(obj->ct.l4proto); + printf("\t\tl3proto %s", family2str(obj->ct.l3proto)); + break; + } default: printf("unknown {%s", opts->nl); break; @@ -1211,11 +1229,12 @@ static void obj_print_data(const struct obj *obj, static const char *obj_type_name_array[] = { [NFT_OBJECT_COUNTER] = "counter", [NFT_OBJECT_QUOTA] = "quota", + [NFT_OBJECT_CT_HELPER] = "", }; const char *obj_type_name(enum stmt_types type) { - assert(type <= NFT_OBJECT_QUOTA && obj_type_name_array[type]); + assert(type <= NFT_OBJECT_CT_HELPER && obj_type_name_array[type]); return obj_type_name_array[type]; } diff --git a/src/statement.c b/src/statement.c index 7ffd25f9..d824dc0b 100644 --- a/src/statement.c +++ b/src/statement.c @@ -174,6 +174,7 @@ struct stmt *counter_stmt_alloc(const struct location *loc) static const char *objref_type[NFT_OBJECT_MAX + 1] = { [NFT_OBJECT_COUNTER] = "counter", [NFT_OBJECT_QUOTA] = "quota", + [NFT_OBJECT_CT_HELPER] = "cthelper", }; static const char *objref_type_name(uint32_t type) @@ -186,7 +187,14 @@ static const char *objref_type_name(uint32_t type) static void objref_stmt_print(const struct stmt *stmt) { - printf("%s name ", objref_type_name(stmt->objref.type)); + switch (stmt->objref.type) { + case NFT_OBJECT_CT_HELPER: + printf("ct helper set "); + break; + default: + printf("%s name ", objref_type_name(stmt->objref.type)); + break; + } expr_print(stmt->objref.expr); } -- cgit v1.2.3