xref: /openbmc/linux/net/netfilter/xt_CHECKSUM.c (revision 7b7fd0ac7dc1ffcaf24d9bca0f051b0168e43cd4)
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
checksum_tg(struct sk_buff * skb,const struct xt_action_param * par)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  
checksum_tg_check(const struct xt_tgchk_param * par)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  	{
68  		.name		= "CHECKSUM",
69  		.family		= NFPROTO_IPV4,
70  		.target		= checksum_tg,
71  		.targetsize	= sizeof(struct xt_CHECKSUM_info),
72  		.table		= "mangle",
73  		.checkentry	= checksum_tg_check,
74  		.me		= THIS_MODULE,
75  	},
76  #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
77  	{
78  		.name		= "CHECKSUM",
79  		.family		= NFPROTO_IPV6,
80  		.target		= checksum_tg,
81  		.targetsize	= sizeof(struct xt_CHECKSUM_info),
82  		.table		= "mangle",
83  		.checkentry	= checksum_tg_check,
84  		.me		= THIS_MODULE,
85  	},
86  #endif
87  };
88  
checksum_tg_init(void)89  static int __init checksum_tg_init(void)
90  {
91  	return xt_register_targets(checksum_tg_reg, ARRAY_SIZE(checksum_tg_reg));
92  }
93  
checksum_tg_exit(void)94  static void __exit checksum_tg_exit(void)
95  {
96  	xt_unregister_targets(checksum_tg_reg, ARRAY_SIZE(checksum_tg_reg));
97  }
98  
99  module_init(checksum_tg_init);
100  module_exit(checksum_tg_exit);
101