1 /* 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Development of this code funded by Astaro AG (http://www.astaro.com/) 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/netlink.h> 15 #include <linux/netfilter.h> 16 #include <linux/netfilter/nf_tables.h> 17 #include <net/netfilter/nf_tables.h> 18 #include <net/netfilter/nf_conntrack.h> 19 #include <net/netfilter/nf_conntrack_acct.h> 20 #include <net/netfilter/nf_conntrack_tuple.h> 21 #include <net/netfilter/nf_conntrack_helper.h> 22 #include <net/netfilter/nf_conntrack_ecache.h> 23 #include <net/netfilter/nf_conntrack_labels.h> 24 25 struct nft_ct { 26 enum nft_ct_keys key:8; 27 enum ip_conntrack_dir dir:8; 28 union { 29 enum nft_registers dreg:8; 30 enum nft_registers sreg:8; 31 }; 32 }; 33 34 static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c, 35 enum nft_ct_keys k, 36 enum ip_conntrack_dir d) 37 { 38 if (d < IP_CT_DIR_MAX) 39 return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) : 40 atomic64_read(&c[d].packets); 41 42 return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) + 43 nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY); 44 } 45 46 static void nft_ct_get_eval(const struct nft_expr *expr, 47 struct nft_regs *regs, 48 const struct nft_pktinfo *pkt) 49 { 50 const struct nft_ct *priv = nft_expr_priv(expr); 51 u32 *dest = ®s->data[priv->dreg]; 52 enum ip_conntrack_info ctinfo; 53 const struct nf_conn *ct; 54 const struct nf_conn_help *help; 55 const struct nf_conntrack_tuple *tuple; 56 const struct nf_conntrack_helper *helper; 57 long diff; 58 unsigned int state; 59 60 ct = nf_ct_get(pkt->skb, &ctinfo); 61 62 switch (priv->key) { 63 case NFT_CT_STATE: 64 if (ct == NULL) 65 state = NF_CT_STATE_INVALID_BIT; 66 else if (nf_ct_is_untracked(ct)) 67 state = NF_CT_STATE_UNTRACKED_BIT; 68 else 69 state = NF_CT_STATE_BIT(ctinfo); 70 *dest = state; 71 return; 72 default: 73 break; 74 } 75 76 if (ct == NULL) 77 goto err; 78 79 switch (priv->key) { 80 case NFT_CT_DIRECTION: 81 *dest = CTINFO2DIR(ctinfo); 82 return; 83 case NFT_CT_STATUS: 84 *dest = ct->status; 85 return; 86 #ifdef CONFIG_NF_CONNTRACK_MARK 87 case NFT_CT_MARK: 88 *dest = ct->mark; 89 return; 90 #endif 91 #ifdef CONFIG_NF_CONNTRACK_SECMARK 92 case NFT_CT_SECMARK: 93 *dest = ct->secmark; 94 return; 95 #endif 96 case NFT_CT_EXPIRATION: 97 diff = (long)jiffies - (long)ct->timeout.expires; 98 if (diff < 0) 99 diff = 0; 100 *dest = jiffies_to_msecs(diff); 101 return; 102 case NFT_CT_HELPER: 103 if (ct->master == NULL) 104 goto err; 105 help = nfct_help(ct->master); 106 if (help == NULL) 107 goto err; 108 helper = rcu_dereference(help->helper); 109 if (helper == NULL) 110 goto err; 111 strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN); 112 return; 113 #ifdef CONFIG_NF_CONNTRACK_LABELS 114 case NFT_CT_LABELS: { 115 struct nf_conn_labels *labels = nf_ct_labels_find(ct); 116 unsigned int size; 117 118 if (!labels) { 119 memset(dest, 0, NF_CT_LABELS_MAX_SIZE); 120 return; 121 } 122 123 size = labels->words * sizeof(long); 124 memcpy(dest, labels->bits, size); 125 if (size < NF_CT_LABELS_MAX_SIZE) 126 memset(((char *) dest) + size, 0, 127 NF_CT_LABELS_MAX_SIZE - size); 128 return; 129 } 130 #endif 131 case NFT_CT_BYTES: /* fallthrough */ 132 case NFT_CT_PKTS: { 133 const struct nf_conn_acct *acct = nf_conn_acct_find(ct); 134 u64 count = 0; 135 136 if (acct) 137 count = nft_ct_get_eval_counter(acct->counter, 138 priv->key, priv->dir); 139 memcpy(dest, &count, sizeof(count)); 140 return; 141 } 142 default: 143 break; 144 } 145 146 tuple = &ct->tuplehash[priv->dir].tuple; 147 switch (priv->key) { 148 case NFT_CT_L3PROTOCOL: 149 *dest = nf_ct_l3num(ct); 150 return; 151 case NFT_CT_SRC: 152 memcpy(dest, tuple->src.u3.all, 153 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); 154 return; 155 case NFT_CT_DST: 156 memcpy(dest, tuple->dst.u3.all, 157 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); 158 return; 159 case NFT_CT_PROTOCOL: 160 *dest = nf_ct_protonum(ct); 161 return; 162 case NFT_CT_PROTO_SRC: 163 *dest = (__force __u16)tuple->src.u.all; 164 return; 165 case NFT_CT_PROTO_DST: 166 *dest = (__force __u16)tuple->dst.u.all; 167 return; 168 default: 169 break; 170 } 171 return; 172 err: 173 regs->verdict.code = NFT_BREAK; 174 } 175 176 static void nft_ct_set_eval(const struct nft_expr *expr, 177 struct nft_regs *regs, 178 const struct nft_pktinfo *pkt) 179 { 180 const struct nft_ct *priv = nft_expr_priv(expr); 181 struct sk_buff *skb = pkt->skb; 182 #ifdef CONFIG_NF_CONNTRACK_MARK 183 u32 value = regs->data[priv->sreg]; 184 #endif 185 enum ip_conntrack_info ctinfo; 186 struct nf_conn *ct; 187 188 ct = nf_ct_get(skb, &ctinfo); 189 if (ct == NULL) 190 return; 191 192 switch (priv->key) { 193 #ifdef CONFIG_NF_CONNTRACK_MARK 194 case NFT_CT_MARK: 195 if (ct->mark != value) { 196 ct->mark = value; 197 nf_conntrack_event_cache(IPCT_MARK, ct); 198 } 199 break; 200 #endif 201 default: 202 break; 203 } 204 } 205 206 static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { 207 [NFTA_CT_DREG] = { .type = NLA_U32 }, 208 [NFTA_CT_KEY] = { .type = NLA_U32 }, 209 [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, 210 [NFTA_CT_SREG] = { .type = NLA_U32 }, 211 }; 212 213 static int nft_ct_l3proto_try_module_get(uint8_t family) 214 { 215 int err; 216 217 if (family == NFPROTO_INET) { 218 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4); 219 if (err < 0) 220 goto err1; 221 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6); 222 if (err < 0) 223 goto err2; 224 } else { 225 err = nf_ct_l3proto_try_module_get(family); 226 if (err < 0) 227 goto err1; 228 } 229 return 0; 230 231 err2: 232 nf_ct_l3proto_module_put(NFPROTO_IPV4); 233 err1: 234 return err; 235 } 236 237 static void nft_ct_l3proto_module_put(uint8_t family) 238 { 239 if (family == NFPROTO_INET) { 240 nf_ct_l3proto_module_put(NFPROTO_IPV4); 241 nf_ct_l3proto_module_put(NFPROTO_IPV6); 242 } else 243 nf_ct_l3proto_module_put(family); 244 } 245 246 static int nft_ct_get_init(const struct nft_ctx *ctx, 247 const struct nft_expr *expr, 248 const struct nlattr * const tb[]) 249 { 250 struct nft_ct *priv = nft_expr_priv(expr); 251 unsigned int len; 252 int err; 253 254 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); 255 switch (priv->key) { 256 case NFT_CT_DIRECTION: 257 if (tb[NFTA_CT_DIRECTION] != NULL) 258 return -EINVAL; 259 len = sizeof(u8); 260 break; 261 case NFT_CT_STATE: 262 case NFT_CT_STATUS: 263 #ifdef CONFIG_NF_CONNTRACK_MARK 264 case NFT_CT_MARK: 265 #endif 266 #ifdef CONFIG_NF_CONNTRACK_SECMARK 267 case NFT_CT_SECMARK: 268 #endif 269 case NFT_CT_EXPIRATION: 270 if (tb[NFTA_CT_DIRECTION] != NULL) 271 return -EINVAL; 272 len = sizeof(u32); 273 break; 274 #ifdef CONFIG_NF_CONNTRACK_LABELS 275 case NFT_CT_LABELS: 276 if (tb[NFTA_CT_DIRECTION] != NULL) 277 return -EINVAL; 278 len = NF_CT_LABELS_MAX_SIZE; 279 break; 280 #endif 281 case NFT_CT_HELPER: 282 if (tb[NFTA_CT_DIRECTION] != NULL) 283 return -EINVAL; 284 len = NF_CT_HELPER_NAME_LEN; 285 break; 286 287 case NFT_CT_L3PROTOCOL: 288 case NFT_CT_PROTOCOL: 289 if (tb[NFTA_CT_DIRECTION] == NULL) 290 return -EINVAL; 291 len = sizeof(u8); 292 break; 293 case NFT_CT_SRC: 294 case NFT_CT_DST: 295 if (tb[NFTA_CT_DIRECTION] == NULL) 296 return -EINVAL; 297 298 switch (ctx->afi->family) { 299 case NFPROTO_IPV4: 300 len = FIELD_SIZEOF(struct nf_conntrack_tuple, 301 src.u3.ip); 302 break; 303 case NFPROTO_IPV6: 304 case NFPROTO_INET: 305 len = FIELD_SIZEOF(struct nf_conntrack_tuple, 306 src.u3.ip6); 307 break; 308 default: 309 return -EAFNOSUPPORT; 310 } 311 break; 312 case NFT_CT_PROTO_SRC: 313 case NFT_CT_PROTO_DST: 314 if (tb[NFTA_CT_DIRECTION] == NULL) 315 return -EINVAL; 316 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all); 317 break; 318 case NFT_CT_BYTES: 319 case NFT_CT_PKTS: 320 /* no direction? return sum of original + reply */ 321 if (tb[NFTA_CT_DIRECTION] == NULL) 322 priv->dir = IP_CT_DIR_MAX; 323 len = sizeof(u64); 324 break; 325 default: 326 return -EOPNOTSUPP; 327 } 328 329 if (tb[NFTA_CT_DIRECTION] != NULL) { 330 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); 331 switch (priv->dir) { 332 case IP_CT_DIR_ORIGINAL: 333 case IP_CT_DIR_REPLY: 334 break; 335 default: 336 return -EINVAL; 337 } 338 } 339 340 priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]); 341 err = nft_validate_register_store(ctx, priv->dreg, NULL, 342 NFT_DATA_VALUE, len); 343 if (err < 0) 344 return err; 345 346 err = nft_ct_l3proto_try_module_get(ctx->afi->family); 347 if (err < 0) 348 return err; 349 350 return 0; 351 } 352 353 static int nft_ct_set_init(const struct nft_ctx *ctx, 354 const struct nft_expr *expr, 355 const struct nlattr * const tb[]) 356 { 357 struct nft_ct *priv = nft_expr_priv(expr); 358 unsigned int len; 359 int err; 360 361 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); 362 switch (priv->key) { 363 #ifdef CONFIG_NF_CONNTRACK_MARK 364 case NFT_CT_MARK: 365 len = FIELD_SIZEOF(struct nf_conn, mark); 366 break; 367 #endif 368 default: 369 return -EOPNOTSUPP; 370 } 371 372 priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]); 373 err = nft_validate_register_load(priv->sreg, len); 374 if (err < 0) 375 return err; 376 377 err = nft_ct_l3proto_try_module_get(ctx->afi->family); 378 if (err < 0) 379 return err; 380 381 return 0; 382 } 383 384 static void nft_ct_destroy(const struct nft_ctx *ctx, 385 const struct nft_expr *expr) 386 { 387 nft_ct_l3proto_module_put(ctx->afi->family); 388 } 389 390 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) 391 { 392 const struct nft_ct *priv = nft_expr_priv(expr); 393 394 if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg)) 395 goto nla_put_failure; 396 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) 397 goto nla_put_failure; 398 399 switch (priv->key) { 400 case NFT_CT_L3PROTOCOL: 401 case NFT_CT_PROTOCOL: 402 case NFT_CT_SRC: 403 case NFT_CT_DST: 404 case NFT_CT_PROTO_SRC: 405 case NFT_CT_PROTO_DST: 406 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir)) 407 goto nla_put_failure; 408 break; 409 case NFT_CT_BYTES: 410 case NFT_CT_PKTS: 411 if (priv->dir < IP_CT_DIR_MAX && 412 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir)) 413 goto nla_put_failure; 414 break; 415 default: 416 break; 417 } 418 419 return 0; 420 421 nla_put_failure: 422 return -1; 423 } 424 425 static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr) 426 { 427 const struct nft_ct *priv = nft_expr_priv(expr); 428 429 if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg)) 430 goto nla_put_failure; 431 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) 432 goto nla_put_failure; 433 return 0; 434 435 nla_put_failure: 436 return -1; 437 } 438 439 static struct nft_expr_type nft_ct_type; 440 static const struct nft_expr_ops nft_ct_get_ops = { 441 .type = &nft_ct_type, 442 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), 443 .eval = nft_ct_get_eval, 444 .init = nft_ct_get_init, 445 .destroy = nft_ct_destroy, 446 .dump = nft_ct_get_dump, 447 }; 448 449 static const struct nft_expr_ops nft_ct_set_ops = { 450 .type = &nft_ct_type, 451 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), 452 .eval = nft_ct_set_eval, 453 .init = nft_ct_set_init, 454 .destroy = nft_ct_destroy, 455 .dump = nft_ct_set_dump, 456 }; 457 458 static const struct nft_expr_ops * 459 nft_ct_select_ops(const struct nft_ctx *ctx, 460 const struct nlattr * const tb[]) 461 { 462 if (tb[NFTA_CT_KEY] == NULL) 463 return ERR_PTR(-EINVAL); 464 465 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG]) 466 return ERR_PTR(-EINVAL); 467 468 if (tb[NFTA_CT_DREG]) 469 return &nft_ct_get_ops; 470 471 if (tb[NFTA_CT_SREG]) 472 return &nft_ct_set_ops; 473 474 return ERR_PTR(-EINVAL); 475 } 476 477 static struct nft_expr_type nft_ct_type __read_mostly = { 478 .name = "ct", 479 .select_ops = &nft_ct_select_ops, 480 .policy = nft_ct_policy, 481 .maxattr = NFTA_CT_MAX, 482 .owner = THIS_MODULE, 483 }; 484 485 static int __init nft_ct_module_init(void) 486 { 487 return nft_register_expr(&nft_ct_type); 488 } 489 490 static void __exit nft_ct_module_exit(void) 491 { 492 nft_unregister_expr(&nft_ct_type); 493 } 494 495 module_init(nft_ct_module_init); 496 module_exit(nft_ct_module_exit); 497 498 MODULE_LICENSE("GPL"); 499 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 500 MODULE_ALIAS_NFT_EXPR("ct"); 501