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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* Masquerading compatibility layer.
  2.    Note that there are no restrictions on other programs binding to
  3.    ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE).  Just DONT
  4.    DO IT.
  5.  */
  6. #include <linux/skbuff.h>
  7. #include <linux/in.h>
  8. #include <linux/ip.h>
  9. #include <linux/icmp.h>
  10. #include <linux/udp.h>
  11. #include <linux/netfilter_ipv4.h>
  12. #include <linux/netdevice.h>
  13. #include <linux/inetdevice.h>
  14. #include <linux/proc_fs.h>
  15. #include <linux/version.h>
  16. #include <linux/module.h>
  17. #include <net/route.h>
  18. #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
  19. #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
  20. #include <linux/netfilter_ipv4/ip_conntrack.h>
  21. #include <linux/netfilter_ipv4/ip_conntrack_core.h>
  22. #include <linux/netfilter_ipv4/ip_nat.h>
  23. #include <linux/netfilter_ipv4/ip_nat_core.h>
  24. #include <linux/netfilter_ipv4/listhelp.h>
  25. #if 0
  26. #define DEBUGP printk
  27. #else
  28. #define DEBUGP(format, args...)
  29. #endif
  30. unsigned int
  31. do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
  32. {
  33. struct iphdr *iph = (*pskb)->nh.iph;
  34. struct ip_nat_info *info;
  35. enum ip_conntrack_info ctinfo;
  36. struct ip_conntrack *ct;
  37. unsigned int ret;
  38. /* Sorry, only ICMP, TCP and UDP. */
  39. if (iph->protocol != IPPROTO_ICMP
  40.     && iph->protocol != IPPROTO_TCP
  41.     && iph->protocol != IPPROTO_UDP)
  42. return NF_DROP;
  43. /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
  44.            but connection tracking doesn't expect that */
  45. ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
  46. if (ret != NF_ACCEPT) {
  47. DEBUGP("ip_conntrack_in returned %u.n", ret);
  48. return ret;
  49. }
  50. ct = ip_conntrack_get(*pskb, &ctinfo);
  51. if (!ct) {
  52. DEBUGP("ip_conntrack_in set to invalid conntrack.n");
  53. return NF_DROP;
  54. }
  55. info = &ct->nat.info;
  56. WRITE_LOCK(&ip_nat_lock);
  57. /* Setup the masquerade, if not already */
  58. if (!info->initialized) {
  59. u_int32_t newsrc;
  60. struct rtable *rt;
  61. struct ip_nat_multi_range range;
  62. /* Pass 0 instead of saddr, since it's going to be changed
  63.    anyway. */
  64. if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
  65. DEBUGP("ipnat_rule_masquerade: Can't reroute.n");
  66. return NF_DROP;
  67. }
  68. newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
  69.   RT_SCOPE_UNIVERSE);
  70. ip_rt_put(rt);
  71. range = ((struct ip_nat_multi_range)
  72.  { 1,
  73.    {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
  74.      newsrc, newsrc,
  75.      { htons(61000) }, { htons(65095) } } } });
  76. ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
  77. if (ret != NF_ACCEPT) {
  78. WRITE_UNLOCK(&ip_nat_lock);
  79. return ret;
  80. }
  81. place_in_hashes(ct, info);
  82. info->initialized = 1;
  83. } else
  84. DEBUGP("Masquerading already done on this conn.n");
  85. WRITE_UNLOCK(&ip_nat_lock);
  86. return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
  87. }
  88. void
  89. check_for_masq_error(struct sk_buff *skb)
  90. {
  91. enum ip_conntrack_info ctinfo;
  92. struct ip_conntrack *ct;
  93. ct = ip_conntrack_get(skb, &ctinfo);
  94. /* Wouldn't be here if not tracked already => masq'ed ICMP
  95.            ping or error related to masq'd connection */
  96. IP_NF_ASSERT(ct);
  97. if (ctinfo == IP_CT_RELATED) {
  98. icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING,
  99.        CTINFO2DIR(ctinfo));
  100. icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING,
  101.        CTINFO2DIR(ctinfo));
  102. }
  103. }
  104. unsigned int
  105. check_for_demasq(struct sk_buff **pskb)
  106. {
  107. struct ip_conntrack_tuple tuple;
  108. struct iphdr *iph = (*pskb)->nh.iph;
  109. struct ip_conntrack_protocol *protocol;
  110. struct ip_conntrack_tuple_hash *h;
  111. enum ip_conntrack_info ctinfo;
  112. struct ip_conntrack *ct;
  113. int ret;
  114. protocol = ip_ct_find_proto(iph->protocol);
  115. /* We don't feed packets to conntrack system unless we know
  116.            they're part of an connection already established by an
  117.            explicit masq command. */
  118. switch (iph->protocol) {
  119. case IPPROTO_ICMP:
  120. /* ICMP errors. */
  121. ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
  122. if (ct) {
  123. /* We only do SNAT in the compatibility layer.
  124.    So we can manipulate ICMP errors from
  125.    server here (== DNAT).  Do SNAT icmp manips
  126.    in POST_ROUTING handling. */
  127. if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
  128. icmp_reply_translation(*pskb, ct,
  129.        NF_IP_PRE_ROUTING,
  130.        CTINFO2DIR(ctinfo));
  131. icmp_reply_translation(*pskb, ct,
  132.        NF_IP_POST_ROUTING,
  133.        CTINFO2DIR(ctinfo));
  134. }
  135. return NF_ACCEPT;
  136. }
  137. /* Fall thru... */
  138. case IPPROTO_TCP:
  139. case IPPROTO_UDP:
  140. IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
  141. if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
  142. if (net_ratelimit())
  143. printk("ip_fw_compat_masq: Can't get tuplen");
  144. return NF_ACCEPT;
  145. }
  146. break;
  147. default:
  148. /* Not ours... */
  149. return NF_ACCEPT;
  150. }
  151. h = ip_conntrack_find_get(&tuple, NULL);
  152. /* MUST be found, and MUST be reply. */
  153. if (h && DIRECTION(h) == 1) {
  154. ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
  155.       NULL, NULL, NULL);
  156. /* Put back the reference gained from find_get */
  157. nf_conntrack_put(&h->ctrack->infos[0]);
  158. if (ret == NF_ACCEPT) {
  159. struct ip_conntrack *ct;
  160. ct = ip_conntrack_get(*pskb, &ctinfo);
  161. if (ct) {
  162. struct ip_nat_info *info = &ct->nat.info;
  163. do_bindings(ct, ctinfo, info,
  164.     NF_IP_PRE_ROUTING,
  165.     pskb);
  166. } else
  167. if (net_ratelimit()) 
  168. printk("ip_fw_compat_masq: conntrack"
  169.        " didn't liken");
  170. }
  171. } else {
  172. if (h)
  173. /* Put back the reference gained from find_get */
  174. nf_conntrack_put(&h->ctrack->infos[0]);
  175. ret = NF_ACCEPT;
  176. }
  177. return ret;
  178. }
  179. int ip_fw_masq_timeouts(void *user, int len)
  180. {
  181. printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECSn");
  182. return 0;
  183. }
  184. static const char *masq_proto_name(u_int16_t protonum)
  185. {
  186. switch (protonum) {
  187. case IPPROTO_TCP: return "TCP";
  188. case IPPROTO_UDP: return "UDP";
  189. case IPPROTO_ICMP: return "ICMP";
  190. default: return "MORE-CAFFIENE-FOR-RUSTY";
  191. }
  192. }
  193. static unsigned int
  194. print_masq(char *buffer, const struct ip_conntrack *conntrack)
  195. {
  196. char temp[129];
  197. /* This is for backwards compatibility, but ick!.
  198.    We should never export jiffies to userspace.
  199. */
  200. sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
  201. masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
  202. ntohl(conntrack->tuplehash[0].tuple.src.ip),
  203. ntohs(conntrack->tuplehash[0].tuple.src.u.all),
  204. ntohl(conntrack->tuplehash[0].tuple.dst.ip),
  205. ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
  206. ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
  207. /* Sorry, no init_seq, delta or previous_delta (yet). */
  208. 0, 0, 0,
  209. conntrack->timeout.expires - jiffies);
  210. return sprintf(buffer, "%-127sn", temp);
  211. }
  212. /* Returns true when finished. */
  213. static int
  214. masq_iterate(const struct ip_conntrack_tuple_hash *hash,
  215.      char *buffer, off_t offset, off_t *upto,
  216.      unsigned int *len, unsigned int maxlen)
  217. {
  218. unsigned int newlen;
  219. IP_NF_ASSERT(hash->ctrack);
  220. /* Only count originals */
  221. if (DIRECTION(hash))
  222. return 0;
  223. if ((*upto)++ < offset)
  224. return 0;
  225. newlen = print_masq(buffer + *len, hash->ctrack);
  226. if (*len + newlen > maxlen)
  227. return 1;
  228. else *len += newlen;
  229. return 0;
  230. }
  231. /* Everything in the hash is masqueraded. */
  232. static int
  233. masq_procinfo(char *buffer, char **start, off_t offset, int length)
  234. {
  235. unsigned int i;
  236. int len = 0;
  237. off_t upto = 1;
  238. /* Header: first record */
  239. if (offset == 0) {
  240. char temp[128];
  241. sprintf(temp,
  242. "Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires (free=0,0,0)");
  243. len = sprintf(buffer, "%-127sn", temp);
  244. offset = 1;
  245. }
  246. READ_LOCK(&ip_conntrack_lock);
  247. /* Traverse hash; print originals then reply. */
  248. for (i = 0; i < ip_conntrack_htable_size; i++) {
  249. if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
  250.       struct ip_conntrack_tuple_hash *,
  251.       buffer, offset, &upto, &len, length))
  252. break;
  253. }
  254. READ_UNLOCK(&ip_conntrack_lock);
  255. /* `start' hack - see fs/proc/generic.c line ~165 */
  256. *start = (char *)((unsigned int)upto - offset);
  257. return len;
  258. }
  259. int __init masq_init(void)
  260. {
  261. int ret;
  262. struct proc_dir_entry *proc;
  263. ret = ip_conntrack_init();
  264. if (ret == 0) {
  265. ret = ip_nat_init();
  266. if (ret == 0) {
  267. proc = proc_net_create("ip_masquerade",
  268.        0, masq_procinfo);
  269. if (proc)
  270. proc->owner = THIS_MODULE;
  271. else {
  272. ip_nat_cleanup();
  273. ip_conntrack_cleanup();
  274. ret = -ENOMEM;
  275. }
  276. } else
  277. ip_conntrack_cleanup();
  278. }
  279. return ret;
  280. }
  281. void masq_cleanup(void)
  282. {
  283. ip_nat_cleanup();
  284. ip_conntrack_cleanup();
  285. proc_net_remove("ip_masquerade");
  286. }