xt_DSCP.c (3883B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8 3 * 4 * (C) 2002 by Harald Welte <laforge@netfilter.org> 5 * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com> 6 * 7 * See RFC2474 for a description of the DSCP field within the IP Header. 8*/ 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10#include <linux/module.h> 11#include <linux/skbuff.h> 12#include <linux/ip.h> 13#include <linux/ipv6.h> 14#include <net/dsfield.h> 15 16#include <linux/netfilter/x_tables.h> 17#include <linux/netfilter/xt_DSCP.h> 18 19MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 20MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); 21MODULE_LICENSE("GPL"); 22MODULE_ALIAS("ipt_DSCP"); 23MODULE_ALIAS("ip6t_DSCP"); 24MODULE_ALIAS("ipt_TOS"); 25MODULE_ALIAS("ip6t_TOS"); 26 27static unsigned int 28dscp_tg(struct sk_buff *skb, const struct xt_action_param *par) 29{ 30 const struct xt_DSCP_info *dinfo = par->targinfo; 31 u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; 32 33 if (dscp != dinfo->dscp) { 34 if (skb_ensure_writable(skb, sizeof(struct iphdr))) 35 return NF_DROP; 36 37 ipv4_change_dsfield(ip_hdr(skb), 38 (__force __u8)(~XT_DSCP_MASK), 39 dinfo->dscp << XT_DSCP_SHIFT); 40 41 } 42 return XT_CONTINUE; 43} 44 45static unsigned int 46dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par) 47{ 48 const struct xt_DSCP_info *dinfo = par->targinfo; 49 u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; 50 51 if (dscp != dinfo->dscp) { 52 if (skb_ensure_writable(skb, sizeof(struct ipv6hdr))) 53 return NF_DROP; 54 55 ipv6_change_dsfield(ipv6_hdr(skb), 56 (__force __u8)(~XT_DSCP_MASK), 57 dinfo->dscp << XT_DSCP_SHIFT); 58 } 59 return XT_CONTINUE; 60} 61 62static int dscp_tg_check(const struct xt_tgchk_param *par) 63{ 64 const struct xt_DSCP_info *info = par->targinfo; 65 66 if (info->dscp > XT_DSCP_MAX) 67 return -EDOM; 68 return 0; 69} 70 71static unsigned int 72tos_tg(struct sk_buff *skb, const struct xt_action_param *par) 73{ 74 const struct xt_tos_target_info *info = par->targinfo; 75 struct iphdr *iph = ip_hdr(skb); 76 u_int8_t orig, nv; 77 78 orig = ipv4_get_dsfield(iph); 79 nv = (orig & ~info->tos_mask) ^ info->tos_value; 80 81 if (orig != nv) { 82 if (skb_ensure_writable(skb, sizeof(struct iphdr))) 83 return NF_DROP; 84 iph = ip_hdr(skb); 85 ipv4_change_dsfield(iph, 0, nv); 86 } 87 88 return XT_CONTINUE; 89} 90 91static unsigned int 92tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) 93{ 94 const struct xt_tos_target_info *info = par->targinfo; 95 struct ipv6hdr *iph = ipv6_hdr(skb); 96 u_int8_t orig, nv; 97 98 orig = ipv6_get_dsfield(iph); 99 nv = (orig & ~info->tos_mask) ^ info->tos_value; 100 101 if (orig != nv) { 102 if (skb_ensure_writable(skb, sizeof(struct iphdr))) 103 return NF_DROP; 104 iph = ipv6_hdr(skb); 105 ipv6_change_dsfield(iph, 0, nv); 106 } 107 108 return XT_CONTINUE; 109} 110 111static struct xt_target dscp_tg_reg[] __read_mostly = { 112 { 113 .name = "DSCP", 114 .family = NFPROTO_IPV4, 115 .checkentry = dscp_tg_check, 116 .target = dscp_tg, 117 .targetsize = sizeof(struct xt_DSCP_info), 118 .table = "mangle", 119 .me = THIS_MODULE, 120 }, 121 { 122 .name = "DSCP", 123 .family = NFPROTO_IPV6, 124 .checkentry = dscp_tg_check, 125 .target = dscp_tg6, 126 .targetsize = sizeof(struct xt_DSCP_info), 127 .table = "mangle", 128 .me = THIS_MODULE, 129 }, 130 { 131 .name = "TOS", 132 .revision = 1, 133 .family = NFPROTO_IPV4, 134 .table = "mangle", 135 .target = tos_tg, 136 .targetsize = sizeof(struct xt_tos_target_info), 137 .me = THIS_MODULE, 138 }, 139 { 140 .name = "TOS", 141 .revision = 1, 142 .family = NFPROTO_IPV6, 143 .table = "mangle", 144 .target = tos_tg6, 145 .targetsize = sizeof(struct xt_tos_target_info), 146 .me = THIS_MODULE, 147 }, 148}; 149 150static int __init dscp_tg_init(void) 151{ 152 return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); 153} 154 155static void __exit dscp_tg_exit(void) 156{ 157 xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); 158} 159 160module_init(dscp_tg_init); 161module_exit(dscp_tg_exit);