blob: c4bdab47597f071c35cb73f45570552777c8ad48 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* module that allows mangling of the arp payload */
2#include <linux/module.h>
3#include <linux/netfilter_arp/arpt_mangle.h>
4#include <net/sock.h>
5
6MODULE_LICENSE("GPL");
7MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
8MODULE_DESCRIPTION("arptables arp payload mangle target");
9
10static unsigned int
Patrick McHardyc4986732006-03-20 18:02:56 -080011target(struct sk_buff **pskb,
12 const struct net_device *in, const struct net_device *out,
13 unsigned int hooknum, const struct xt_target *target,
Patrick McHardyfe1cb102006-08-22 00:35:47 -070014 const void *targinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015{
16 const struct arpt_mangle *mangle = targinfo;
17 struct arphdr *arp;
18 unsigned char *arpptr;
19 int pln, hln;
20
21 if (skb_shared(*pskb) || skb_cloned(*pskb)) {
22 struct sk_buff *nskb;
23
24 nskb = skb_copy(*pskb, GFP_ATOMIC);
25 if (!nskb)
26 return NF_DROP;
27 if ((*pskb)->sk)
28 skb_set_owner_w(nskb, (*pskb)->sk);
29 kfree_skb(*pskb);
30 *pskb = nskb;
31 }
32
Arnaldo Carvalho de Melod0a92be2007-03-12 20:56:31 -030033 arp = arp_hdr(*pskb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -070034 arpptr = skb_network_header(*pskb) + sizeof(*arp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 pln = arp->ar_pln;
36 hln = arp->ar_hln;
37 /* We assume that pln and hln were checked in the match */
38 if (mangle->flags & ARPT_MANGLE_SDEV) {
39 if (ARPT_DEV_ADDR_LEN_MAX < hln ||
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -070040 (arpptr + hln > skb_tail_pointer(*pskb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 return NF_DROP;
42 memcpy(arpptr, mangle->src_devaddr, hln);
43 }
44 arpptr += hln;
45 if (mangle->flags & ARPT_MANGLE_SIP) {
46 if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -070047 (arpptr + pln > skb_tail_pointer(*pskb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 return NF_DROP;
49 memcpy(arpptr, &mangle->u_s.src_ip, pln);
50 }
51 arpptr += pln;
52 if (mangle->flags & ARPT_MANGLE_TDEV) {
53 if (ARPT_DEV_ADDR_LEN_MAX < hln ||
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -070054 (arpptr + hln > skb_tail_pointer(*pskb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 return NF_DROP;
56 memcpy(arpptr, mangle->tgt_devaddr, hln);
57 }
58 arpptr += hln;
59 if (mangle->flags & ARPT_MANGLE_TIP) {
60 if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -070061 (arpptr + pln > skb_tail_pointer(*pskb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 return NF_DROP;
63 memcpy(arpptr, &mangle->u_t.tgt_ip, pln);
64 }
65 return mangle->target;
66}
67
Jan Engelhardte1931b72007-07-07 22:16:26 -070068static bool
Patrick McHardyc4986732006-03-20 18:02:56 -080069checkentry(const char *tablename, const void *e, const struct xt_target *target,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090070 void *targinfo, unsigned int hook_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
72 const struct arpt_mangle *mangle = targinfo;
73
74 if (mangle->flags & ~ARPT_MANGLE_MASK ||
75 !(mangle->flags & ARPT_MANGLE_MASK))
Jan Engelhardte1931b72007-07-07 22:16:26 -070076 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78 if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
79 mangle->target != ARPT_CONTINUE)
Jan Engelhardte1931b72007-07-07 22:16:26 -070080 return false;
81 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
Patrick McHardy9f15c532007-07-07 22:22:02 -070084static struct arpt_target arpt_mangle_reg __read_mostly = {
Patrick McHardyaa83c1a2006-03-20 18:01:28 -080085 .name = "mangle",
86 .target = target,
87 .targetsize = sizeof(struct arpt_mangle),
88 .checkentry = checkentry,
89 .me = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -070090};
91
Andrew Morton65b4b4e2006-03-28 16:37:06 -080092static int __init arpt_mangle_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 if (arpt_register_target(&arpt_mangle_reg))
95 return -EINVAL;
96
97 return 0;
98}
99
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800100static void __exit arpt_mangle_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
102 arpt_unregister_target(&arpt_mangle_reg);
103}
104
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800105module_init(arpt_mangle_init);
106module_exit(arpt_mangle_fini);