0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 #include <linux/module.h>
0011 #include <linux/skbuff.h>
0012 #include <linux/ip.h>
0013 #include <linux/ipv6.h>
0014 #include <net/dsfield.h>
0015
0016 #include <linux/netfilter/x_tables.h>
0017 #include <linux/netfilter/xt_DSCP.h>
0018
0019 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
0020 MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification");
0021 MODULE_LICENSE("GPL");
0022 MODULE_ALIAS("ipt_DSCP");
0023 MODULE_ALIAS("ip6t_DSCP");
0024 MODULE_ALIAS("ipt_TOS");
0025 MODULE_ALIAS("ip6t_TOS");
0026
0027 #define XT_DSCP_ECN_MASK 3u
0028
0029 static unsigned int
0030 dscp_tg(struct sk_buff *skb, const struct xt_action_param *par)
0031 {
0032 const struct xt_DSCP_info *dinfo = par->targinfo;
0033 u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
0034
0035 if (dscp != dinfo->dscp) {
0036 if (skb_ensure_writable(skb, sizeof(struct iphdr)))
0037 return NF_DROP;
0038
0039 ipv4_change_dsfield(ip_hdr(skb), XT_DSCP_ECN_MASK,
0040 dinfo->dscp << XT_DSCP_SHIFT);
0041
0042 }
0043 return XT_CONTINUE;
0044 }
0045
0046 static unsigned int
0047 dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par)
0048 {
0049 const struct xt_DSCP_info *dinfo = par->targinfo;
0050 u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
0051
0052 if (dscp != dinfo->dscp) {
0053 if (skb_ensure_writable(skb, sizeof(struct ipv6hdr)))
0054 return NF_DROP;
0055
0056 ipv6_change_dsfield(ipv6_hdr(skb), XT_DSCP_ECN_MASK,
0057 dinfo->dscp << XT_DSCP_SHIFT);
0058 }
0059 return XT_CONTINUE;
0060 }
0061
0062 static int dscp_tg_check(const struct xt_tgchk_param *par)
0063 {
0064 const struct xt_DSCP_info *info = par->targinfo;
0065
0066 if (info->dscp > XT_DSCP_MAX)
0067 return -EDOM;
0068 return 0;
0069 }
0070
0071 static unsigned int
0072 tos_tg(struct sk_buff *skb, const struct xt_action_param *par)
0073 {
0074 const struct xt_tos_target_info *info = par->targinfo;
0075 struct iphdr *iph = ip_hdr(skb);
0076 u_int8_t orig, nv;
0077
0078 orig = ipv4_get_dsfield(iph);
0079 nv = (orig & ~info->tos_mask) ^ info->tos_value;
0080
0081 if (orig != nv) {
0082 if (skb_ensure_writable(skb, sizeof(struct iphdr)))
0083 return NF_DROP;
0084 iph = ip_hdr(skb);
0085 ipv4_change_dsfield(iph, 0, nv);
0086 }
0087
0088 return XT_CONTINUE;
0089 }
0090
0091 static unsigned int
0092 tos_tg6(struct sk_buff *skb, const struct xt_action_param *par)
0093 {
0094 const struct xt_tos_target_info *info = par->targinfo;
0095 struct ipv6hdr *iph = ipv6_hdr(skb);
0096 u_int8_t orig, nv;
0097
0098 orig = ipv6_get_dsfield(iph);
0099 nv = (orig & ~info->tos_mask) ^ info->tos_value;
0100
0101 if (orig != nv) {
0102 if (skb_ensure_writable(skb, sizeof(struct iphdr)))
0103 return NF_DROP;
0104 iph = ipv6_hdr(skb);
0105 ipv6_change_dsfield(iph, 0, nv);
0106 }
0107
0108 return XT_CONTINUE;
0109 }
0110
0111 static struct xt_target dscp_tg_reg[] __read_mostly = {
0112 {
0113 .name = "DSCP",
0114 .family = NFPROTO_IPV4,
0115 .checkentry = dscp_tg_check,
0116 .target = dscp_tg,
0117 .targetsize = sizeof(struct xt_DSCP_info),
0118 .table = "mangle",
0119 .me = THIS_MODULE,
0120 },
0121 {
0122 .name = "DSCP",
0123 .family = NFPROTO_IPV6,
0124 .checkentry = dscp_tg_check,
0125 .target = dscp_tg6,
0126 .targetsize = sizeof(struct xt_DSCP_info),
0127 .table = "mangle",
0128 .me = THIS_MODULE,
0129 },
0130 {
0131 .name = "TOS",
0132 .revision = 1,
0133 .family = NFPROTO_IPV4,
0134 .table = "mangle",
0135 .target = tos_tg,
0136 .targetsize = sizeof(struct xt_tos_target_info),
0137 .me = THIS_MODULE,
0138 },
0139 {
0140 .name = "TOS",
0141 .revision = 1,
0142 .family = NFPROTO_IPV6,
0143 .table = "mangle",
0144 .target = tos_tg6,
0145 .targetsize = sizeof(struct xt_tos_target_info),
0146 .me = THIS_MODULE,
0147 },
0148 };
0149
0150 static int __init dscp_tg_init(void)
0151 {
0152 return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
0153 }
0154
0155 static void __exit dscp_tg_exit(void)
0156 {
0157 xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
0158 }
0159
0160 module_init(dscp_tg_init);
0161 module_exit(dscp_tg_exit);