美文网首页
原始套接字发送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

    相关API 实例

  • 原始套接字发送UDP

  • 第四十二天——[原始套接字]

    学习内容:原始套接字收获: 了解了原始套接字的概念; 了解了链路层原始套接字的创建; 了解了UDP封包格式; 了解...

  • 原始套接字

    1.原始套接字编写的程序执行需要sudo权限 2.拼接包时要注意拼接位置 3.UDP要加上一个伪头部再计算检验和,...

  • 广播的发送与接收

    广播的发送 流程 创建socket 设置套接字选项(在默认情况下,UDP套接字文件不允许发送广播,需要设置套接字文...

  • 链路层原始套接字

    创建套接字的函数原型如下 对于链路层原始套接字来说,第一个参数指定协议族类型为PF_PACKET,第二个参数typ...

  • Day18-总结

    01-服务端套接字 套接字又叫套接字,指的是实现通信的两个端。等待请求的一段叫服务端套接字,发送请求的叫客户端套接...

  • udp网络程序发送、接收数据

    基于udp的网络程序流程 步骤: 创建客户端套接字 发送/接收数据 关闭套接字udp.jpg 实现代码1--发送数...

  • iOS之Socket编程最全总结

    Socket简介: 所谓socket,通常称为“套接字”,网络应用程序通过套接字向网络发送请求或者应答网络请求...

  • Android Socket简介

    什么是Socket Socket又叫“套接字” 应用程序通过“套接字”向网络发送请求或接收网络请求。 Java中有...

网友评论

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

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