ip_nat_standalone.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* This file contains all the functions required for the standalone
  2.    ip_nat module.
  3.    These are not required by the compatibility layer.
  4. */
  5. /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
  6.  * Public Licence.
  7.  *
  8.  * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
  9.  *  - new API and handling of conntrack/nat helpers
  10.  *  - now capable of multiple expectations for one master
  11.  * */
  12. #include <linux/config.h>
  13. #include <linux/types.h>
  14. #include <linux/ip.h>
  15. #include <linux/netfilter.h>
  16. #include <linux/netfilter_ipv4.h>
  17. #include <linux/module.h>
  18. #include <linux/skbuff.h>
  19. #include <linux/proc_fs.h>
  20. #include <net/checksum.h>
  21. #include <linux/spinlock.h>
  22. #include <linux/version.h>
  23. #include <linux/brlock.h>
  24. #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
  25. #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
  26. #include <linux/netfilter_ipv4/ip_nat.h>
  27. #include <linux/netfilter_ipv4/ip_nat_rule.h>
  28. #include <linux/netfilter_ipv4/ip_nat_protocol.h>
  29. #include <linux/netfilter_ipv4/ip_nat_core.h>
  30. #include <linux/netfilter_ipv4/ip_nat_helper.h>
  31. #include <linux/netfilter_ipv4/ip_tables.h>
  32. #include <linux/netfilter_ipv4/ip_conntrack_core.h>
  33. #include <linux/netfilter_ipv4/listhelp.h>
  34. #if 0
  35. #define DEBUGP printk
  36. #else
  37. #define DEBUGP(format, args...)
  38. #endif
  39. #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING"  
  40.    : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" 
  41.       : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT"  
  42.          : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  
  43.     : "*ERROR*")))
  44. static inline int call_expect(struct ip_conntrack *master,
  45.       struct sk_buff **pskb,
  46.       unsigned int hooknum,
  47.       struct ip_conntrack *ct,
  48.       struct ip_nat_info *info)
  49. {
  50. return master->nat.info.helper->expect(pskb, hooknum, ct, info);
  51. }
  52. static unsigned int
  53. ip_nat_fn(unsigned int hooknum,
  54.   struct sk_buff **pskb,
  55.   const struct net_device *in,
  56.   const struct net_device *out,
  57.   int (*okfn)(struct sk_buff *))
  58. {
  59. struct ip_conntrack *ct;
  60. enum ip_conntrack_info ctinfo;
  61. struct ip_nat_info *info;
  62. /* maniptype == SRC for postrouting. */
  63. enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
  64. /* We never see fragments: conntrack defrags on pre-routing
  65.    and local-out, and ip_nat_out protects post-routing. */
  66. IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
  67.        & htons(IP_MF|IP_OFFSET)));
  68. (*pskb)->nfcache |= NFC_UNKNOWN;
  69. /* If we had a hardware checksum before, it's now invalid */
  70. if ((*pskb)->ip_summed == CHECKSUM_HW)
  71. (*pskb)->ip_summed = CHECKSUM_NONE;
  72. ct = ip_conntrack_get(*pskb, &ctinfo);
  73. /* Can't track?  It's not due to stress, or conntrack would
  74.    have dropped it.  Hence it's the user's responsibilty to
  75.    packet filter it out, or implement conntrack/NAT for that
  76.    protocol. 8) --RR */
  77. if (!ct) {
  78. /* Exception: ICMP redirect to new connection (not in
  79.                    hash table yet).  We must not let this through, in
  80.                    case we're doing NAT to the same network. */
  81. struct iphdr *iph = (*pskb)->nh.iph;
  82. struct icmphdr *hdr = (struct icmphdr *)
  83. ((u_int32_t *)iph + iph->ihl);
  84. if (iph->protocol == IPPROTO_ICMP
  85.     && hdr->type == ICMP_REDIRECT)
  86. return NF_DROP;
  87. return NF_ACCEPT;
  88. }
  89. switch (ctinfo) {
  90. case IP_CT_RELATED:
  91. case IP_CT_RELATED+IP_CT_IS_REPLY:
  92. if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
  93. return icmp_reply_translation(*pskb, ct, hooknum,
  94.       CTINFO2DIR(ctinfo));
  95. }
  96. /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
  97. case IP_CT_NEW:
  98. #ifdef CONFIG_IP_NF_NAT_LOCAL
  99. /* LOCAL_IN hook doesn't have a chain and thus doesn't care
  100.  * about new packets -HW */
  101. if (hooknum == NF_IP_LOCAL_IN)
  102. return NF_ACCEPT;
  103. #endif
  104. info = &ct->nat.info;
  105. WRITE_LOCK(&ip_nat_lock);
  106. /* Seen it before?  This can happen for loopback, retrans,
  107.    or local packets.. */
  108. if (!(info->initialized & (1 << maniptype))) {
  109. int in_hashes = info->initialized;
  110. unsigned int ret;
  111. if (ct->master
  112.     && master_ct(ct)->nat.info.helper
  113.     && master_ct(ct)->nat.info.helper->expect) {
  114. ret = call_expect(master_ct(ct), pskb, 
  115.   hooknum, ct, info);
  116. } else {
  117. ret = ip_nat_rule_find(pskb, hooknum, in, out,
  118.        ct, info);
  119. }
  120. if (ret != NF_ACCEPT) {
  121. WRITE_UNLOCK(&ip_nat_lock);
  122. return ret;
  123. }
  124. if (in_hashes) {
  125. IP_NF_ASSERT(info->bysource.conntrack);
  126. replace_in_hashes(ct, info);
  127. } else {
  128. place_in_hashes(ct, info);
  129. }
  130. } else
  131. DEBUGP("Already setup manip %s for ct %pn",
  132.        maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
  133.        ct);
  134. WRITE_UNLOCK(&ip_nat_lock);
  135. break;
  136. default:
  137. /* ESTABLISHED */
  138. IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
  139.      || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
  140. info = &ct->nat.info;
  141. }
  142. IP_NF_ASSERT(info);
  143. return do_bindings(ct, ctinfo, info, hooknum, pskb);
  144. }
  145. static unsigned int
  146. ip_nat_out(unsigned int hooknum,
  147.    struct sk_buff **pskb,
  148.    const struct net_device *in,
  149.    const struct net_device *out,
  150.    int (*okfn)(struct sk_buff *))
  151. {
  152. /* root is playing with raw sockets. */
  153. if ((*pskb)->len < sizeof(struct iphdr)
  154.     || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
  155. return NF_ACCEPT;
  156. /* We can hit fragment here; forwarded packets get
  157.    defragmented by connection tracking coming in, then
  158.    fragmented (grr) by the forward code.
  159.    In future: If we have nfct != NULL, AND we have NAT
  160.    initialized, AND there is no helper, then we can do full
  161.    NAPT on the head, and IP-address-only NAT on the rest.
  162.    I'm starting to have nightmares about fragments.  */
  163. if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
  164. *pskb = ip_ct_gather_frags(*pskb);
  165. if (!*pskb)
  166. return NF_STOLEN;
  167. }
  168. return ip_nat_fn(hooknum, pskb, in, out, okfn);
  169. }
  170. static unsigned int
  171. ip_nat_local_fn(unsigned int hooknum,
  172. struct sk_buff **pskb,
  173. const struct net_device *in,
  174. const struct net_device *out,
  175. int (*okfn)(struct sk_buff *))
  176. {
  177. u_int32_t saddr, daddr;
  178. unsigned int ret;
  179. /* root is playing with raw sockets. */
  180. if ((*pskb)->len < sizeof(struct iphdr)
  181.     || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
  182. return NF_ACCEPT;
  183. saddr = (*pskb)->nh.iph->saddr;
  184. daddr = (*pskb)->nh.iph->daddr;
  185. ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
  186. if (ret != NF_DROP && ret != NF_STOLEN
  187.     && ((*pskb)->nh.iph->saddr != saddr
  188. || (*pskb)->nh.iph->daddr != daddr))
  189. return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
  190. return ret;
  191. }
  192. /* We must be after connection tracking and before packet filtering. */
  193. /* Before packet filtering, change destination */
  194. static struct nf_hook_ops ip_nat_in_ops
  195. = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
  196. /* After packet filtering, change source */
  197. static struct nf_hook_ops ip_nat_out_ops
  198. = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
  199. /* Before packet filtering, change destination */
  200. static struct nf_hook_ops ip_nat_local_out_ops
  201. = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
  202. #ifdef CONFIG_IP_NF_NAT_LOCAL
  203. static struct nf_hook_ops ip_nat_local_in_ops
  204. = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_NAT_SRC };
  205. #endif
  206. /* Protocol registration. */
  207. int ip_nat_protocol_register(struct ip_nat_protocol *proto)
  208. {
  209. int ret = 0;
  210. struct list_head *i;
  211. WRITE_LOCK(&ip_nat_lock);
  212. for (i = protos.next; i != &protos; i = i->next) {
  213. if (((struct ip_nat_protocol *)i)->protonum
  214.     == proto->protonum) {
  215. ret = -EBUSY;
  216. goto out;
  217. }
  218. }
  219. list_prepend(&protos, proto);
  220. MOD_INC_USE_COUNT;
  221.  out:
  222. WRITE_UNLOCK(&ip_nat_lock);
  223. return ret;
  224. }
  225. /* Noone stores the protocol anywhere; simply delete it. */
  226. void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
  227. {
  228. WRITE_LOCK(&ip_nat_lock);
  229. LIST_DELETE(&protos, proto);
  230. WRITE_UNLOCK(&ip_nat_lock);
  231. /* Someone could be still looking at the proto in a bh. */
  232. br_write_lock_bh(BR_NETPROTO_LOCK);
  233. br_write_unlock_bh(BR_NETPROTO_LOCK);
  234. MOD_DEC_USE_COUNT;
  235. }
  236. static int init_or_cleanup(int init)
  237. {
  238. int ret = 0;
  239. if (!init) goto cleanup;
  240. ret = ip_nat_rule_init();
  241. if (ret < 0) {
  242. printk("ip_nat_init: can't setup rules.n");
  243. goto cleanup_nothing;
  244. }
  245. ret = ip_nat_init();
  246. if (ret < 0) {
  247. printk("ip_nat_init: can't setup rules.n");
  248. goto cleanup_rule_init;
  249. }
  250. ret = nf_register_hook(&ip_nat_in_ops);
  251. if (ret < 0) {
  252. printk("ip_nat_init: can't register in hook.n");
  253. goto cleanup_nat;
  254. }
  255. ret = nf_register_hook(&ip_nat_out_ops);
  256. if (ret < 0) {
  257. printk("ip_nat_init: can't register out hook.n");
  258. goto cleanup_inops;
  259. }
  260. ret = nf_register_hook(&ip_nat_local_out_ops);
  261. if (ret < 0) {
  262. printk("ip_nat_init: can't register local out hook.n");
  263. goto cleanup_outops;
  264. }
  265. #ifdef CONFIG_IP_NF_NAT_LOCAL
  266. ret = nf_register_hook(&ip_nat_local_in_ops);
  267. if (ret < 0) {
  268. printk("ip_nat_init: can't register local in hook.n");
  269. goto cleanup_localoutops;
  270. }
  271. #endif
  272. if (ip_conntrack_module)
  273. __MOD_INC_USE_COUNT(ip_conntrack_module);
  274. return ret;
  275.  cleanup:
  276. if (ip_conntrack_module)
  277. __MOD_DEC_USE_COUNT(ip_conntrack_module);
  278. #ifdef CONFIG_IP_NF_NAT_LOCAL
  279. nf_unregister_hook(&ip_nat_local_in_ops);
  280.  cleanup_localoutops:
  281. #endif
  282. nf_unregister_hook(&ip_nat_local_out_ops);
  283.  cleanup_outops:
  284. nf_unregister_hook(&ip_nat_out_ops);
  285.  cleanup_inops:
  286. nf_unregister_hook(&ip_nat_in_ops);
  287.  cleanup_nat:
  288. ip_nat_cleanup();
  289.  cleanup_rule_init:
  290. ip_nat_rule_cleanup();
  291.  cleanup_nothing:
  292. MUST_BE_READ_WRITE_UNLOCKED(&ip_nat_lock);
  293. return ret;
  294. }
  295. static int __init init(void)
  296. {
  297. return init_or_cleanup(1);
  298. }
  299. static void __exit fini(void)
  300. {
  301. init_or_cleanup(0);
  302. }
  303. module_init(init);
  304. module_exit(fini);
  305. EXPORT_SYMBOL(ip_nat_setup_info);
  306. EXPORT_SYMBOL(ip_nat_protocol_register);
  307. EXPORT_SYMBOL(ip_nat_protocol_unregister);
  308. EXPORT_SYMBOL(ip_nat_helper_register);
  309. EXPORT_SYMBOL(ip_nat_helper_unregister);
  310. EXPORT_SYMBOL(ip_nat_cheat_check);
  311. EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
  312. EXPORT_SYMBOL(ip_nat_used_tuple);
  313. MODULE_LICENSE("GPL");