网关伪造ping 回应

环境:内网众多机器会发出ping,希望在网关上进行修改,使得所有ping 包在网关被截获,并返回ping reply。

最简单的解决方法就是iptables 转发的网关内部地址,由其负责回应ping。但这样就会使得ping 值非常小,作假也看着不像了。当时想写个程序控制回应ping 包,但这样回应就会有两个,一个网卡自身回应的ping 包,和程序回应的ping 包,为了拦截网卡本省发出的ping 包,可以采用内核模块编程,hook 住ICMP 包,这样有点超过我的范围了,调了一天多,放弃了。最后使用了一个折中的办法,iptables 将内网ping 包转发到外网ip 地址,运行ping 回应程序,最后iptables 拦截所有外网地址的ICMP 包,这样网关程序既可以收到ping 包回应,而外网卡的ping 被REJECT ,而内网卡的ping 不被REJECT。有个小小的问题就是client 收到ping 的回应都带有(DUP!),可能是因为报文的内容的原因,有知道原因的请告诉我哦~~~

 

下面三张图帮助了解iptables 机制:

DNAT 修改目的地址在进行路由之前进行

SNAT 修改源地址在进行路由之后进行

INPUT 控制所有进入网关处理的包(比如在DNAT 将–to-destination 改为网关地址)

OUTPUT 控制所有从网关发出的包

netfilter-t

下面是转发流程:

netfilter_forward

下面是网关处理后转发流程:

netfilter_io-t

inet_addr

函数作用:将“xxx.xxx.xxx.xxx”字符串格式地址转换为结构格式,返回地址

函数申明:in_addr_t inet_addr(const char *cp);

头文件:<arpa/inet.h>

inet_ntoa

函数作用:将地址转换为“xxx.xxx.xxx.xxx”字符串格式,返回地址

函数申明:char *inet_ntoa (struct in_addr);

头文件:<arpa/inet.h>

recvfrom

函数作用:经socket接收数据

函数申明:ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen); 六个参数分别是一个已连接套接口的描述字、接收数据缓冲区、缓冲区长度、调用操作方式、装有源地址的缓冲区和缓冲区长度值。

头文件:<arpa/inet.h>

 

   1: #include <;unistd.h>

   2: #include <;fcntl.h>

   3: #include <;stdlib.h>

   4: #include <;stdio.h>

   5: #include <;string.h>

   6: #include <;errno.h>

   7: #include <;sys/ioctl.h>

   8: #include <;sys/socket.h>

   9: #include <;linux/if.h>

  10: #include <;linux/if_tun.h>

  11: #include <;sys/types.h>

  12: #include <;netinet/in.h>

  13: #include <;netinet/ip.h>

  14: #include <;netinet/ip_icmp.h>

  15: #include <;arpa/inet.h>

  16: #include <;syswait.h>

  17:  

  18: int id;

  19: 

  20: int get_icmp(int sock,

  21:              unsigned char * buff,

  22:              int buff_len,

  23:              struct sockaddr_in * addr,

  24:              socklen_t * len){

  25:   struct ip * ip;

  26:   static u_char outpack[4096];

  27:   struct icmp * icmp=(struct icmp *)outpack;

  28:   int ret,iphl;

  29:  

  30:   printf("waiting for your ping ...\n");

  31:   ret = recvfrom(sock,buff,buff_len,0,(struct sockaddr *)addr,len);

  32:   if (ret){

  33:     ip = (struct ip *) buff;

  34:     iphl = ip->ip_hl << 2;

  35:     printf(">>>>>ip length:  %d\n",iphl);

  36:     printf(">>>>>ip address: %s\n",inet_ntoa(addr->sin_addr));

  37:     icmp = (struct icmp *) (buff + iphl);

  38:     id=icmp->icmp_id;

  39:     printf(">>>>>id= %d\n",id);

  40:     memmove(buff,buff+(iphl+8),ret-(iphl+8));

  41:     return(ret-(iphl+8));

  42:   }

  43: }

  44:  

  45: int send_icmp(int sock,

  46:               unsigned char * buff,

  47:               int buff_len,

  48:               struct sockaddr_in * addr,

  49:               socklen_t len){

  50:   int ret,cc;

  51:   static u_char outpack[4096];

  52:   struct icmp * icmp = (struct icmp *) outpack;

  53: 

  54:   icmp->icmp_type = ICMP_ECHOREPLY;

  55:   icmp->;icmp_code = 0;

  56:   icmp->;icmp_cksum = 0;

  57:   icmp->;icmp_seq = 0;

  58:   icmp->;icmp_id = id;

  59:   cc = 8 + buff_len;

  60:   memcpy(&outpack[8],buff,buff_len);

  61:   printf("echo your ping now!\n");

  62:   printf(">>>>>ip address: %s\n",inet_ntoa(addr->sin_addr));

  63:   if ((ret = sendto(sock, outpack, cc, 0,(struct sockaddr *) addr, len)) <; 0){

  64:     perror("icmp sendto");

  65:     exit(1);

  66:   }

  67:   return(ret);

  68: }

  69:  

  70: unsigned short get_delay(char* ip_p){

  71:   unsigned short delay=10;

  72:   

  73:   delay=20;

  74:   return delay;

  75: }

  76:  

  77: void wait_time(struct sockaddr_in *addr){

  78:   char ip_str[16];

  79:   unsigned short delay;

  80:   char * ip_p;

  81:   

  82:   ip_p=ip_str;

  83:   sprintf(ip_p,"%s",inet_ntoa(addr->;sin_addr));

  84:   delay=get_delay(ip_p);

  85:   usleep(delay*1000);

  86: }

  87:  

  88: int main(void){

  89:   unsigned char buff[4096];

  90:   fd_set rset;

  91:   struct sockaddr_in addr;

  92:   struct sockaddr_in addr_recv;

  93:   int sock;

  94:   int ret;

  95:   socklen_t len = sizeof(struct sockaddr_in);

  96:   socklen_t len_recv = sizeof(struct sockaddr_in);

  97:   int tunfd;

  98: 

  99:   if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0){

 100:     perror("error: socket\n");

 101:     exit(1);

 102:   }

 103:   memset(&;addr,0,sizeof(struct sockaddr_in));

 104:   addr.sin_family = AF_INET;

 105:   addr.sin_port = 0;

 106:   while(1){

 107:     FD_ZERO(&;rset);

 108:     FD_SET(sock,&;rset);

 109:     if (FD_ISSET(sock,&;rset)){

 110:       printf(">>>ready to test\n");

 111:       if ((ret = get_icmp(sock,buff,sizeof(buff),&addr_recv,&len_recv)) > 0){

 112:         printf(">>>ping received\n");

 113:       }

 114:     }

 115:     memcpy((char *)&;addr.sin_addr,(char *)&addr_recv.sin_addr,sizeof(addr.sin_addr));

 116:     wait_time(&;addr);

 117:     printf(">>>ready to echo\n");

 118:     send_icmp(sock,buff,ret,&addr,len);

 119:     printf(">>>echo sent!\n");

 120:   }

 121: }


参考文献:

  1. 用C 实现ping 程序功能
  2. recvfrom 函数
  3. FS_SET()
  4. struct sockeaddr_in
  5. iptables 的升级宝典
  6. ping.c 内核源码

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据