PARSER_SC_SECMARK,
PARSER_SC_TCP,
PARSER_SC_TYPE,
+ PARSER_SC_TUNNEL,
PARSER_SC_VLAN,
PARSER_SC_XT,
PARSER_SC_CMD_DESTROY,
char ctx[NFT_SECMARK_CTX_MAXLEN];
};
+struct tunnel {
+ uint32_t id;
+ struct expr *src;
+ struct expr *dst;
+ uint16_t sport;
+ uint16_t dport;
+ uint8_t tos;
+ uint8_t ttl;
+};
+
/**
* struct obj - nftables stateful object statement
*
struct secmark secmark;
struct ct_expect ct_expect;
struct synproxy synproxy;
+ struct tunnel tunnel;
};
};
CMD_OBJ_CT_EXPECTATIONS,
CMD_OBJ_SYNPROXY,
CMD_OBJ_SYNPROXYS,
+ CMD_OBJ_TUNNEL,
+ CMD_OBJ_TUNNELS,
CMD_OBJ_HOOKS,
};
case CMD_OBJ_CT_TIMEOUTS:
case CMD_OBJ_CT_EXPECT:
case CMD_OBJ_CT_EXPECTATIONS:
+ case CMD_OBJ_TUNNEL:
+ case CMD_OBJ_TUNNELS:
if (h->table.name &&
strlen(h->table.name) > NFT_NAME_MAXLEN) {
loc = &h->table.location;
return 0;
}
+static int tunnel_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+ if (obj->tunnel.src) {
+ expr_set_context(&ctx->ectx, obj->tunnel.src->dtype,
+ obj->tunnel.src->dtype->size);
+ if (expr_evaluate(ctx, &obj->tunnel.src) < 0)
+ return -1;
+ }
+
+ if (obj->tunnel.dst) {
+ expr_set_context(&ctx->ectx, obj->tunnel.dst->dtype,
+ obj->tunnel.dst->dtype->size);
+ if (expr_evaluate(ctx, &obj->tunnel.dst) < 0)
+ return -1;
+ }
+
+ if (obj->tunnel.src->dtype != obj->tunnel.dst->dtype)
+ return __stmt_binary_error(ctx, &obj->location, NULL,
+ "specify either ip or ip6 for address");
+
+ return 0;
+}
+
static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
{
struct table *table;
return ct_timeout_evaluate(ctx, obj);
case NFT_OBJECT_CT_EXPECT:
return ct_expect_evaluate(ctx, obj);
+ case NFT_OBJECT_TUNNEL:
+ return tunnel_evaluate(ctx, obj);
default:
break;
}
case CMD_OBJ_SECMARK:
case CMD_OBJ_CT_EXPECT:
case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_TUNNEL:
handle_merge(&cmd->object->handle, &cmd->handle);
return obj_evaluate(ctx, cmd->object);
default:
json_object_update(root, tmp);
json_decref(tmp);
break;
+ case NFT_OBJECT_TUNNEL:
+ /* TODO */
+ break;
}
return nft_json_pack("{s:o}", type, root);
case CMD_OBJ_SYNPROXYS:
root = do_list_obj_json(ctx, cmd, NFT_OBJECT_SYNPROXY);
break;
+ case CMD_OBJ_TUNNEL:
+ case CMD_OBJ_TUNNELS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_TUNNEL);
+ break;
case CMD_OBJ_FLOWTABLE:
root = do_list_flowtable_json(ctx, cmd, table);
break;
unsigned int flags)
{
struct obj *obj = cmd->object;
+ struct nft_data_linearize nld;
struct nftnl_udata_buf *udbuf;
struct nftnl_obj *nlo;
struct nlmsghdr *nlh;
nftnl_obj_set_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS,
obj->synproxy.flags);
break;
+ case NFT_OBJECT_TUNNEL:
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_TUNNEL_ID, obj->tunnel.id);
+ if (obj->tunnel.sport)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_SPORT,
+ obj->tunnel.sport);
+ if (obj->tunnel.dport)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_DPORT,
+ obj->tunnel.dport);
+ if (obj->tunnel.tos)
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_TUNNEL_TOS,
+ obj->tunnel.tos);
+ if (obj->tunnel.ttl)
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_TUNNEL_TTL,
+ obj->tunnel.ttl);
+ if (obj->tunnel.src) {
+ netlink_gen_data(obj->tunnel.src, &nld);
+ if (nld.len == sizeof(struct in_addr)) {
+ nftnl_obj_set_u32(nlo,
+ NFTNL_OBJ_TUNNEL_IPV4_SRC,
+ nld.value[0]);
+ } else {
+ nftnl_obj_set_data(nlo,
+ NFTNL_OBJ_TUNNEL_IPV6_SRC,
+ nld.value, nld.len);
+ }
+ }
+ if (obj->tunnel.dst) {
+ netlink_gen_data(obj->tunnel.dst, &nld);
+ if (nld.len == sizeof(struct in_addr)) {
+ nftnl_obj_set_u32(nlo,
+ NFTNL_OBJ_TUNNEL_IPV4_DST,
+ nld.value[0]);
+ } else {
+ nftnl_obj_set_data(nlo,
+ NFTNL_OBJ_TUNNEL_IPV6_DST,
+ nld.value, nld.len);
+ }
+ }
+ break;
default:
BUG("Unknown type %d\n", obj->type);
break;
fprintf(fp, "\n");
}
+static struct in6_addr all_zeroes;
+
+static struct expr *
+netlink_obj_tunnel_parse_addr(struct nftnl_obj *nlo, int attr)
+{
+ struct nft_data_delinearize nld;
+ const struct datatype *dtype;
+ const uint32_t *addr6;
+ struct expr *expr;
+ uint32_t addr;
+
+ memset(&nld, 0, sizeof(nld));
+
+ switch (attr) {
+ case NFTNL_OBJ_TUNNEL_IPV4_SRC:
+ case NFTNL_OBJ_TUNNEL_IPV4_DST:
+ addr = nftnl_obj_get_u32(nlo, attr);
+ if (!addr)
+ return NULL;
+
+ dtype = &ipaddr_type;
+ nld.value = &addr;
+ nld.len = sizeof(struct in_addr);
+ break;
+ case NFTNL_OBJ_TUNNEL_IPV6_SRC:
+ case NFTNL_OBJ_TUNNEL_IPV6_DST:
+ addr6 = nftnl_obj_get(nlo, attr);
+ if (!memcmp(addr6, &all_zeroes, sizeof(all_zeroes)))
+ return NULL;
+
+ dtype = &ip6addr_type;
+ nld.value = addr6;
+ nld.len = sizeof(struct in6_addr);
+ break;
+ default:
+ return NULL;
+ }
+
+ expr = netlink_alloc_value(&netlink_location, &nld);
+ expr->dtype = dtype;
+ expr->byteorder = BYTEORDER_BIG_ENDIAN;
+
+ return expr;
+}
+
static int obj_parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
unsigned char *value = nftnl_udata_get(attr);
obj->synproxy.flags =
nftnl_obj_get_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS);
break;
+ case NFT_OBJECT_TUNNEL:
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_ID))
+ obj->tunnel.id = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TUNNEL_ID);
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_SPORT)) {
+ obj->tunnel.sport =
+ nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_SPORT);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_DPORT)) {
+ obj->tunnel.dport =
+ nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_DPORT);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_TOS)) {
+ obj->tunnel.tos =
+ nftnl_obj_get_u8(nlo, NFTNL_OBJ_TUNNEL_TOS);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_TTL)) {
+ obj->tunnel.ttl =
+ nftnl_obj_get_u8(nlo, NFTNL_OBJ_TUNNEL_TTL);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV4_SRC)) {
+ obj->tunnel.src =
+ netlink_obj_tunnel_parse_addr(nlo, NFTNL_OBJ_TUNNEL_IPV4_SRC);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV4_DST)) {
+ obj->tunnel.dst =
+ netlink_obj_tunnel_parse_addr(nlo, NFTNL_OBJ_TUNNEL_IPV4_DST);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_SRC)) {
+ obj->tunnel.src =
+ netlink_obj_tunnel_parse_addr(nlo, NFTNL_OBJ_TUNNEL_IPV6_SRC);
+ }
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_DST)) {
+ obj->tunnel.dst =
+ netlink_obj_tunnel_parse_addr(nlo, NFTNL_OBJ_TUNNEL_IPV6_DST);
+ }
+ break;
default:
netlink_io_error(ctx, NULL, "Unknown object type %u", type);
obj_free(obj);
%token LENGTH "length"
%token FRAG_OFF "frag-off"
%token TTL "ttl"
+%token TOS "tos"
%token PROTOCOL "protocol"
%token CHECKSUM "checksum"
%token LAST "last"
%token NEVER "never"
+%token TUNNEL "tunnel"
+
%token COUNTERS "counters"
%token QUOTAS "quotas"
%token LIMITS "limits"
+%token TUNNELS "tunnels"
%token SYNPROXYS "synproxys"
%token HELPERS "helpers"
%type <flowtable> flowtable_block_alloc flowtable_block
%destructor { flowtable_free($$); } flowtable_block_alloc
-%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block
+%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block tunnel_block
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
%type <expr> and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
%destructor { expr_free($$); } and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
-%type <obj> counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj
-%destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj
+%type <obj> counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj tunnel_obj
+%destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj tunnel_obj
%type <expr> relational_expr
%destructor { expr_free($$); } relational_expr
close_scope_log : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_LOG); }
close_scope_synproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_SYNPROXY); }
+close_scope_tunnel : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TUNNEL); }
close_scope_xt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_XT); }
common_block : INCLUDE QUOTED_STRING stmt_separator
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
}
+ | TUNNEL obj_spec tunnel_obj '{' tunnel_block '}' close_scope_tunnel
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TUNNEL, &$2, &@$, $3);
+ }
;
replace_cmd : RULE ruleid_spec rule
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
}
+ | TUNNEL obj_spec tunnel_obj '{' tunnel_block '}' close_scope_tunnel
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_TUNNEL, &$2, &@$, $3);
+ }
;
insert_cmd : RULE rule_position rule
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
}
+ | TUNNEL obj_or_id_spec close_scope_tunnel
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TUNNEL, &$2, &@$, NULL);
+ }
;
destroy_cmd : TABLE table_or_id_spec
{
$$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
}
+ | TUNNEL obj_or_id_spec close_scope_tunnel
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_TUNNEL, &$2, &@$, NULL);
+ }
;
list_add_tail(&$4->list, &$1->objs);
$$ = $1;
}
+ | table_block TUNNEL obj_identifier
+ obj_block_alloc '{' tunnel_block '}'
+ stmt_separator close_scope_tunnel
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_TUNNEL;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
;
chain_block_alloc : /* empty */
}
;
+tunnel_config : ID NUM
+ {
+ $<obj>0->tunnel.id = $2;
+ }
+ | IP SADDR expr close_scope_ip
+ {
+ $<obj>0->tunnel.src = $3;
+ datatype_set($3, &ipaddr_type);
+ }
+ | IP DADDR expr close_scope_ip
+ {
+ $<obj>0->tunnel.dst = $3;
+ datatype_set($3, &ipaddr_type);
+ }
+ | IP6 SADDR expr close_scope_ip6
+ {
+ $<obj>0->tunnel.src = $3;
+ datatype_set($3, &ip6addr_type);
+ }
+ | IP6 DADDR expr close_scope_ip6
+ {
+ $<obj>0->tunnel.dst = $3;
+ datatype_set($3, &ip6addr_type);
+ }
+ | SPORT NUM
+ {
+ $<obj>0->tunnel.sport = $2;
+ }
+ | DPORT NUM
+ {
+ $<obj>0->tunnel.dport = $2;
+ }
+ | TTL NUM
+ {
+ $<obj>0->tunnel.ttl = $2;
+ }
+ | TOS NUM
+ {
+ $<obj>0->tunnel.tos = $2;
+ }
+ ;
+
+tunnel_block : /* empty */ { $$ = $<obj>-1; }
+ | tunnel_block common_block
+ | tunnel_block stmt_separator
+ | tunnel_block tunnel_config stmt_separator
+ {
+ $$ = $1;
+ }
+ | tunnel_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+tunnel_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_TUNNEL;
+ }
+ ;
+
relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
[NFT_OBJECT_SECMARK] = "secmark",
[NFT_OBJECT_CT_EXPECT] = "ct expectation",
[NFT_OBJECT_SYNPROXY] = "synproxy",
+ [NFT_OBJECT_TUNNEL] = "tunnel",
};
unsigned int i;
obj->synproxy.flags |= flags;
break;
+ case CMD_OBJ_TUNNEL:
+ /* TODO */
+ break;
default:
BUG("Invalid CMD '%d'", cmd_obj);
}
{ "ct helper", NFT_OBJECT_CT_HELPER, json_parse_cmd_add_object },
{ "ct timeout", NFT_OBJECT_CT_TIMEOUT, json_parse_cmd_add_object },
{ "ct expectation", NFT_OBJECT_CT_EXPECT, json_parse_cmd_add_object },
+ { "tunnel", NFT_OBJECT_TUNNEL, json_parse_cmd_add_object },
{ "limit", CMD_OBJ_LIMIT, json_parse_cmd_add_object },
{ "secmark", CMD_OBJ_SECMARK, json_parse_cmd_add_object },
{ "synproxy", CMD_OBJ_SYNPROXY, json_parse_cmd_add_object }
case CMD_OBJ_SETS:
case CMD_OBJ_COUNTERS:
case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_TUNNELS:
if (!json_unpack(root, "{s:s}", "table", &tmp))
h.table.name = xstrdup(tmp);
break;
{ "ct helpers", CMD_OBJ_CT_HELPERS, json_parse_cmd_list_multiple },
{ "ct timeout", NFT_OBJECT_CT_TIMEOUT, json_parse_cmd_add_object },
{ "ct expectation", NFT_OBJECT_CT_EXPECT, json_parse_cmd_add_object },
+ { "tunnel", NFT_OBJECT_TUNNEL, json_parse_cmd_add_object },
+ { "tunnels", CMD_OBJ_TUNNELS, json_parse_cmd_list_multiple },
{ "limit", CMD_OBJ_LIMIT, json_parse_cmd_add_object },
{ "limits", CMD_OBJ_LIMIT, json_parse_cmd_list_multiple },
{ "ruleset", CMD_OBJ_RULESET, json_parse_cmd_list_multiple },
case CMD_OBJ_LIMIT:
case CMD_OBJ_SECMARK:
case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_TUNNEL:
obj_free(cmd->object);
break;
case CMD_OBJ_FLOWTABLE:
case CMD_OBJ_LIMIT:
case CMD_OBJ_SECMARK:
case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_TUNNEL:
return mnl_nft_obj_add(ctx, cmd, flags);
case CMD_OBJ_FLOWTABLE:
return mnl_nft_flowtable_add(ctx, cmd, flags);
return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_SECMARK);
case CMD_OBJ_SYNPROXY:
return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_TUNNEL:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_TUNNEL);
case CMD_OBJ_FLOWTABLE:
return mnl_nft_flowtable_del(ctx, cmd);
default:
return;
free_const(obj->comment);
handle_free(&obj->handle);
- if (obj->type == NFT_OBJECT_CT_TIMEOUT) {
+ switch (obj->type) {
+ case NFT_OBJECT_CT_TIMEOUT: {
struct timeout_state *ts, *next;
list_for_each_entry_safe(ts, next, &obj->ct_timeout.timeout_list, head) {
free_const(ts->timeout_str);
free(ts);
}
+ }
+ break;
+ case NFT_OBJECT_TUNNEL:
+ expr_free(obj->tunnel.src);
+ expr_free(obj->tunnel.dst);
+ break;
+ default:
+ break;
}
free(obj);
}
nft_print(octx, "%s", opts->stmt_separator);
}
break;
+ case NFT_OBJECT_TUNNEL:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+
+ nft_print(octx, "%s%s%sid %u",
+ opts->nl, opts->tab, opts->tab, obj->tunnel.id);
+
+ if (obj->tunnel.src) {
+ if (obj->tunnel.src->len == 32) {
+ nft_print(octx, "%s%s%sip saddr ",
+ opts->nl, opts->tab, opts->tab);
+ expr_print(obj->tunnel.src, octx);
+ } else if (obj->tunnel.src->len == 128) {
+ nft_print(octx, "%s%s%sip6 saddr ",
+ opts->nl, opts->tab, opts->tab);
+ expr_print(obj->tunnel.src, octx);
+ }
+ }
+ if (obj->tunnel.dst) {
+ if (obj->tunnel.dst->len == 32) {
+ nft_print(octx, "%s%s%sip daddr ",
+ opts->nl, opts->tab, opts->tab);
+ expr_print(obj->tunnel.dst, octx);
+ } else if (obj->tunnel.dst->len == 128) {
+ nft_print(octx, "%s%s%sip6 daddr ",
+ opts->nl, opts->tab, opts->tab);
+ expr_print(obj->tunnel.dst, octx);
+ }
+ }
+ if (obj->tunnel.sport) {
+ nft_print(octx, "%s%s%ssport %u",
+ opts->nl, opts->tab, opts->tab,
+ obj->tunnel.sport);
+ }
+ if (obj->tunnel.dport) {
+ nft_print(octx, "%s%s%sdport %u",
+ opts->nl, opts->tab, opts->tab,
+ obj->tunnel.dport);
+ }
+ if (obj->tunnel.tos) {
+ nft_print(octx, "%s%s%stos %u",
+ opts->nl, opts->tab, opts->tab,
+ obj->tunnel.tos);
+ }
+ if (obj->tunnel.ttl) {
+ nft_print(octx, "%s%s%sttl %u",
+ opts->nl, opts->tab, opts->tab,
+ obj->tunnel.ttl);
+ }
+ nft_print(octx, "%s", opts->stmt_separator);
+ break;
default:
nft_print(octx, " unknown {%s", opts->nl);
break;
[NFT_OBJECT_SECMARK] = "secmark",
[NFT_OBJECT_SYNPROXY] = "synproxy",
[NFT_OBJECT_CT_EXPECT] = "ct expectation",
+ [NFT_OBJECT_TUNNEL] = "tunnel",
};
const char *obj_type_name(unsigned int type)
[NFT_OBJECT_SECMARK] = CMD_OBJ_SECMARK,
[NFT_OBJECT_SYNPROXY] = CMD_OBJ_SYNPROXY,
[NFT_OBJECT_CT_EXPECT] = CMD_OBJ_CT_EXPECT,
+ [NFT_OBJECT_TUNNEL] = CMD_OBJ_TUNNEL,
};
enum cmd_obj obj_type_to_cmd(uint32_t type)
case CMD_OBJ_SYNPROXY:
case CMD_OBJ_SYNPROXYS:
return do_list_obj(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_TUNNEL:
+ case CMD_OBJ_TUNNELS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_TUNNEL);
case CMD_OBJ_FLOWTABLE:
return do_list_flowtable(ctx, cmd, table);
case CMD_OBJ_FLOWTABLES:
%s SCANSTATE_SECMARK
%s SCANSTATE_TCP
%s SCANSTATE_TYPE
+%s SCANSTATE_TUNNEL
%s SCANSTATE_VLAN
%s SCANSTATE_XT
%s SCANSTATE_CMD_DESTROY
"maps" { return MAPS; }
"secmarks" { return SECMARKS; }
"synproxys" { return SYNPROXYS; }
+ "tunnel" { return TUNNEL; }
+ "tunnels" { return TUNNELS; }
"hooks" { return HOOKS; }
}
"sack-perm" { return SACK_PERM; }
}
+"tunnel" { scanner_push_start_cond(yyscanner, SCANSTATE_TUNNEL); return TUNNEL; }
+<SCANSTATE_TUNNEL>{
+ "id" { return ID; }
+ "sport" { return SPORT; }
+ "dport" { return DPORT; }
+ "ttl" { return TTL; }
+ "tos" { return TOS; }
+}
+
"notrack" { return NOTRACK; }
"all" { return ALL; }