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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* iptables module for the IPv4 and TCP ECN bits, Version 1.2
  2.  *
  3.  * (C) 2002 by Harald Welte <laforge@gnumonks.org>
  4.  * 
  5.  * This software is distributed under GNU GPL v2, 1991
  6.  * 
  7.  * ipt_ECN.c,v 1.4 2002/08/05 19:36:51 laforge Exp
  8. */
  9. #include <linux/module.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/ip.h>
  12. #include <net/checksum.h>
  13. #include <linux/netfilter_ipv4/ip_tables.h>
  14. #include <linux/netfilter_ipv4/ipt_ECN.h>
  15. MODULE_LICENSE("GPL");
  16. /* set ECT codepoint from IP header.
  17.  *  return 0 in case there was no ECT codepoint
  18.  *  return 1 in case ECT codepoint has been overwritten
  19.  *  return < 0 in case there was error */
  20. static int inline
  21. set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
  22.    const struct ipt_ECN_info *einfo)
  23. {
  24. if ((iph->tos & IPT_ECN_IP_MASK)
  25.     != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
  26. u_int16_t diffs[2];
  27. /* raw socket (tcpdump) may have clone of incoming
  28.  * skb: don't disturb it --RR */
  29. if (skb_cloned(*pskb) && !(*pskb)->sk) {
  30. struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
  31. if (!nskb)
  32. return NF_DROP;
  33. kfree_skb(*pskb);
  34. *pskb = nskb;
  35. iph = (*pskb)->nh.iph;
  36. }
  37. diffs[0] = htons(iph->tos) ^ 0xFFFF;
  38. iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
  39. iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
  40. diffs[1] = htons(iph->tos);
  41. iph->check = csum_fold(csum_partial((char *)diffs,
  42.                                     sizeof(diffs),
  43.                                     iph->check^0xFFFF));
  44. (*pskb)->nfcache |= NFC_ALTERED;
  45. return 1;
  46. return 0;
  47. }
  48. static int inline
  49. set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
  50.     const struct ipt_ECN_info *einfo)
  51. {
  52. struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
  53. u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
  54. u_int16_t diffs[2];
  55. /* raw socket (tcpdump) may have clone of incoming
  56.  * skb: don't disturb it --RR */
  57. if (skb_cloned(*pskb) && !(*pskb)->sk) {
  58. struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
  59. if (!nskb)
  60. return NF_DROP;
  61. kfree_skb(*pskb);
  62. *pskb = nskb;
  63. iph = (*pskb)->nh.iph;
  64. }
  65. diffs[0] = *tcpflags;
  66. if (einfo->operation & IPT_ECN_OP_SET_ECE
  67.     && tcph->ece != einfo->proto.tcp.ece) {
  68. tcph->ece = einfo->proto.tcp.ece;
  69. }
  70. if (einfo->operation & IPT_ECN_OP_SET_CWR
  71.     && tcph->cwr != einfo->proto.tcp.cwr) {
  72. tcph->cwr = einfo->proto.tcp.cwr;
  73. }
  74. if (diffs[0] != *tcpflags) {
  75. diffs[0] = htons(diffs[0]) ^ 0xFFFF;
  76. diffs[1] = htons(*tcpflags);
  77. tcph->check = csum_fold(csum_partial((char *)diffs,
  78.                                     sizeof(diffs),
  79.                                     tcph->check^0xFFFF));
  80. (*pskb)->nfcache |= NFC_ALTERED;
  81. return 1;
  82. }
  83. return 0;
  84. }
  85. static unsigned int
  86. target(struct sk_buff **pskb,
  87.        unsigned int hooknum,
  88.        const struct net_device *in,
  89.        const struct net_device *out,
  90.        const void *targinfo,
  91.        void *userinfo)
  92. {
  93. struct iphdr *iph = (*pskb)->nh.iph;
  94. const struct ipt_ECN_info *einfo = targinfo;
  95. if (einfo->operation & IPT_ECN_OP_SET_IP)
  96. set_ect_ip(pskb, iph, einfo);
  97. if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
  98.     && iph->protocol == IPPROTO_TCP)
  99. set_ect_tcp(pskb, iph, einfo);
  100. return IPT_CONTINUE;
  101. }
  102. static int
  103. checkentry(const char *tablename,
  104.    const struct ipt_entry *e,
  105.            void *targinfo,
  106.            unsigned int targinfosize,
  107.            unsigned int hook_mask)
  108. {
  109. const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
  110. if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
  111. printk(KERN_WARNING "ECN: targinfosize %u != %Zun",
  112.        targinfosize,
  113.        IPT_ALIGN(sizeof(struct ipt_ECN_info)));
  114. return 0;
  115. }
  116. if (strcmp(tablename, "mangle") != 0) {
  117. printk(KERN_WARNING "ECN: can only be called from "mangle" table, not "%s"n", tablename);
  118. return 0;
  119. }
  120. if (einfo->operation & IPT_ECN_OP_MASK) {
  121. printk(KERN_WARNING "ECN: unsupported ECN operation %xn",
  122. einfo->operation);
  123. return 0;
  124. }
  125. if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
  126. printk(KERN_WARNING "ECN: new ECT codepoint %x out of maskn",
  127. einfo->ip_ect);
  128. return 0;
  129. }
  130. if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
  131.     && e->ip.proto != IPPROTO_TCP) {
  132. printk(KERN_WARNING "ECN: cannot use TCP operations on a "
  133.        "non-tcp rulen");
  134. return 0;
  135. }
  136. return 1;
  137. }
  138. static struct ipt_target ipt_ecn_reg
  139. = { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
  140. static int __init init(void)
  141. {
  142. if (ipt_register_target(&ipt_ecn_reg))
  143. return -EINVAL;
  144. return 0;
  145. }
  146. static void __exit fini(void)
  147. {
  148. ipt_unregister_target(&ipt_ecn_reg);
  149. }
  150. module_init(init);
  151. module_exit(fini);