ip_nat_standalone.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

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