|
10 | 10 | #include <linux/netlink.h> |
11 | 11 | #include <linux/netfilter.h> |
12 | 12 | #include <linux/netfilter/nf_tables.h> |
| 13 | +#include <linux/sctp.h> |
13 | 14 | #include <net/netfilter/nf_tables_core.h> |
14 | 15 | #include <net/netfilter/nf_tables.h> |
| 16 | +#include <net/sctp/sctp.h> |
15 | 17 | #include <net/tcp.h> |
16 | 18 |
|
17 | 19 | struct nft_exthdr { |
@@ -300,6 +302,43 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr, |
300 | 302 | } |
301 | 303 | } |
302 | 304 |
|
| 305 | +static void nft_exthdr_sctp_eval(const struct nft_expr *expr, |
| 306 | + struct nft_regs *regs, |
| 307 | + const struct nft_pktinfo *pkt) |
| 308 | +{ |
| 309 | + unsigned int offset = pkt->xt.thoff + sizeof(struct sctphdr); |
| 310 | + struct nft_exthdr *priv = nft_expr_priv(expr); |
| 311 | + u32 *dest = ®s->data[priv->dreg]; |
| 312 | + const struct sctp_chunkhdr *sch; |
| 313 | + struct sctp_chunkhdr _sch; |
| 314 | + |
| 315 | + do { |
| 316 | + sch = skb_header_pointer(pkt->skb, offset, sizeof(_sch), &_sch); |
| 317 | + if (!sch || !sch->length) |
| 318 | + break; |
| 319 | + |
| 320 | + if (sch->type == priv->type) { |
| 321 | + if (priv->flags & NFT_EXTHDR_F_PRESENT) { |
| 322 | + nft_reg_store8(dest, true); |
| 323 | + return; |
| 324 | + } |
| 325 | + if (priv->offset + priv->len > ntohs(sch->length) || |
| 326 | + offset + ntohs(sch->length) > pkt->skb->len) |
| 327 | + break; |
| 328 | + |
| 329 | + dest[priv->len / NFT_REG32_SIZE] = 0; |
| 330 | + memcpy(dest, (char *)sch + priv->offset, priv->len); |
| 331 | + return; |
| 332 | + } |
| 333 | + offset += SCTP_PAD4(ntohs(sch->length)); |
| 334 | + } while (offset < pkt->skb->len); |
| 335 | + |
| 336 | + if (priv->flags & NFT_EXTHDR_F_PRESENT) |
| 337 | + nft_reg_store8(dest, false); |
| 338 | + else |
| 339 | + regs->verdict.code = NFT_BREAK; |
| 340 | +} |
| 341 | + |
303 | 342 | static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = { |
304 | 343 | [NFTA_EXTHDR_DREG] = { .type = NLA_U32 }, |
305 | 344 | [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 }, |
@@ -499,6 +538,14 @@ static const struct nft_expr_ops nft_exthdr_tcp_set_ops = { |
499 | 538 | .dump = nft_exthdr_dump_set, |
500 | 539 | }; |
501 | 540 |
|
| 541 | +static const struct nft_expr_ops nft_exthdr_sctp_ops = { |
| 542 | + .type = &nft_exthdr_type, |
| 543 | + .size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)), |
| 544 | + .eval = nft_exthdr_sctp_eval, |
| 545 | + .init = nft_exthdr_init, |
| 546 | + .dump = nft_exthdr_dump, |
| 547 | +}; |
| 548 | + |
502 | 549 | static const struct nft_expr_ops * |
503 | 550 | nft_exthdr_select_ops(const struct nft_ctx *ctx, |
504 | 551 | const struct nlattr * const tb[]) |
@@ -529,6 +576,10 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx, |
529 | 576 | return &nft_exthdr_ipv4_ops; |
530 | 577 | } |
531 | 578 | break; |
| 579 | + case NFT_EXTHDR_OP_SCTP: |
| 580 | + if (tb[NFTA_EXTHDR_DREG]) |
| 581 | + return &nft_exthdr_sctp_ops; |
| 582 | + break; |
532 | 583 | } |
533 | 584 |
|
534 | 585 | return ERR_PTR(-EOPNOTSUPP); |
|
0 commit comments