Skip to content

Commit 857b460

Browse files
sveyretummakynes
authored andcommitted
netfilter: nft_ct: add ct expectations support
This patch allows to add, list and delete expectations via nft objref infrastructure and assigning these expectations via nft rule. This allows manual port triggering when no helper is defined to manage a specific protocol. For example, if I have an online game which protocol is based on initial connection to TCP port 9753 of the server, and where the server opens a connection to port 9876, I can set rules as follow: table ip filter { ct expectation mygame { protocol udp; dport 9876; timeout 2m; size 1; } chain input { type filter hook input priority 0; policy drop; tcp dport 9753 ct expectation set "mygame"; } chain output { type filter hook output priority 0; policy drop; udp dport 9876 ct status expected accept; } } Signed-off-by: Stéphane Veyret <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 16e6427 commit 857b460

File tree

2 files changed

+149
-3
lines changed

2 files changed

+149
-3
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,17 @@ enum nft_ct_timeout_timeout_attributes {
14451445
};
14461446
#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
14471447

1448+
enum nft_ct_expectation_attributes {
1449+
NFTA_CT_EXPECT_UNSPEC,
1450+
NFTA_CT_EXPECT_L3PROTO,
1451+
NFTA_CT_EXPECT_L4PROTO,
1452+
NFTA_CT_EXPECT_DPORT,
1453+
NFTA_CT_EXPECT_TIMEOUT,
1454+
NFTA_CT_EXPECT_SIZE,
1455+
__NFTA_CT_EXPECT_MAX,
1456+
};
1457+
#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1)
1458+
14481459
#define NFT_OBJECT_UNSPEC 0
14491460
#define NFT_OBJECT_COUNTER 1
14501461
#define NFT_OBJECT_QUOTA 2
@@ -1454,7 +1465,8 @@ enum nft_ct_timeout_timeout_attributes {
14541465
#define NFT_OBJECT_TUNNEL 6
14551466
#define NFT_OBJECT_CT_TIMEOUT 7
14561467
#define NFT_OBJECT_SECMARK 8
1457-
#define __NFT_OBJECT_MAX 9
1468+
#define NFT_OBJECT_CT_EXPECT 9
1469+
#define __NFT_OBJECT_MAX 10
14581470
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
14591471

14601472
/**

net/netfilter/nft_ct.c

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <net/netfilter/nf_conntrack_labels.h>
2525
#include <net/netfilter/nf_conntrack_timeout.h>
2626
#include <net/netfilter/nf_conntrack_l4proto.h>
27+
#include <net/netfilter/nf_conntrack_expect.h>
2728

2829
struct nft_ct {
2930
enum nft_ct_keys key:8;
@@ -1156,6 +1157,131 @@ static struct nft_object_type nft_ct_helper_obj_type __read_mostly = {
11561157
.owner = THIS_MODULE,
11571158
};
11581159

1160+
struct nft_ct_expect_obj {
1161+
u16 l3num;
1162+
__be16 dport;
1163+
u8 l4proto;
1164+
u8 size;
1165+
u32 timeout;
1166+
};
1167+
1168+
static int nft_ct_expect_obj_init(const struct nft_ctx *ctx,
1169+
const struct nlattr * const tb[],
1170+
struct nft_object *obj)
1171+
{
1172+
struct nft_ct_expect_obj *priv = nft_obj_data(obj);
1173+
1174+
if (!tb[NFTA_CT_EXPECT_L4PROTO] ||
1175+
!tb[NFTA_CT_EXPECT_DPORT] ||
1176+
!tb[NFTA_CT_EXPECT_TIMEOUT] ||
1177+
!tb[NFTA_CT_EXPECT_SIZE])
1178+
return -EINVAL;
1179+
1180+
priv->l3num = ctx->family;
1181+
if (tb[NFTA_CT_EXPECT_L3PROTO])
1182+
priv->l3num = ntohs(nla_get_be16(tb[NFTA_CT_EXPECT_L3PROTO]));
1183+
1184+
priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]);
1185+
priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]);
1186+
priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]);
1187+
priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]);
1188+
1189+
return nf_ct_netns_get(ctx->net, ctx->family);
1190+
}
1191+
1192+
static void nft_ct_expect_obj_destroy(const struct nft_ctx *ctx,
1193+
struct nft_object *obj)
1194+
{
1195+
nf_ct_netns_put(ctx->net, ctx->family);
1196+
}
1197+
1198+
static int nft_ct_expect_obj_dump(struct sk_buff *skb,
1199+
struct nft_object *obj, bool reset)
1200+
{
1201+
const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
1202+
1203+
if (nla_put_be16(skb, NFTA_CT_EXPECT_L3PROTO, htons(priv->l3num)) ||
1204+
nla_put_u8(skb, NFTA_CT_EXPECT_L4PROTO, priv->l4proto) ||
1205+
nla_put_be16(skb, NFTA_CT_EXPECT_DPORT, priv->dport) ||
1206+
nla_put_u32(skb, NFTA_CT_EXPECT_TIMEOUT, priv->timeout) ||
1207+
nla_put_u8(skb, NFTA_CT_EXPECT_SIZE, priv->size))
1208+
return -1;
1209+
1210+
return 0;
1211+
}
1212+
1213+
static void nft_ct_expect_obj_eval(struct nft_object *obj,
1214+
struct nft_regs *regs,
1215+
const struct nft_pktinfo *pkt)
1216+
{
1217+
const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
1218+
struct nf_conntrack_expect *exp;
1219+
enum ip_conntrack_info ctinfo;
1220+
struct nf_conn_help *help;
1221+
enum ip_conntrack_dir dir;
1222+
u16 l3num = priv->l3num;
1223+
struct nf_conn *ct;
1224+
1225+
ct = nf_ct_get(pkt->skb, &ctinfo);
1226+
if (!ct || ctinfo == IP_CT_UNTRACKED) {
1227+
regs->verdict.code = NFT_BREAK;
1228+
return;
1229+
}
1230+
dir = CTINFO2DIR(ctinfo);
1231+
1232+
help = nfct_help(ct);
1233+
if (!help)
1234+
help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
1235+
1236+
if (help->expecting[NF_CT_EXPECT_CLASS_DEFAULT] >= priv->size) {
1237+
regs->verdict.code = NFT_BREAK;
1238+
return;
1239+
}
1240+
if (l3num == NFPROTO_INET)
1241+
l3num = nf_ct_l3num(ct);
1242+
1243+
exp = nf_ct_expect_alloc(ct);
1244+
if (exp == NULL) {
1245+
regs->verdict.code = NF_DROP;
1246+
return;
1247+
}
1248+
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, l3num,
1249+
&ct->tuplehash[!dir].tuple.src.u3,
1250+
&ct->tuplehash[!dir].tuple.dst.u3,
1251+
priv->l4proto, NULL, &priv->dport);
1252+
exp->timeout.expires = jiffies + priv->timeout * HZ;
1253+
1254+
if (nf_ct_expect_related(exp) != 0)
1255+
regs->verdict.code = NF_DROP;
1256+
}
1257+
1258+
static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX + 1] = {
1259+
[NFTA_CT_EXPECT_L3PROTO] = { .type = NLA_U16 },
1260+
[NFTA_CT_EXPECT_L4PROTO] = { .type = NLA_U8 },
1261+
[NFTA_CT_EXPECT_DPORT] = { .type = NLA_U16 },
1262+
[NFTA_CT_EXPECT_TIMEOUT] = { .type = NLA_U32 },
1263+
[NFTA_CT_EXPECT_SIZE] = { .type = NLA_U8 },
1264+
};
1265+
1266+
static struct nft_object_type nft_ct_expect_obj_type;
1267+
1268+
static const struct nft_object_ops nft_ct_expect_obj_ops = {
1269+
.type = &nft_ct_expect_obj_type,
1270+
.size = sizeof(struct nft_ct_expect_obj),
1271+
.eval = nft_ct_expect_obj_eval,
1272+
.init = nft_ct_expect_obj_init,
1273+
.destroy = nft_ct_expect_obj_destroy,
1274+
.dump = nft_ct_expect_obj_dump,
1275+
};
1276+
1277+
static struct nft_object_type nft_ct_expect_obj_type __read_mostly = {
1278+
.type = NFT_OBJECT_CT_EXPECT,
1279+
.ops = &nft_ct_expect_obj_ops,
1280+
.maxattr = NFTA_CT_EXPECT_MAX,
1281+
.policy = nft_ct_expect_policy,
1282+
.owner = THIS_MODULE,
1283+
};
1284+
11591285
static int __init nft_ct_module_init(void)
11601286
{
11611287
int err;
@@ -1173,17 +1299,23 @@ static int __init nft_ct_module_init(void)
11731299
err = nft_register_obj(&nft_ct_helper_obj_type);
11741300
if (err < 0)
11751301
goto err2;
1302+
1303+
err = nft_register_obj(&nft_ct_expect_obj_type);
1304+
if (err < 0)
1305+
goto err3;
11761306
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
11771307
err = nft_register_obj(&nft_ct_timeout_obj_type);
11781308
if (err < 0)
1179-
goto err3;
1309+
goto err4;
11801310
#endif
11811311
return 0;
11821312

11831313
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1314+
err4:
1315+
nft_unregister_obj(&nft_ct_expect_obj_type);
1316+
#endif
11841317
err3:
11851318
nft_unregister_obj(&nft_ct_helper_obj_type);
1186-
#endif
11871319
err2:
11881320
nft_unregister_expr(&nft_notrack_type);
11891321
err1:
@@ -1196,6 +1328,7 @@ static void __exit nft_ct_module_exit(void)
11961328
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
11971329
nft_unregister_obj(&nft_ct_timeout_obj_type);
11981330
#endif
1331+
nft_unregister_obj(&nft_ct_expect_obj_type);
11991332
nft_unregister_obj(&nft_ct_helper_obj_type);
12001333
nft_unregister_expr(&nft_notrack_type);
12011334
nft_unregister_expr(&nft_ct_type);
@@ -1210,3 +1343,4 @@ MODULE_ALIAS_NFT_EXPR("ct");
12101343
MODULE_ALIAS_NFT_EXPR("notrack");
12111344
MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);
12121345
MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_TIMEOUT);
1346+
MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_EXPECT);

0 commit comments

Comments
 (0)