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 */ 6#include <linux/module.h> 7#include <linux/netfilter_ipv6/ip6_tables.h> 8 9#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \ 10 (1 << NF_IP6_LOCAL_IN) | \ 11 (1 << NF_IP6_FORWARD) | \ 12 (1 << NF_IP6_LOCAL_OUT) | \ 13 (1 << NF_IP6_POST_ROUTING)) 14 15#define DEBUGP(x, args...) 16 17/* Standard entry. */ 18struct ip6t_standard 19{ 20 struct ip6t_entry entry; 21 struct ip6t_standard_target target; 22}; 23 24struct ip6t_error_target 25{ 26 struct ip6t_entry_target target; 27 char errorname[IP6T_FUNCTION_MAXNAMELEN]; 28}; 29 30struct ip6t_error 31{ 32 struct ip6t_entry entry; 33 struct ip6t_error_target target; 34}; 35 36static struct 37{ 38 struct ip6t_replace repl; 39 struct ip6t_standard entries[5]; 40 struct ip6t_error term; 41} initial_table __initdata 42= { { "mangle", MANGLE_VALID_HOOKS, 6, 43 sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), 44 { [NF_IP6_PRE_ROUTING] 0, 45 [NF_IP6_LOCAL_IN] sizeof(struct ip6t_standard), 46 [NF_IP6_FORWARD] sizeof(struct ip6t_standard) * 2, 47 [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) * 3, 48 [NF_IP6_POST_ROUTING] sizeof(struct ip6t_standard) * 4}, 49 { [NF_IP6_PRE_ROUTING] 0, 50 [NF_IP6_LOCAL_IN] sizeof(struct ip6t_standard), 51 [NF_IP6_FORWARD] sizeof(struct ip6t_standard) * 2, 52 [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) * 3, 53 [NF_IP6_POST_ROUTING] sizeof(struct ip6t_standard) * 4}, 54 0, NULL, { } }, 55 { 56 /* PRE_ROUTING */ 57 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 58 0, 59 sizeof(struct ip6t_entry), 60 sizeof(struct ip6t_standard), 61 0, { 0, 0 }, { } }, 62 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 63 -NF_ACCEPT - 1 } }, 64 /* LOCAL_IN */ 65 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 66 0, 67 sizeof(struct ip6t_entry), 68 sizeof(struct ip6t_standard), 69 0, { 0, 0 }, { } }, 70 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 71 -NF_ACCEPT - 1 } }, 72 /* FORWARD */ 73 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 74 0, 75 sizeof(struct ip6t_entry), 76 sizeof(struct ip6t_standard), 77 0, { 0, 0 }, { } }, 78 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 79 -NF_ACCEPT - 1 } }, 80 /* LOCAL_OUT */ 81 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 82 0, 83 sizeof(struct ip6t_entry), 84 sizeof(struct ip6t_standard), 85 0, { 0, 0 }, { } }, 86 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 87 -NF_ACCEPT - 1 } }, 88 /* POST_ROUTING */ 89 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 90 0, 91 sizeof(struct ip6t_entry), 92 sizeof(struct ip6t_standard), 93 0, { 0, 0 }, { } }, 94 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, 95 -NF_ACCEPT - 1 } } 96 }, 97 /* ERROR */ 98 { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 99 0, 100 sizeof(struct ip6t_entry), 101 sizeof(struct ip6t_error), 102 0, { 0, 0 }, { } }, 103 { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, 104 { } }, 105 "ERROR" 106 } 107 } 108}; 109 110static struct ip6t_table packet_mangler 111= { { NULL, NULL }, "mangle", &initial_table.repl, 112 MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE }; 113 114/* The work comes in here from netfilter.c. */ 115static unsigned int 116ip6t_route_hook(unsigned int hook, 117 struct sk_buff **pskb, 118 const struct net_device *in, 119 const struct net_device *out, 120 int (*okfn)(struct sk_buff *)) 121{ 122 return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); 123} 124 125static unsigned int 126ip6t_local_hook(unsigned int hook, 127 struct sk_buff **pskb, 128 const struct net_device *in, 129 const struct net_device *out, 130 int (*okfn)(struct sk_buff *)) 131{ 132 133 unsigned long nfmark; 134 unsigned int ret; 135 struct in6_addr saddr, daddr; 136 u_int8_t hop_limit; 137 u_int32_t flowlabel; 138 139 140 /* save source/dest address, nfmark, hoplimit, flowlabel, priority, */ 141 memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr)); 142 memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr)); 143 nfmark = (*pskb)->nfmark; 144 hop_limit = (*pskb)->nh.ipv6h->hop_limit; 145 146 /* flowlabel and prio (includes version, which shouldn't change either */ 147 flowlabel = (u_int32_t) (*pskb)->nh.ipv6h; 148 149 ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); 150 151 if (ret != NF_DROP && ret != NF_STOLEN 152 && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) 153 || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) 154 || (*pskb)->nfmark != nfmark 155 || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) { 156 157 /* something which could affect routing has changed */ 158 159 DEBUGP("ip6table_mangle: we'd need to re-route a packet\n"); 160 } 161 162 return ret; 163} 164 165static struct nf_hook_ops ip6t_ops[] 166= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE }, 167 { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN, NF_IP6_PRI_MANGLE }, 168 { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD, NF_IP6_PRI_MANGLE }, 169 { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT, NF_IP6_PRI_MANGLE }, 170 { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE } 171}; 172 173static int __init init(void) 174{ 175 int ret; 176 177 /* Register table */ 178 ret = ip6t_register_table(&packet_mangler); 179 if (ret < 0) 180 return ret; 181 182 /* Register hooks */ 183 ret = nf_register_hook(&ip6t_ops[0]); 184 if (ret < 0) 185 goto cleanup_table; 186 187 ret = nf_register_hook(&ip6t_ops[1]); 188 if (ret < 0) 189 goto cleanup_hook0; 190 191 ret = nf_register_hook(&ip6t_ops[2]); 192 if (ret < 0) 193 goto cleanup_hook1; 194 195 ret = nf_register_hook(&ip6t_ops[3]); 196 if (ret < 0) 197 goto cleanup_hook2; 198 199 ret = nf_register_hook(&ip6t_ops[4]); 200 if (ret < 0) 201 goto cleanup_hook3; 202 203 return ret; 204 205 cleanup_hook3: 206 nf_unregister_hook(&ip6t_ops[3]); 207 cleanup_hook2: 208 nf_unregister_hook(&ip6t_ops[2]); 209 cleanup_hook1: 210 nf_unregister_hook(&ip6t_ops[1]); 211 cleanup_hook0: 212 nf_unregister_hook(&ip6t_ops[0]); 213 cleanup_table: 214 ip6t_unregister_table(&packet_mangler); 215 216 return ret; 217} 218 219static void __exit fini(void) 220{ 221 unsigned int i; 222 223 for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) 224 nf_unregister_hook(&ip6t_ops[i]); 225 226 ip6t_unregister_table(&packet_mangler); 227} 228 229module_init(init); 230module_exit(fini); 231MODULE_LICENSE("GPL"); 232