Chinaunix首页 | 论坛 | 博客
  • 博客访问: 80858
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-06 15:31
文章分类

全部博文(29)

文章存档

2015年(18)

2014年(11)

我的朋友

分类: LINUX

2015-01-06 16:38:48

偶尔在网上看到了这篇文章,
并结合中的例子,
然后修改了一下tcp计算checksum部分,在linux2.6.24上用netfilter_queue在用户态实现NAT

程序功能: 将输出端目的地为 220.181.37.55 的包,都改为目的地为 202.118.236.130,输入段反之,达到DNAT的一小半功能,完整的NAT要做状态记录的.

直接上代码:

nf_queue_test.c

点击(此处)折叠或打开

  1. /*
  2.  * =====================================================================================
  3.  *
  4.  * Filename: nf_queue_test.c
  5.  *
  6.  * Description: 用netfilter_queue 在用户态修改网络数据包的例子程序
  7.  *
  8.  * Version: 1.0
  9.  * Created: 04/02/2010 09:49:48 AM
  10.  * Revision: none
  11.  * Compiler: gcc
  12.  *
  13.  * Author: LeiuX (xulei), xulei@pact518.hit.edu.cn
  14.  * Company: HIT
  15.  *
  16.  * =====================================================================================
  17.  */

  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <netdb.h>
  22. #include <string.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>

  25. #include <asm/byteorder.h>
  26. #include <linux/netfilter.h>
  27. #include <libnetfilter_queue/libnetfilter_queue.h>
  28. #include <linux/ip.h>
  29. #include <linux/tcp.h>

  30. #ifdef __LITTLE_ENDIAN
  31. #define IPQUAD(addr) \
  32. ((unsigned char *)&addr)[0], \
  33. ((unsigned char *)&addr)[1], \
  34. ((unsigned char *)&addr)[2], \
  35. ((unsigned char *)&addr)[3]
  36. #else
  37. #define IPQUAD(addr) \
  38. ((unsigned char *)&addr)[3], \
  39. ((unsigned char *)&addr)[2], \
  40. ((unsigned char *)&addr)[1], \
  41. ((unsigned char *)&addr)[0]
  42. #endif

  43. struct tcp_pseudo /*the tcp pseudo header*/
  44. {
  45.   __u32 src_addr;
  46.   __u32 dst_addr;
  47.   __u8 zero;
  48.   __u8 proto;
  49.   __u16 length;
  50. } pseudohead;


  51. long checksum(unsigned short *addr, unsigned int count) {
  52.   /* Compute Internet Checksum for "count" bytes
  53.    * beginning at location "addr".
  54.    */
  55.   register long sum = 0;

  56.   while( count > 1 ) {
  57.     /* This is the inner loop */
  58.     sum += * addr++;
  59.     count -= 2;
  60.   }
  61.   /* Add left-over byte, if any */
  62.   if( count > 0 )
  63.     sum += * (unsigned char *) addr;

  64.   /* Fold 32-bit sum to 16 bits */
  65.   while (sum>>16)
  66.     sum = (sum & 0xffff) + (sum >> 16);

  67.   return ~sum;
  68. }


  69. /*************************tcp checksum**********************/
  70. long get_tcp_checksum(struct iphdr * myip, struct tcphdr * mytcp) {

  71.   __u16 total_len = ntohs(myip->tot_len);

  72.   int tcpopt_len = mytcp->doff*4 - 20;
  73.   int tcpdatalen = total_len - (mytcp->doff*4) - (myip->ihl*4);

  74.   pseudohead.src_addr=myip->saddr;
  75.   pseudohead.dst_addr=myip->daddr;
  76.   pseudohead.zero=0;
  77.   pseudohead.proto=IPPROTO_TCP;
  78.   pseudohead.length=htons(sizeof(struct tcphdr) + tcpopt_len + tcpdatalen);

  79.   int totaltcp_len = sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + tcpopt_len +tcpdatalen;
  80.   //unsigned short * tcp = new unsigned short[totaltcp_len];

  81.   unsigned short * tcp = malloc(totaltcp_len);


  82.   memcpy((unsigned char *)tcp,&pseudohead,sizeof(struct tcp_pseudo));
  83.   memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo),(unsigned char*)mytcp,sizeof(struct tcphdr));
  84.   memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo)+sizeof(struct tcphdr),(unsigned char *)myip+(myip->ihl*4)+(sizeof(struct tcphdr)), tcpopt_len);
  85.   memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo)+sizeof(structtcphdr)+tcpopt_len, (unsigned char *)mytcp+(mytcp->doff*4), tcpdatalen);

  86.   /* printf("pseud length: %d\n",pseudohead.length);
  87.           printf("tcp hdr length: %d\n",mytcp->doff*4);
  88.           printf("tcp hdr struct length: %d\n",sizeof(struct tcphdr));
  89.           printf("tcp opt length: %d\n",tcpopt_len);
  90.           printf("tcp total+psuedo length: %d\n",totaltcp_len);

  91.           fflush(stdout);

  92.           printf("tcp data len: %d, data start %u\n", tcpdatalen,mytcp + (mytcp->doff*4));
  93.    */


  94.   return checksum(tcp,totaltcp_len);

  95. }

  96. static u_int16_t tcp_checksum(struct iphdr* iphdrp){
  97.   struct tcphdr *tcphdrp =
  98.     (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
  99.   return get_tcp_checksum(iphdrp, tcphdrp);
  100. }

  101. static void set_tcp_checksum(struct iphdr* iphdrp){
  102.   struct tcphdr *tcphdrp =
  103.     (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
  104.   tcphdrp->check = 0;
  105.   tcphdrp->check = get_tcp_checksum(iphdrp, tcphdrp);
  106. }
  107. /****************************tcp checksum end****************************/


  108. /********************************Ip checksum*****************************/
  109. static u_int16_t ip_checksum(struct iphdr* iphdrp){
  110.   return checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
  111. }

  112. static void set_ip_checksum(struct iphdr* iphdrp){
  113.   iphdrp->check = 0;
  114.   iphdrp->check = checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
  115. }
  116. /****************************Ip checksum end******************************/

  117. static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
  118.     struct nfq_data *nfa, void *data){
  119.   (void)nfmsg;
  120.   (void)data;
  121.   u_int32_t id = 0;
  122.   struct nfqnl_msg_packet_hdr *ph;
  123.   unsigned char *pdata = NULL;
  124.   int pdata_len;

  125.   ph = nfq_get_msg_packet_hdr(nfa);
  126.   if (ph){
  127.     id = ntohl(ph->packet_id);
  128.   }

  129.   pdata_len = nfq_get_payload(nfa, (char**)&pdata);
  130.   if(pdata_len == -1){
  131.     pdata_len = 0;
  132.   }

  133.   struct iphdr *iphdrp = (struct iphdr *)pdata;

  134.   printf("len %d iphdr %d %u.%u.%u.%u ->",
  135.       pdata_len,
  136.       iphdrp->ihl<<2,
  137.       IPQUAD(iphdrp->saddr));
  138.   printf(" %u.%u.%u.%u %s",
  139.       IPQUAD(iphdrp->daddr),
  140.       getprotobynumber(iphdrp->protocol)->p_name);
  141.   printf(" ipsum %hu", ip_checksum(iphdrp));
  142.   if(iphdrp->protocol == IPPROTO_TCP){
  143.     printf(" tcpsum %hu", tcp_checksum(iphdrp));
  144.   }

  145. #define TO "220.181.37.55"
  146. #define DNAT_TO "202.118.236.130"

  147.   if(iphdrp->daddr == inet_addr(TO)){
  148.     printf(" !hacked!");
  149.     iphdrp->daddr = inet_addr(DNAT_TO);
  150.     set_ip_checksum(iphdrp);
  151.     if(iphdrp->protocol == IPPROTO_TCP){
  152.       set_tcp_checksum(iphdrp);
  153.       printf(" ipsum+ %hu tcpsum+ %hu",
  154.           ip_checksum(iphdrp), tcp_checksum(iphdrp));
  155.     }
  156.   }

  157.   if(iphdrp->saddr == inet_addr(DNAT_TO)){
  158.     iphdrp->saddr = inet_addr(TO);
  159.     printf(" !hacked!");
  160.     set_ip_checksum(iphdrp);
  161.     if(iphdrp->protocol == IPPROTO_TCP){
  162.       set_tcp_checksum(iphdrp);
  163.       printf(" ipsum+ %hu tcpsum+ %hu",
  164.           ip_checksum(iphdrp), tcp_checksum(iphdrp));
  165.     }
  166.   }

  167.   printf("\n");

  168.   return nfq_set_verdict_mark(qh, id, NF_REPEAT, 1,
  169.       (u_int32_t)pdata_len, pdata);
  170. }

  171. int main(int argc, char **argv)
  172. {
  173.   struct nfq_handle *h;
  174.   struct nfq_q_handle *qh;
  175.   struct nfnl_handle *nh;
  176.   int fd;
  177.   int rv;
  178.   char buf[4096];

  179.   h = nfq_open();
  180.   if (!h) {
  181.     exit(1);
  182.   }

  183.   nfq_unbind_pf(h, AF_INET);

  184.   /*2.6.24 的内核有BUG, nfq_unbind_pf 返回值不正确,
  185.     见:http://article.gmane.org/gmane.c ... ilter.general/33573*/

  186.   /*
  187.      if (nfq_unbind_pf(h, AF_INET) < 0){
  188.      exit(1);
  189.      }
  190.   */

  191.   if (nfq_bind_pf(h, AF_INET) < 0) {
  192.     exit(1);
  193.   }

  194.   int qid = 0;
  195.   if(argc == 2){
  196.     qid = atoi(argv[1]);
  197.   }
  198.   printf("binding this socket to queue %d\n", qid);
  199.   qh = nfq_create_queue(h, qid, &cb, NULL);
  200.   if (!qh) {
  201.     exit(1);
  202.   }

  203.   if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
  204.     exit(1);
  205.   }

  206.   nh = nfq_nfnlh(h);
  207.   fd = nfnl_fd(nh);

  208.   while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
  209.     nfq_handle_packet(h, buf, rv);
  210.   }

  211.   /* never reached */
  212.   nfq_destroy_queue(qh);

  213.   nfq_close(h);

  214.   exit(0);
  215. }

阅读(1167) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~