0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/module.h>
0012 #include <linux/skbuff.h>
0013 #include <linux/icmp.h>
0014
0015 #include <linux/netfilter/x_tables.h>
0016 #include <linux/netfilter/xt_HMARK.h>
0017
0018 #include <net/ip.h>
0019 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
0020 #include <net/netfilter/nf_conntrack.h>
0021 #endif
0022 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0023 #include <net/ipv6.h>
0024 #include <linux/netfilter_ipv6/ip6_tables.h>
0025 #endif
0026
0027 MODULE_LICENSE("GPL");
0028 MODULE_AUTHOR("Hans Schillstrom <hans.schillstrom@ericsson.com>");
0029 MODULE_DESCRIPTION("Xtables: packet marking using hash calculation");
0030 MODULE_ALIAS("ipt_HMARK");
0031 MODULE_ALIAS("ip6t_HMARK");
0032
0033 struct hmark_tuple {
0034 __be32 src;
0035 __be32 dst;
0036 union hmark_ports uports;
0037 u8 proto;
0038 };
0039
0040 static inline __be32 hmark_addr6_mask(const __be32 *addr32, const __be32 *mask)
0041 {
0042 return (addr32[0] & mask[0]) ^
0043 (addr32[1] & mask[1]) ^
0044 (addr32[2] & mask[2]) ^
0045 (addr32[3] & mask[3]);
0046 }
0047
0048 static inline __be32
0049 hmark_addr_mask(int l3num, const __be32 *addr32, const __be32 *mask)
0050 {
0051 switch (l3num) {
0052 case AF_INET:
0053 return *addr32 & *mask;
0054 case AF_INET6:
0055 return hmark_addr6_mask(addr32, mask);
0056 }
0057 return 0;
0058 }
0059
0060 static inline void hmark_swap_ports(union hmark_ports *uports,
0061 const struct xt_hmark_info *info)
0062 {
0063 union hmark_ports hp;
0064 u16 src, dst;
0065
0066 hp.b32 = (uports->b32 & info->port_mask.b32) | info->port_set.b32;
0067 src = ntohs(hp.b16.src);
0068 dst = ntohs(hp.b16.dst);
0069
0070 if (dst > src)
0071 uports->v32 = (dst << 16) | src;
0072 else
0073 uports->v32 = (src << 16) | dst;
0074 }
0075
0076 static int
0077 hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,
0078 const struct xt_hmark_info *info)
0079 {
0080 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
0081 enum ip_conntrack_info ctinfo;
0082 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
0083 struct nf_conntrack_tuple *otuple;
0084 struct nf_conntrack_tuple *rtuple;
0085
0086 if (ct == NULL)
0087 return -1;
0088
0089 otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0090 rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
0091
0092 t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.ip6,
0093 info->src_mask.ip6);
0094 t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.ip6,
0095 info->dst_mask.ip6);
0096
0097 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
0098 return 0;
0099
0100 t->proto = nf_ct_protonum(ct);
0101 if (t->proto != IPPROTO_ICMP) {
0102 t->uports.b16.src = otuple->src.u.all;
0103 t->uports.b16.dst = rtuple->src.u.all;
0104 hmark_swap_ports(&t->uports, info);
0105 }
0106
0107 return 0;
0108 #else
0109 return -1;
0110 #endif
0111 }
0112
0113
0114
0115 static inline u32
0116 hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)
0117 {
0118 u32 hash;
0119 u32 src = ntohl(t->src);
0120 u32 dst = ntohl(t->dst);
0121
0122 if (dst < src)
0123 swap(src, dst);
0124
0125 hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd);
0126 hash = hash ^ (t->proto & info->proto_mask);
0127
0128 return reciprocal_scale(hash, info->hmodulus) + info->hoffset;
0129 }
0130
0131 static void
0132 hmark_set_tuple_ports(const struct sk_buff *skb, unsigned int nhoff,
0133 struct hmark_tuple *t, const struct xt_hmark_info *info)
0134 {
0135 int protoff;
0136
0137 protoff = proto_ports_offset(t->proto);
0138 if (protoff < 0)
0139 return;
0140
0141 nhoff += protoff;
0142 if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0)
0143 return;
0144
0145 hmark_swap_ports(&t->uports, info);
0146 }
0147
0148 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0149 static int get_inner6_hdr(const struct sk_buff *skb, int *offset)
0150 {
0151 struct icmp6hdr *icmp6h, _ih6;
0152
0153 icmp6h = skb_header_pointer(skb, *offset, sizeof(_ih6), &_ih6);
0154 if (icmp6h == NULL)
0155 return 0;
0156
0157 if (icmp6h->icmp6_type && icmp6h->icmp6_type < 128) {
0158 *offset += sizeof(struct icmp6hdr);
0159 return 1;
0160 }
0161 return 0;
0162 }
0163
0164 static int
0165 hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t,
0166 const struct xt_hmark_info *info)
0167 {
0168 struct ipv6hdr *ip6, _ip6;
0169 int flag = IP6_FH_F_AUTH;
0170 unsigned int nhoff = 0;
0171 u16 fragoff = 0;
0172 int nexthdr;
0173
0174 ip6 = (struct ipv6hdr *) (skb->data + skb_network_offset(skb));
0175 nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag);
0176 if (nexthdr < 0)
0177 return 0;
0178
0179 if ((flag & IP6_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6))
0180 goto noicmp;
0181
0182 if (get_inner6_hdr(skb, &nhoff)) {
0183 ip6 = skb_header_pointer(skb, nhoff, sizeof(_ip6), &_ip6);
0184 if (ip6 == NULL)
0185 return -1;
0186
0187 flag = IP6_FH_F_AUTH;
0188 nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag);
0189 if (nexthdr < 0)
0190 return -1;
0191 }
0192 noicmp:
0193 t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.ip6);
0194 t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.ip6);
0195
0196 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
0197 return 0;
0198
0199 t->proto = nexthdr;
0200 if (t->proto == IPPROTO_ICMPV6)
0201 return 0;
0202
0203 if (flag & IP6_FH_F_FRAG)
0204 return 0;
0205
0206 hmark_set_tuple_ports(skb, nhoff, t, info);
0207 return 0;
0208 }
0209
0210 static unsigned int
0211 hmark_tg_v6(struct sk_buff *skb, const struct xt_action_param *par)
0212 {
0213 const struct xt_hmark_info *info = par->targinfo;
0214 struct hmark_tuple t;
0215
0216 memset(&t, 0, sizeof(struct hmark_tuple));
0217
0218 if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT)) {
0219 if (hmark_ct_set_htuple(skb, &t, info) < 0)
0220 return XT_CONTINUE;
0221 } else {
0222 if (hmark_pkt_set_htuple_ipv6(skb, &t, info) < 0)
0223 return XT_CONTINUE;
0224 }
0225
0226 skb->mark = hmark_hash(&t, info);
0227 return XT_CONTINUE;
0228 }
0229 #endif
0230
0231 static int get_inner_hdr(const struct sk_buff *skb, int iphsz, int *nhoff)
0232 {
0233 const struct icmphdr *icmph;
0234 struct icmphdr _ih;
0235
0236
0237 icmph = skb_header_pointer(skb, *nhoff + iphsz, sizeof(_ih), &_ih);
0238 if (icmph == NULL || icmph->type > NR_ICMP_TYPES)
0239 return 0;
0240
0241
0242 if (!icmp_is_err(icmph->type))
0243 return 0;
0244
0245 *nhoff += iphsz + sizeof(_ih);
0246 return 1;
0247 }
0248
0249 static int
0250 hmark_pkt_set_htuple_ipv4(const struct sk_buff *skb, struct hmark_tuple *t,
0251 const struct xt_hmark_info *info)
0252 {
0253 struct iphdr *ip, _ip;
0254 int nhoff = skb_network_offset(skb);
0255
0256 ip = (struct iphdr *) (skb->data + nhoff);
0257 if (ip->protocol == IPPROTO_ICMP) {
0258
0259 if (get_inner_hdr(skb, ip->ihl * 4, &nhoff)) {
0260 ip = skb_header_pointer(skb, nhoff, sizeof(_ip), &_ip);
0261 if (ip == NULL)
0262 return -1;
0263 }
0264 }
0265
0266 t->src = ip->saddr & info->src_mask.ip;
0267 t->dst = ip->daddr & info->dst_mask.ip;
0268
0269 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
0270 return 0;
0271
0272 t->proto = ip->protocol;
0273
0274
0275 if (t->proto == IPPROTO_ICMP)
0276 return 0;
0277
0278
0279 if (ip_is_fragment(ip))
0280 return 0;
0281
0282 hmark_set_tuple_ports(skb, (ip->ihl * 4) + nhoff, t, info);
0283
0284 return 0;
0285 }
0286
0287 static unsigned int
0288 hmark_tg_v4(struct sk_buff *skb, const struct xt_action_param *par)
0289 {
0290 const struct xt_hmark_info *info = par->targinfo;
0291 struct hmark_tuple t;
0292
0293 memset(&t, 0, sizeof(struct hmark_tuple));
0294
0295 if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT)) {
0296 if (hmark_ct_set_htuple(skb, &t, info) < 0)
0297 return XT_CONTINUE;
0298 } else {
0299 if (hmark_pkt_set_htuple_ipv4(skb, &t, info) < 0)
0300 return XT_CONTINUE;
0301 }
0302
0303 skb->mark = hmark_hash(&t, info);
0304 return XT_CONTINUE;
0305 }
0306
0307 static int hmark_tg_check(const struct xt_tgchk_param *par)
0308 {
0309 const struct xt_hmark_info *info = par->targinfo;
0310 const char *errmsg = "proto mask must be zero with L3 mode";
0311
0312 if (!info->hmodulus)
0313 return -EINVAL;
0314
0315 if (info->proto_mask &&
0316 (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)))
0317 goto err;
0318
0319 if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK) &&
0320 (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT_MASK) |
0321 XT_HMARK_FLAG(XT_HMARK_DPORT_MASK))))
0322 return -EINVAL;
0323
0324 if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI) &&
0325 (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT) |
0326 XT_HMARK_FLAG(XT_HMARK_DPORT)))) {
0327 errmsg = "spi-set and port-set can't be combined";
0328 goto err;
0329 }
0330 return 0;
0331 err:
0332 pr_info_ratelimited("%s\n", errmsg);
0333 return -EINVAL;
0334 }
0335
0336 static struct xt_target hmark_tg_reg[] __read_mostly = {
0337 {
0338 .name = "HMARK",
0339 .family = NFPROTO_IPV4,
0340 .target = hmark_tg_v4,
0341 .targetsize = sizeof(struct xt_hmark_info),
0342 .checkentry = hmark_tg_check,
0343 .me = THIS_MODULE,
0344 },
0345 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
0346 {
0347 .name = "HMARK",
0348 .family = NFPROTO_IPV6,
0349 .target = hmark_tg_v6,
0350 .targetsize = sizeof(struct xt_hmark_info),
0351 .checkentry = hmark_tg_check,
0352 .me = THIS_MODULE,
0353 },
0354 #endif
0355 };
0356
0357 static int __init hmark_tg_init(void)
0358 {
0359 return xt_register_targets(hmark_tg_reg, ARRAY_SIZE(hmark_tg_reg));
0360 }
0361
0362 static void __exit hmark_tg_exit(void)
0363 {
0364 xt_unregister_targets(hmark_tg_reg, ARRAY_SIZE(hmark_tg_reg));
0365 }
0366
0367 module_init(hmark_tg_init);
0368 module_exit(hmark_tg_exit);