aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStéphane Veyret <sveyret@gmail.com>2019-05-25 09:30:58 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2019-06-17 10:35:20 -0400
commit857b46027d6f91150797295752581b7155b9d0e1 (patch)
treec3408c8afa62515ec21cfc5f007af55ea8291dc5
parent16e6427c88c5b7e7b6612f6c286d5f71d659e5be (diff)
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 <sveyret@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h14
-rw-r--r--net/netfilter/nft_ct.c138
2 files changed, 149 insertions, 3 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 505393c6e959..31a6b8f7ff73 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1445,6 +1445,17 @@ enum nft_ct_timeout_timeout_attributes {
1445}; 1445};
1446#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) 1446#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
1447 1447
1448enum 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
1448#define NFT_OBJECT_UNSPEC 0 1459#define NFT_OBJECT_UNSPEC 0
1449#define NFT_OBJECT_COUNTER 1 1460#define NFT_OBJECT_COUNTER 1
1450#define NFT_OBJECT_QUOTA 2 1461#define NFT_OBJECT_QUOTA 2
@@ -1454,7 +1465,8 @@ enum nft_ct_timeout_timeout_attributes {
1454#define NFT_OBJECT_TUNNEL 6 1465#define NFT_OBJECT_TUNNEL 6
1455#define NFT_OBJECT_CT_TIMEOUT 7 1466#define NFT_OBJECT_CT_TIMEOUT 7
1456#define NFT_OBJECT_SECMARK 8 1467#define NFT_OBJECT_SECMARK 8
1457#define __NFT_OBJECT_MAX 9 1468#define NFT_OBJECT_CT_EXPECT 9
1469#define __NFT_OBJECT_MAX 10
1458#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) 1470#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
1459 1471
1460/** 1472/**
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index f043936763f3..06b52c894573 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -24,6 +24,7 @@
24#include <net/netfilter/nf_conntrack_labels.h> 24#include <net/netfilter/nf_conntrack_labels.h>
25#include <net/netfilter/nf_conntrack_timeout.h> 25#include <net/netfilter/nf_conntrack_timeout.h>
26#include <net/netfilter/nf_conntrack_l4proto.h> 26#include <net/netfilter/nf_conntrack_l4proto.h>
27#include <net/netfilter/nf_conntrack_expect.h>
27 28
28struct nft_ct { 29struct nft_ct {
29 enum nft_ct_keys key:8; 30 enum nft_ct_keys key:8;
@@ -1156,6 +1157,131 @@ static struct nft_object_type nft_ct_helper_obj_type __read_mostly = {
1156 .owner = THIS_MODULE, 1157 .owner = THIS_MODULE,
1157}; 1158};
1158 1159
1160struct nft_ct_expect_obj {
1161 u16 l3num;
1162 __be16 dport;
1163 u8 l4proto;
1164 u8 size;
1165 u32 timeout;
1166};
1167
1168static 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
1192static 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
1198static 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
1213static 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
1258static 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
1266static struct nft_object_type nft_ct_expect_obj_type;
1267
1268static 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
1277static 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
1159static int __init nft_ct_module_init(void) 1285static int __init nft_ct_module_init(void)
1160{ 1286{
1161 int err; 1287 int err;
@@ -1173,17 +1299,23 @@ static int __init nft_ct_module_init(void)
1173 err = nft_register_obj(&nft_ct_helper_obj_type); 1299 err = nft_register_obj(&nft_ct_helper_obj_type);
1174 if (err < 0) 1300 if (err < 0)
1175 goto err2; 1301 goto err2;
1302
1303 err = nft_register_obj(&nft_ct_expect_obj_type);
1304 if (err < 0)
1305 goto err3;
1176#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 1306#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1177 err = nft_register_obj(&nft_ct_timeout_obj_type); 1307 err = nft_register_obj(&nft_ct_timeout_obj_type);
1178 if (err < 0) 1308 if (err < 0)
1179 goto err3; 1309 goto err4;
1180#endif 1310#endif
1181 return 0; 1311 return 0;
1182 1312
1183#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 1313#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1314err4:
1315 nft_unregister_obj(&nft_ct_expect_obj_type);
1316#endif
1184err3: 1317err3:
1185 nft_unregister_obj(&nft_ct_helper_obj_type); 1318 nft_unregister_obj(&nft_ct_helper_obj_type);
1186#endif
1187err2: 1319err2:
1188 nft_unregister_expr(&nft_notrack_type); 1320 nft_unregister_expr(&nft_notrack_type);
1189err1: 1321err1:
@@ -1196,6 +1328,7 @@ static void __exit nft_ct_module_exit(void)
1196#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 1328#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
1197 nft_unregister_obj(&nft_ct_timeout_obj_type); 1329 nft_unregister_obj(&nft_ct_timeout_obj_type);
1198#endif 1330#endif
1331 nft_unregister_obj(&nft_ct_expect_obj_type);
1199 nft_unregister_obj(&nft_ct_helper_obj_type); 1332 nft_unregister_obj(&nft_ct_helper_obj_type);
1200 nft_unregister_expr(&nft_notrack_type); 1333 nft_unregister_expr(&nft_notrack_type);
1201 nft_unregister_expr(&nft_ct_type); 1334 nft_unregister_expr(&nft_ct_type);
@@ -1210,3 +1343,4 @@ MODULE_ALIAS_NFT_EXPR("ct");
1210MODULE_ALIAS_NFT_EXPR("notrack"); 1343MODULE_ALIAS_NFT_EXPR("notrack");
1211MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER); 1344MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);
1212MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_TIMEOUT); 1345MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_TIMEOUT);
1346MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_EXPECT);