socket发送arp的工具

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>

#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

#define IPV4_LENGTH 4
#define buffer_len 60   //ARP请求包大小为60B,,抓包时会抓到一些42B的包,这是抓包软件没有显示18B的Padding字段,Padding全0填充在包的末尾
/*ARP包结构*/
/*字段顺序不可更改,发包时是直接将buffer发出*/
struct arp_head{
    uint16_t hardware_type;   //硬件类型#1:Ethernet
	uint16_t protocol_type;   //协议类型#0x0800:IPv4
    uint8_t hardware_size;    //MAC地址长度#6
    uint8_t protocol_size;    //IP地址长度#4
    uint16_t opcode;          //ARP类型#1:request;2:reply
    uint8_t sender_mac[ETH_ALEN];    //源MAC地址
    uint8_t sender_ip[IPV4_LENGTH];  //源IP地址
    uint8_t target_mac[ETH_ALEN];    //目标MAC地址
    uint8_t target_ip[IPV4_LENGTH];  //目标IP地址
};

static void show_manual(int argc,char const *argv[]);
static int ip4str_parse(const char *point, unsigned char result[4]);
static int macstr_parse(const char *point, unsigned char result[6]);
static int parse_arg(int argc,char const *argv[],char *dev_name,uint8_t *dest_mac_addr,uint8_t *sender_ip,uint8_t *target_ip);
/******************************************************************************************/
int main(int argc, char const *argv[])
{
    int i;
    char dev_name[0x10];
    uint8_t dest_mac_addr[6];
    uint8_t sender_ip[4];    //ARP请求的源IP
    uint8_t target_ip[4];     //ARP请求的目标IP

    if(parse_arg(argc,argv,dev_name,dest_mac_addr,sender_ip,target_ip)){
        show_manual(argc,argv);
        exit(1);
    }
    //创建buffer
    uint8_t buffer[buffer_len];
    memset(buffer, 0, buffer_len);
    //创建以太网头部指针,指向buffer
    struct ethhdr *eth_req = (struct ethhdr*)buffer;
    //创建ARP包指针,指向buffer的后46字节,因为以太网头包含:2*6B(MAC地址)+2B(协议地址)=14B
    struct arp_head *arp_req = (struct arp_head*)(buffer+14);
    //创建sockaddr_ll结构地址
    struct sockaddr_ll sock_addr;
    //创建socket
    /***int socket(int __domain, int __type, int __protocol)
     *** __domain
     * PF_PACKET指示为二层协议簇
     * 使用AF_PACKET也可,socket.h中有#define AF_PACKET PF_PACKET
     *** __type
     * 使用PF_PACKET的后,__type只能选择SOCK_RAW或者SOCK_DGRAM
     * 其中SOCK_RAW可以自己构造帧头,SOCK_DGRAM不行
     * 帧头使用sockaddr_ll结构体构建,这个结构体在if_packet.h中
     * 有一些资料这里选择的是SOCK_PACKET,这个类型目前已经被建议弃用
     *** __protocol
     * ETH_P_ARP意味着我们仅仅接受ARP类型
     * 如果是ETH_P_ALL就意味着我们接受所有类型帧
     * 更多选项参看if_ether.h中定义
     */
    int sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if(sock_fd == -1){
        perror("socket()");
        exit(-1);
    }
    /**获取网卡等需要的信息
     * ifreq结构体可以用于设置或者获取网卡等相关信息,定义在if.h中
     * 配合ioctl()一起使用
     * ioctl()的具体参数用法和系统实现相关,不是通用的,具体参见ioctls.h
     * 以下获取的信息都会保存在ifreq不同字段之中
     */
    struct ifreq ifr;

    /*根据网卡设备名获取Index*/
    strcpy(ifr.ifr_name, dev_name);
    if(ioctl(sock_fd, SIOCGIFINDEX, &ifr) == -1){
        perror("SIOCGIFINDEX");
        exit(-1);
    }
    int ifindex = ifr.ifr_ifindex;
    printf("网卡索引为:%d\n",ifindex);

    /*获取网卡设备MAC地址*/
    if(ioctl(sock_fd, SIOCGIFHWADDR, &ifr) == -1){
        perror("SIOCGIFHWADDR");
        exit(-1);
    }

    /*将MAC地址写入所需结构*/
    for(i=0;i<6;i++){
        //以太网帧的目标MAC,即广播MAC,全1
        eth_req->h_dest[i] = dest_mac_addr[i];
        //ARP请求包目标MAC,全0
        arp_req->target_mac[i] = (uint8_t)0x00;
        //以太网帧源MAC,即本机MAC
        //ifr_hwaddr是sockaddr结构体格式
        eth_req->h_source[i] = (uint8_t)ifr.ifr_hwaddr.sa_data[i];
        //ARP请求包源MAC,即本机MAC
        arp_req->sender_mac[i] = (uint8_t)ifr.ifr_hwaddr.sa_data[i];
        //sockaddr中的MAC,也是本地MAC
        sock_addr.sll_addr[i] = (uint8_t)ifr.ifr_hwaddr.sa_data[i];
    }

    /*打印MAC地址*/
    printf("网卡MAC地址: %02X:%02X:%02X:%02X:%02X:%02X\n",
            eth_req->h_source[0],
            eth_req->h_source[1],
            eth_req->h_source[2],
            eth_req->h_source[3],
            eth_req->h_source[4],
            eth_req->h_source[5]);

    /*完善sockaddr_ll结构体*/
    sock_addr.sll_family = PF_PACKET;
    sock_addr.sll_protocol = htons(ETH_P_ARP);
    sock_addr.sll_ifindex = ifindex;
    sock_addr.sll_hatype = htons(ARPHRD_ETHER);
    sock_addr.sll_halen = ETH_ALEN;

    /*完善以太网帧头*/
    eth_req->h_proto = htons(ETH_P_ARP);

    /*完善ARP包头*/
    arp_req->hardware_type = htons(0x01);
    arp_req->protocol_type = htons(ETH_P_IP);
    arp_req->hardware_size = ETH_ALEN;
    arp_req->protocol_size = IPV4_LENGTH;
    arp_req->opcode = htons(ARPOP_REQUEST);
    memcpy(arp_req->sender_ip,sender_ip,IPV4_LENGTH);
    memcpy(arp_req->target_ip,target_ip,IPV4_LENGTH);

    /*发送ARP请求*/
    if(sendto(sock_fd, buffer, 60, 0, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) == -1){
        perror("sendto()");
        exit(-1);
    }
    printf("发送ARP请求包:");
    for(i=0;i<60;i++){
        if(i%16==0)
            printf("\n");
        printf("%02X ",buffer[i]);
    }
    printf("\n");
    close(sock_fd);
    return 0;
}
/***********************************************************************************/
static void show_manual(int argc,char const *argv[])
{
    printf("Usage:\n",argv[0]);
    printf("\t%s <interface> <sender_ip> <target_ip>\n",argv[0]);
    printf("\tdefault dest_mac is ff-ff-ff-ff-ff-ff\n");
    printf("\t%s <interface> <sender_ip> <target_ip> <dest_mac>\n",argv[0]);
    printf("example:\n");
    printf("\t%s eth0 192.168.1.200 192.168.1.100\n",argv[0]);
    printf("\t%s eth0 192.168.1.200 192.168.1.100 00-01-02-03-04-05\n",argv[0]);
}
static int macstr_parse(const char *point, unsigned char result[6])
{
    int i;
    for (i = 0; i < 6; i++) {
        result[i] = 0xfe;
    }
    char buf[18] = {0}, p = 0, q = 0;
    strcpy(buf, point);
    buf[strlen(point)] = '-';
    for(i = 0;i < 6; i++) {
        q = strchr(buf+p, '-') - buf;
        buf[q] = '\0';
        result[i] = strtol(buf+p, NULL, 16);
        p = q + 1;
    }
    return 1;
}
static int ip4str_parse(const char *point, unsigned char result[4])
{
    int i;
    for (i = 0; i < 4; i++) {
        result[i] = 0;
    }
    char buf[18] = {0}, p = 0, q = 0;
    strcpy(buf, point);
    buf[strlen(point)] = '.';
    for(i = 0;i < 4; i++) {
        q = strchr(buf+p, '.') - buf;
        buf[q] = '\0';
        result[i] = strtol(buf+p, NULL, 10);
        p = q + 1;
    }
    return 1;
}
static int parse_arg(int argc,char const *argv[],char *dev_name,uint8_t *dest_mac_addr,uint8_t *sender_ip,uint8_t *target_ip)
{
    int i;
    if(argc == 5){
        strncpy(dev_name,argv[1],sizeof(dev_name));
        ip4str_parse(argv[2],sender_ip);
        ip4str_parse(argv[3],target_ip);
        macstr_parse(argv[4],dest_mac_addr);
    }else if(argc == 4){
        strncpy(dev_name,argv[1],sizeof(dev_name));
        ip4str_parse(argv[2],sender_ip);
        ip4str_parse(argv[3],target_ip);
        for(i=0;i<6;i++){
            dest_mac_addr[i] = 0xff;
        }
    }else{
        return -1;
    }
    printf("dev:%s\n",dev_name);
    printf("destination mac:%02X:%02X:%02X:%02X:%02X:%02X\n",dest_mac_addr[0],dest_mac_addr[1],dest_mac_addr[2],dest_mac_addr[3],dest_mac_addr[4],dest_mac_addr[5]);
    printf("sender ip:%u.%u.%u.%u\n",sender_ip[0],sender_ip[1],sender_ip[2],sender_ip[3]);
    printf("target ip:%u.%u.%u.%u\n",target_ip[0],target_ip[1],target_ip[2],target_ip[3]);
    return 0;
}

参考自 https://blog.csdn.net/u014302425/article/details/113844474

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ArpSender是C#写的ARP发包器,写的初衷是想试下什么样的ARP包才会引起ARP攻击,构造一些包可能会导致别人上不了网。至于包怎么填,发挥大家的想象吧,嘿嘿。 ArpSender用了SharpPcap这个开源API,有兴趣的到网上查下,用起来挺简单的。编程过程中最大的问题就是线程的问题。发包的代码中用了BackgroundWorker控件,因为参数只能传一个,并且线程是不允许直接调用主窗口控件,后来用了一个结构体struct ArpPac来传,感觉还是很麻烦啊!不过还好在BackgroundWorker的RunWorkerCompleted可以直接操作主窗口控件了,能把结果显示到主窗口上。 在编写获取IP的MAC地址部分,一开始还是用BackgroundWorker,在获取存在的IP地址MAC时可以正常工作,可是当IP不存在是,DOWORK方法一直没结束。因为里面一个Resolve方法一直没返回,也没超时设定,线程就一直卡在那不动了。也不知道该怎么结束这个线程。于是改用了Thread,传参数用了个object数组,嘿嘿,所有参数都封起来。到了那边再解封,很好用。后来才发现,线程是没有返回值的。。又不能直接操作窗体控件。。没办法,只好设个全局变量来保存结果了。获取MAC部分还用了个Timer控件,1秒钟如果还没得到返回的MAC,直接结束该线程。。。 BackgroundWorker 用起来简单也很好用,如果有个abort方法的话。。。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值