const char *str, int8_t *dir);
extern struct error_record *ct_key_parse(const struct location *loc, const char *str,
unsigned int *key);
+extern struct error_record *ct_objtype_parse(const struct location *loc, const char *str, int *type);
extern struct stmt *notrack_stmt_alloc(const struct location *loc);
NFTA_FIB_F_PRESENT = 1 << 5, /* check existence only */
};
+enum nft_ct_helper_attributes {
+ NFTA_CT_HELPER_UNSPEC,
+ NFTA_CT_HELPER_NAME,
+ NFTA_CT_HELPER_L3PROTO,
+ NFTA_CT_HELPER_L4PROTO,
+ __NFTA_CT_HELPER_MAX,
+};
+#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+
#define NFT_OBJECT_UNSPEC 0
#define NFT_OBJECT_COUNTER 1
#define NFT_OBJECT_QUOTA 2
-#define __NFT_OBJECT_MAX 3
+#define NFT_OBJECT_CT_HELPER 3
+#define __NFT_OBJECT_MAX 4
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
uint32_t flags;
};
+struct ct {
+ char helper_name[16];
+ uint16_t l3proto;
+ uint8_t l4proto;
+};
+
/**
* struct obj - nftables stateful object statement
*
union {
struct counter counter;
struct quota quota;
+ struct ct ct;
};
};
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)
{
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;
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;
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;
%type <set> map_block_alloc map_block
%destructor { set_free($$); } map_block_alloc
-%type <obj> obj_block_alloc counter_block quota_block
+%type <obj> obj_block_alloc counter_block quota_block ct_block
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list
%destructor { expr_free($$); } exthdr_exists_expr
%type <val> exthdr_key
+%type <val> ct_l4protoname
+%type <string> ct_obj_kind
+%destructor { xfree($$); } ct_obj_kind
+
%%
input : /* empty */
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 */
}
;
+ct_block : /* empty */ { $$ = $<obj>-1; }
+ | ct_block common_block
+ | ct_block stmt_seperator
+ | ct_block ct_config
+ {
+ $$ = $1;
+ }
+ ;
+
+
type_identifier : STRING { $$ = $1; }
| MARK { $$ = xstrdup("mark"); }
| DSCP { $$ = xstrdup("dscp"); }
}
;
+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 = &$<obj>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
+ {
+ $<obj>0->ct.l3proto = $2;
+ }
+ ;
+
relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
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
{
#include <statement.h>
#include <rule.h>
#include <utils.h>
+#include <netdb.h>
#include <netlink.h>
#include <libnftnl/common.h>
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)
{
}
}
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;
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];
}
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)
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);
}