]>
Commit | Line | Data |
---|---|---|
0ac4f893 HW |
1 | /* |
2 | * Hop Limit modification target for ip6tables | |
3 | * Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
4 | * Based on HW's TTL module | |
5 | * | |
6 | * This software is distributed under the terms of GNU GPL | |
7 | */ | |
8 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/skbuff.h> | |
11 | #include <linux/ip.h> | |
12 | ||
13 | #include <linux/netfilter_ipv6/ip6_tables.h> | |
14 | #include <linux/netfilter_ipv6/ip6t_HL.h> | |
15 | ||
16 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
17 | MODULE_DESCRIPTION("IP tables Hop Limit modification module"); | |
18 | MODULE_LICENSE("GPL"); | |
19 | ||
20 | static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |
21 | const struct net_device *in, | |
22 | const struct net_device *out, | |
23 | unsigned int hooknum, | |
24 | const void *targinfo, void *userinfo) | |
25 | { | |
26 | struct ipv6hdr *ip6h; | |
27 | const struct ip6t_HL_info *info = targinfo; | |
28 | u_int16_t diffs[2]; | |
29 | int new_hl; | |
30 | ||
31 | if (!skb_make_writable(pskb, (*pskb)->len)) | |
32 | return NF_DROP; | |
33 | ||
34 | ip6h = (*pskb)->nh.ipv6h; | |
35 | ||
36 | switch (info->mode) { | |
37 | case IP6T_HL_SET: | |
38 | new_hl = info->hop_limit; | |
39 | break; | |
40 | case IP6T_HL_INC: | |
41 | new_hl = ip6h->hop_limit + info->hop_limit; | |
42 | if (new_hl > 255) | |
43 | new_hl = 255; | |
44 | break; | |
45 | case IP6T_HL_DEC: | |
46 | new_hl = ip6h->hop_limit - info->hop_limit; | |
47 | if (new_hl < 0) | |
48 | new_hl = 0; | |
49 | break; | |
50 | default: | |
51 | new_hl = ip6h->hop_limit; | |
52 | break; | |
53 | } | |
54 | ||
55 | if (new_hl != ip6h->hop_limit) { | |
56 | diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF; | |
57 | ip6h->hop_limit = new_hl; | |
58 | diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8); | |
59 | } | |
60 | ||
61 | return IP6T_CONTINUE; | |
62 | } | |
63 | ||
64 | static int ip6t_hl_checkentry(const char *tablename, | |
2e4e6a17 | 65 | const void *entry, |
0ac4f893 HW |
66 | void *targinfo, |
67 | unsigned int targinfosize, | |
68 | unsigned int hook_mask) | |
69 | { | |
70 | struct ip6t_HL_info *info = targinfo; | |
71 | ||
72 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) { | |
73 | printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n", | |
74 | targinfosize, | |
75 | IP6T_ALIGN(sizeof(struct ip6t_HL_info))); | |
76 | return 0; | |
77 | } | |
78 | ||
79 | if (strcmp(tablename, "mangle")) { | |
80 | printk(KERN_WARNING "ip6t_HL: can only be called from " | |
81 | "\"mangle\" table, not \"%s\"\n", tablename); | |
82 | return 0; | |
83 | } | |
84 | ||
85 | if (info->mode > IP6T_HL_MAXMODE) { | |
86 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | |
87 | info->mode); | |
88 | return 0; | |
89 | } | |
90 | ||
91 | if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { | |
92 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | |
93 | "make sense with value 0\n"); | |
94 | return 0; | |
95 | } | |
96 | ||
97 | return 1; | |
98 | } | |
99 | ||
100 | static struct ip6t_target ip6t_HL = { | |
101 | .name = "HL", | |
102 | .target = ip6t_hl_target, | |
103 | .checkentry = ip6t_hl_checkentry, | |
104 | .me = THIS_MODULE | |
105 | }; | |
106 | ||
107 | static int __init init(void) | |
108 | { | |
109 | return ip6t_register_target(&ip6t_HL); | |
110 | } | |
111 | ||
112 | static void __exit fini(void) | |
113 | { | |
114 | ip6t_unregister_target(&ip6t_HL); | |
115 | } | |
116 | ||
117 | module_init(init); | |
118 | module_exit(fini); |