Merge tag 'powerpc-5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / net / netfilter / xt_CHECKSUM.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* iptables module for the packet checksum mangling
3  *
4  * (C) 2002 by Harald Welte <laforge@netfilter.org>
5  * (C) 2010 Red Hat, Inc.
6  *
7  * Author: Michael S. Tsirkin <mst@redhat.com>
8 */
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12
13 #include <linux/netfilter/x_tables.h>
14 #include <linux/netfilter/xt_CHECKSUM.h>
15
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv6/ip6_tables.h>
18
19 MODULE_LICENSE("GPL");
20 MODULE_AUTHOR("Michael S. Tsirkin <mst@redhat.com>");
21 MODULE_DESCRIPTION("Xtables: checksum modification");
22 MODULE_ALIAS("ipt_CHECKSUM");
23 MODULE_ALIAS("ip6t_CHECKSUM");
24
25 static unsigned int
26 checksum_tg(struct sk_buff *skb, const struct xt_action_param *par)
27 {
28         if (skb->ip_summed == CHECKSUM_PARTIAL && !skb_is_gso(skb))
29                 skb_checksum_help(skb);
30
31         return XT_CONTINUE;
32 }
33
34 static int checksum_tg_check(const struct xt_tgchk_param *par)
35 {
36         const struct xt_CHECKSUM_info *einfo = par->targinfo;
37         const struct ip6t_ip6 *i6 = par->entryinfo;
38         const struct ipt_ip *i4 = par->entryinfo;
39
40         if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
41                 pr_info_ratelimited("unsupported CHECKSUM operation %x\n",
42                                     einfo->operation);
43                 return -EINVAL;
44         }
45         if (!einfo->operation)
46                 return -EINVAL;
47
48         switch (par->family) {
49         case NFPROTO_IPV4:
50                 if (i4->proto == IPPROTO_UDP &&
51                     (i4->invflags & XT_INV_PROTO) == 0)
52                         return 0;
53                 break;
54         case NFPROTO_IPV6:
55                 if ((i6->flags & IP6T_F_PROTO) &&
56                     i6->proto == IPPROTO_UDP &&
57                     (i6->invflags & XT_INV_PROTO) == 0)
58                         return 0;
59                 break;
60         }
61
62         pr_warn_once("CHECKSUM should be avoided.  If really needed, restrict with \"-p udp\" and only use in OUTPUT\n");
63         return 0;
64 }
65
66 static struct xt_target checksum_tg_reg __read_mostly = {
67         .name           = "CHECKSUM",
68         .family         = NFPROTO_UNSPEC,
69         .target         = checksum_tg,
70         .targetsize     = sizeof(struct xt_CHECKSUM_info),
71         .table          = "mangle",
72         .checkentry     = checksum_tg_check,
73         .me             = THIS_MODULE,
74 };
75
76 static int __init checksum_tg_init(void)
77 {
78         return xt_register_target(&checksum_tg_reg);
79 }
80
81 static void __exit checksum_tg_exit(void)
82 {
83         xt_unregister_target(&checksum_tg_reg);
84 }
85
86 module_init(checksum_tg_init);
87 module_exit(checksum_tg_exit);