1 /* 2 * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6 3 * 4 * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org> 5 * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Extended to all five netfilter hooks by Brad Chapman & Harald Welte 12 */ 13 #include <linux/module.h> 14 #include <linux/netfilter_ipv6/ip6_tables.h> 15 16 MODULE_LICENSE("GPL"); 17 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 18 MODULE_DESCRIPTION("ip6tables mangle table"); 19 20 #define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \ 21 (1 << NF_IP6_LOCAL_IN) | \ 22 (1 << NF_IP6_FORWARD) | \ 23 (1 << NF_IP6_LOCAL_OUT) | \ 24 (1 << NF_IP6_POST_ROUTING)) 25 26 #if 0 27 #define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args) 28 #else 29 #define DEBUGP(x, args...) 30 #endif 31 32 /* Standard entry. */ 33 struct ip6t_standard 34 { 35 struct ip6t_entry entry; 36 struct ip6t_standard_target target; 37 }; 38 39 struct ip6t_error_target 40 { 41 struct ip6t_entry_target target; 42 char errorname[IP6T_FUNCTION_MAXNAMELEN]; 43 }; 44 45 struct ip6t_error 46 { 47 struct ip6t_entry entry; 48 struct ip6t_error_target target; 49 }; 50 51 static struct 52 { 53 struct ip6t_replace repl; 54 struct ip6t_standard entries[5]; 55 struct ip6t_error term; 56 } initial_table __initdata 57 = { { "mangle", MANGLE_VALID_HOOKS, 6, 58 sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), 59 { [NF_IP6_PRE_ROUTING] = 0, 60 [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), 61 [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, 62 [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, 63 [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4}, 64 { [NF_IP6_PRE_ROUTING] = 0, 65 [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), 66 [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, 67 [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, 68 [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4}, 69 0, NULL, { } }, 70 { 71 /* PRE_ROUTING */ 72 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 73 0, 74 sizeof(struct ip6t_entry), 75 sizeof(struct ip6t_standard), 76 0, { 0, 0 }, { } }, 77 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 78 -NF_ACCEPT - 1 } }, 79 /* LOCAL_IN */ 80 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 81 0, 82 sizeof(struct ip6t_entry), 83 sizeof(struct ip6t_standard), 84 0, { 0, 0 }, { } }, 85 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 86 -NF_ACCEPT - 1 } }, 87 /* FORWARD */ 88 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 89 0, 90 sizeof(struct ip6t_entry), 91 sizeof(struct ip6t_standard), 92 0, { 0, 0 }, { } }, 93 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 94 -NF_ACCEPT - 1 } }, 95 /* LOCAL_OUT */ 96 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 97 0, 98 sizeof(struct ip6t_entry), 99 sizeof(struct ip6t_standard), 100 0, { 0, 0 }, { } }, 101 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 102 -NF_ACCEPT - 1 } }, 103 /* POST_ROUTING */ 104 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 105 0, 106 sizeof(struct ip6t_entry), 107 sizeof(struct ip6t_standard), 108 0, { 0, 0 }, { } }, 109 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 110 -NF_ACCEPT - 1 } } 111 }, 112 /* ERROR */ 113 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 114 0, 115 sizeof(struct ip6t_entry), 116 sizeof(struct ip6t_error), 117 0, { 0, 0 }, { } }, 118 { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, 119 { } }, 120 "ERROR" 121 } 122 } 123 }; 124 125 static struct ip6t_table packet_mangler = { 126 .name = "mangle", 127 .valid_hooks = MANGLE_VALID_HOOKS, 128 .lock = RW_LOCK_UNLOCKED, 129 .me = THIS_MODULE, 130 }; 131 132 /* The work comes in here from netfilter.c. */ 133 static unsigned int 134 ip6t_route_hook(unsigned int hook, 135 struct sk_buff **pskb, 136 const struct net_device *in, 137 const struct net_device *out, 138 int (*okfn)(struct sk_buff *)) 139 { 140 return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); 141 } 142 143 static unsigned int 144 ip6t_local_hook(unsigned int hook, 145 struct sk_buff **pskb, 146 const struct net_device *in, 147 const struct net_device *out, 148 int (*okfn)(struct sk_buff *)) 149 { 150 151 unsigned long nfmark; 152 unsigned int ret; 153 struct in6_addr saddr, daddr; 154 u_int8_t hop_limit; 155 u_int32_t flowlabel; 156 157 #if 0 158 /* root is playing with raw sockets. */ 159 if ((*pskb)->len < sizeof(struct iphdr) 160 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { 161 if (net_ratelimit()) 162 printk("ip6t_hook: happy cracking.\n"); 163 return NF_ACCEPT; 164 } 165 #endif 166 167 /* save source/dest address, nfmark, hoplimit, flowlabel, priority, */ 168 memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr)); 169 memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr)); 170 nfmark = (*pskb)->nfmark; 171 hop_limit = (*pskb)->nh.ipv6h->hop_limit; 172 173 /* flowlabel and prio (includes version, which shouldn't change either */ 174 flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); 175 176 ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); 177 178 if (ret != NF_DROP && ret != NF_STOLEN 179 && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) 180 || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) 181 || (*pskb)->nfmark != nfmark 182 || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) { 183 184 /* something which could affect routing has changed */ 185 186 DEBUGP("ip6table_mangle: we'd need to re-route a packet\n"); 187 } 188 189 return ret; 190 } 191 192 static struct nf_hook_ops ip6t_ops[] = { 193 { 194 .hook = ip6t_route_hook, 195 .owner = THIS_MODULE, 196 .pf = PF_INET6, 197 .hooknum = NF_IP6_PRE_ROUTING, 198 .priority = NF_IP6_PRI_MANGLE, 199 }, 200 { 201 .hook = ip6t_local_hook, 202 .owner = THIS_MODULE, 203 .pf = PF_INET6, 204 .hooknum = NF_IP6_LOCAL_IN, 205 .priority = NF_IP6_PRI_MANGLE, 206 }, 207 { 208 .hook = ip6t_route_hook, 209 .owner = THIS_MODULE, 210 .pf = PF_INET6, 211 .hooknum = NF_IP6_FORWARD, 212 .priority = NF_IP6_PRI_MANGLE, 213 }, 214 { 215 .hook = ip6t_local_hook, 216 .owner = THIS_MODULE, 217 .pf = PF_INET6, 218 .hooknum = NF_IP6_LOCAL_OUT, 219 .priority = NF_IP6_PRI_MANGLE, 220 }, 221 { 222 .hook = ip6t_route_hook, 223 .owner = THIS_MODULE, 224 .pf = PF_INET6, 225 .hooknum = NF_IP6_POST_ROUTING, 226 .priority = NF_IP6_PRI_MANGLE, 227 }, 228 }; 229 230 static int __init init(void) 231 { 232 int ret; 233 234 /* Register table */ 235 ret = ip6t_register_table(&packet_mangler, &initial_table.repl); 236 if (ret < 0) 237 return ret; 238 239 /* Register hooks */ 240 ret = nf_register_hook(&ip6t_ops[0]); 241 if (ret < 0) 242 goto cleanup_table; 243 244 ret = nf_register_hook(&ip6t_ops[1]); 245 if (ret < 0) 246 goto cleanup_hook0; 247 248 ret = nf_register_hook(&ip6t_ops[2]); 249 if (ret < 0) 250 goto cleanup_hook1; 251 252 ret = nf_register_hook(&ip6t_ops[3]); 253 if (ret < 0) 254 goto cleanup_hook2; 255 256 ret = nf_register_hook(&ip6t_ops[4]); 257 if (ret < 0) 258 goto cleanup_hook3; 259 260 return ret; 261 262 cleanup_hook3: 263 nf_unregister_hook(&ip6t_ops[3]); 264 cleanup_hook2: 265 nf_unregister_hook(&ip6t_ops[2]); 266 cleanup_hook1: 267 nf_unregister_hook(&ip6t_ops[1]); 268 cleanup_hook0: 269 nf_unregister_hook(&ip6t_ops[0]); 270 cleanup_table: 271 ip6t_unregister_table(&packet_mangler); 272 273 return ret; 274 } 275 276 static void __exit fini(void) 277 { 278 unsigned int i; 279 280 for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) 281 nf_unregister_hook(&ip6t_ops[i]); 282 283 ip6t_unregister_table(&packet_mangler); 284 } 285 286 module_init(init); 287 module_exit(fini); 288