美文网首页
原始套接字发送ARP

原始套接字发送ARP

作者: 二进制人类 | 来源:发表于2022-09-22 19:46 被阅读0次

    相关API

    #include <sys/types.h>
    #include <sys/socket.h>
    
    /**
     * [sendto 发送]
     * @param  sockfd    [套接字文件描述符]
     * @param  buf       [原始套接字需要发送数据帧]
     * @param  len       [长度]
     * @param  flags     [数据发送的方式,在原始套接字中一般使用0表示阻塞模式发送]
     * @param  dest_addr [需要发送的网络接口(对应的网卡设备)]
     * @param  addrlen   [上个参数大小]
     * @return           [成功返回发送数据的字节数,失败返回-1且修改errno的值]
     */
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    
    #include <netpaket/packet.h>                /* 头文件的路径:/usr/include */
    struct sockaddr_ll
    {
        unsigned short int sll_family;        /* 一般为AP_PACKET */
        unsigned short int sll_protocol;      /* 上次协议 */
        int sll_ifindex;                      /* 需要发送数据的接口类型 */
        unsigned short int sll_hatype;        /* 报头类型 */
        unsigned char sll_pkttype;            /* 包类型 */
        unsigned char sll_halen;              /* 地址长度 */
        unsigned char sll_addr[8];            /* MAC地址 */
    }; 
    //PS:注意在整个数据发送的过程,只需要初始化接口类型成员(.sll_ifindex);
    
    #include <sys/ioctl.h>
    /*
    功能:设置网络接口类型
    参数:
        参数1:fd表示需要设置设备文件的文件描述符;
        参数2:request请求:由于是用来设置网络设备接口类型,所以使用SIOCGIFINDEX,
        SIOCGIFINDEX获取网络接口
        SIOCSIFADDR设置接口地址
        SIOCGIGADDR获取接口地址
        SIOCSIFFLAGS设置接口标志
        SIOCGIFFLAGS获取接口标志
        参数3的数据类型:struct ifreq
    */
    int ioctl(int fd, unsigned long request, ...);
    

    实例

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>          
    #include <sys/socket.h>
    #include <netinet/ether.h>
    #include <arpa/inet.h>
    #include <net/if.h>
    #include <netpacket/packet.h>
    #include <sys/ioctl.h>
    
    int SendTo(int sockfd, void *msg, int msg_len, char *eth_name)
    {
        int ret;
        struct ifreq ethreq;
        struct sockaddr_ll sll;
    
        /* 获取网络接口类型 */
        memset(&ethreq, 0, sizeof(ethreq));
        strncpy(ethreq.ifr_name, eth_name, IFNAMSIZ);
        ret = ioctl(sockfd, SIOCGIFINDEX, &ethreq);
        if (ret == -1)
        {
            perror("ioctl");
            return -1;
        }
    
        /* 设置网络接口类型 */
        memset(&sll, 0, sizeof(sll));
        sll.sll_ifindex = ethreq.ifr_ifindex;
    
        /* 发送数据 */
        ret = sendto(sockfd, msg, msg_len, 0, (const struct sockaddr *)&sll, sizeof(sll));
        if (ret == -1)
        {
            perror("sendto");
            return -1;
        }
    }
    
    int main()
    {
        int ret;
        int sockfd;
        int msg_len;
        unsigned char buf[1024];
    
        /* 创建原始套接字文件:基于链路层,可用于任意协议数据的收发 */
        sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if(sockfd == -1)
        {
            perror("socket");
            return -1;
        }
        printf("sockfd = %d\n", sockfd);
    
        /* 组ARP请求报文数据 */
        unsigned char msg[1024] =
        {
            /* --------------组以太网数据报文-----14---------- */
            0xff, 0xff, 0xff, 0xff, 0xff, 0xff,/* 目的mac:在ARP的请求时候以广播形式发送,所以目的mac为广播mac */
            0x00, 0x0c, 0x29, 0x84, 0x0e, 0x96,/* 源mac:发送主机的mac地址 */
            0x08, 0x06,/* 数据帧类型:ARP请求的类型编号为0x0806 */
            /* --------------组ARP请求报文-----28---------- */
            0x00, 0x01,/* 硬件类型:1 = 以太网类型 */
            0x08, 0x00,/* 协议类型:0x0800 IP协议 */
            0x06,/* 硬件地址(mac地址长度):6 */
            0x04,/* 协议地址(IP地址长度):4 */
            0x00, 0x01,/* ARP报文类型:1 = ARP请求*/
            0x00, 0x0c, 0x29, 0x84, 0x0e, 0x96,/* 源mac:发送主机的mac地址 */
            10, 7, 181, 108,/* 源IP:发送主机的IP地址 */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/* 目的mac:接收主机的mac地址 */
            10, 7, 181, 28/*目的IP:接收主机的IP地址*/
        };
        msg_len = 14 + 28;
    
        /* 发送数据 */
        SendTo(sockfd, msg, msg_len, "ens33");
        while(1)
        {
            ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
            if (ret == -1)
            {
                perror("recvfrom");
                return -1;
            }
    
            if (ntohs(*(unsigned short *)(buf + 12)) != 0x0806)
            {
                continue;
            }
    
            if (ntohs(*(unsigned short *)(buf + 20)) != 2)
            {
                continue;
            }
    
            /* ARP 应答 */
            char src_ip[16];
            inet_ntop(AF_INET, buf + 28, src_ip, sizeof(src_ip));
    
            char src_mac[18];
            sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[22], buf[23], buf[24], buf[25], buf[26], buf[27]);
    
            if (strcmp(src_ip, "10.7.181.67") == 0)
            {
                printf("%s -> %s\n", src_ip, src_mac);
                break;
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:原始套接字发送ARP

          本文链接:https://www.haomeiwen.com/subject/ufwnortx.html