1/* 2 * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x. 3 * 4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling 5 * 6 * Extended to all five netfilter hooks by Brad Chapman & Harald Welte 7 */ 8#include <linux/config.h> 9#include <linux/module.h> 10#include <linux/netfilter_ipv4/ip_tables.h> 11#include <linux/netdevice.h> 12#include <linux/skbuff.h> 13#include <net/sock.h> 14#include <net/route.h> 15#include <linux/ip.h> 16 17#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \ 18 (1 << NF_IP_LOCAL_IN) | \ 19 (1 << NF_IP_FORWARD) | \ 20 (1 << NF_IP_LOCAL_OUT) | \ 21 (1 << NF_IP_POST_ROUTING)) 22 23/* Standard entry. */ 24struct ipt_standard 25{ 26 struct ipt_entry entry; 27 struct ipt_standard_target target; 28}; 29 30struct ipt_error_target 31{ 32 struct ipt_entry_target target; 33 char errorname[IPT_FUNCTION_MAXNAMELEN]; 34}; 35 36struct ipt_error 37{ 38 struct ipt_entry entry; 39 struct ipt_error_target target; 40}; 41 42/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */ 43static struct 44{ 45 struct ipt_replace repl; 46 struct ipt_standard entries[5]; 47 struct ipt_error term; 48} initial_table __initdata 49= { { "mangle", MANGLE_VALID_HOOKS, 6, 50 sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error), 51 { [NF_IP_PRE_ROUTING] 0, 52 [NF_IP_LOCAL_IN] sizeof(struct ipt_standard), 53 [NF_IP_FORWARD] sizeof(struct ipt_standard) * 2, 54 [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 3, 55 [NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 4 }, 56 { [NF_IP_PRE_ROUTING] 0, 57 [NF_IP_LOCAL_IN] sizeof(struct ipt_standard), 58 [NF_IP_FORWARD] sizeof(struct ipt_standard) * 2, 59 [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 3, 60 [NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 4 }, 61 0, NULL, { } }, 62 { 63 /* PRE_ROUTING */ 64 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 65 0, 66 sizeof(struct ipt_entry), 67 sizeof(struct ipt_standard), 68 0, { 0, 0 }, { } }, 69 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, 70 -NF_ACCEPT - 1 } }, 71 /* LOCAL_IN */ 72 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 73 0, 74 sizeof(struct ipt_entry), 75 sizeof(struct ipt_standard), 76 0, { 0, 0 }, { } }, 77 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, 78 -NF_ACCEPT - 1 } }, 79 /* FORWARD */ 80 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 81 0, 82 sizeof(struct ipt_entry), 83 sizeof(struct ipt_standard), 84 0, { 0, 0 }, { } }, 85 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, 86 -NF_ACCEPT - 1 } }, 87 /* LOCAL_OUT */ 88 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 89 0, 90 sizeof(struct ipt_entry), 91 sizeof(struct ipt_standard), 92 0, { 0, 0 }, { } }, 93 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, 94 -NF_ACCEPT - 1 } }, 95 /* POST_ROUTING */ 96 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 97 0, 98 sizeof(struct ipt_entry), 99 sizeof(struct ipt_standard), 100 0, { 0, 0 }, { } }, 101 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, 102 -NF_ACCEPT - 1 } }, 103 }, 104 /* ERROR */ 105 { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 106 0, 107 sizeof(struct ipt_entry), 108 sizeof(struct ipt_error), 109 0, { 0, 0 }, { } }, 110 { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, 111 { } }, 112 "ERROR" 113 } 114 } 115}; 116 117static struct ipt_table packet_mangler 118= { { NULL, NULL }, "mangle", &initial_table.repl, 119 MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE }; 120 121/* The work comes in here from netfilter.c. */ 122static unsigned int 123ipt_route_hook(unsigned int hook, 124 struct sk_buff **pskb, 125 const struct net_device *in, 126 const struct net_device *out, 127 int (*okfn)(struct sk_buff *)) 128{ 129 return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); 130} 131 132static unsigned int 133ipt_local_hook(unsigned int hook, 134 struct sk_buff **pskb, 135 const struct net_device *in, 136 const struct net_device *out, 137 int (*okfn)(struct sk_buff *)) 138{ 139 unsigned int ret; 140 u_int8_t tos; 141 u_int32_t saddr, daddr; 142 unsigned long nfmark; 143 144 /* root is playing with raw sockets. */ 145 if ((*pskb)->len < sizeof(struct iphdr) 146 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { 147 if (net_ratelimit()) 148 printk("ipt_hook: happy cracking.\n"); 149 return NF_ACCEPT; 150 } 151 152 /* Save things which could affect route */ 153 nfmark = (*pskb)->nfmark; 154 saddr = (*pskb)->nh.iph->saddr; 155 daddr = (*pskb)->nh.iph->daddr; 156 tos = (*pskb)->nh.iph->tos; 157 158 ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); 159 /* Reroute for ANY change. */ 160 if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE 161 && ((*pskb)->nh.iph->saddr != saddr 162 || (*pskb)->nh.iph->daddr != daddr 163 || (*pskb)->nfmark != nfmark 164 || (*pskb)->nh.iph->tos != tos)) 165 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; 166 167 return ret; 168} 169 170static struct nf_hook_ops ipt_ops[] 171= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 172 NF_IP_PRI_MANGLE }, 173 { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN, 174 NF_IP_PRI_MANGLE }, 175 { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD, 176 NF_IP_PRI_MANGLE }, 177 { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT, 178 NF_IP_PRI_MANGLE }, 179 { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING, 180 NF_IP_PRI_MANGLE } 181}; 182 183static int __init init(void) 184{ 185 int ret; 186 187 /* Register table */ 188 ret = ipt_register_table(&packet_mangler); 189 if (ret < 0) 190 return ret; 191 192 /* Register hooks */ 193 ret = nf_register_hook(&ipt_ops[0]); 194 if (ret < 0) 195 goto cleanup_table; 196 197 ret = nf_register_hook(&ipt_ops[1]); 198 if (ret < 0) 199 goto cleanup_hook0; 200 201 ret = nf_register_hook(&ipt_ops[2]); 202 if (ret < 0) 203 goto cleanup_hook1; 204 205 ret = nf_register_hook(&ipt_ops[3]); 206 if (ret < 0) 207 goto cleanup_hook2; 208 209 ret = nf_register_hook(&ipt_ops[4]); 210 if (ret < 0) 211 goto cleanup_hook3; 212 213 return ret; 214 215 cleanup_hook3: 216 nf_unregister_hook(&ipt_ops[3]); 217 cleanup_hook2: 218 nf_unregister_hook(&ipt_ops[2]); 219 cleanup_hook1: 220 nf_unregister_hook(&ipt_ops[1]); 221 cleanup_hook0: 222 nf_unregister_hook(&ipt_ops[0]); 223 cleanup_table: 224 ipt_unregister_table(&packet_mangler); 225 226 return ret; 227} 228 229static void __exit fini(void) 230{ 231 unsigned int i; 232 233 for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) 234 nf_unregister_hook(&ipt_ops[i]); 235 236 ipt_unregister_table(&packet_mangler); 237} 238 239module_init(init); 240module_exit(fini); 241MODULE_LICENSE("GPL"); 242