当前位置: 首页 > news >正文

linux实现ARP协议

// arp协议
// 以太网头部 || ARP请求/应答
// 目的mac地址 | 源mac地址 | 帧类型 || 硬件类型 | 协议类型 | 硬件地址长度 | 协议地址长度 | 操作方式 | 发送方硬件地址 | 发送方IP地址 | 接收方硬件地址 | 接收方IP地址 |
// 6byte | 6byte | 2byte || 2byte | 2byte | 1byte | 1byte | 2byte | 6byte | 4byte | 6byte | 4byte |

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/types.h>
#include <asm/types.h>
#include <features.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>

// arp协议
// 以太网头部 || ARP请求/应答
// 目的mac地址 | 源mac地址 | 帧类型 || 硬件类型 | 协议类型 | 硬件地址长度 | 协议地址长度 | 操作方式 | 发送方硬件地址 | 发送方IP地址 | 接收方硬件地址 | 接收方IP地址 |
// 6byte      | 6byte     | 2byte || 2byte   | 2byte   | 1byte       | 1byte       | 2byte    | 6byte         | 4byte       | 6byte         | 4byte      |

typedef struct
{
    /* 以太网头部 */
    unsigned char nDstMac[6]; /* 目的mac地址 */
    unsigned char nSrcMac[6]; /* 源mac地址 */
    unsigned short nProto;    /* 帧类型 */

    /* ARP请求/应答 */
    unsigned short hardwareType; /* 硬件类型 */
    unsigned short protoType;    /* 协议类型 */
    unsigned char hardwareLen;   /* 硬件地址长度 */
    unsigned char protoLen;      /* 协议地址长度 */
    unsigned short optionCode;   /* 操作方式 */
    /*mac地址 IP地址*/
    unsigned char srcMac[6];  /* 发送方硬件地址 */
    unsigned char szSrcIp[4]; /* 发送方IP地址 */
    unsigned char dstMac[6];  /* 接收方硬件地址 */
    unsigned char szDstIp[4]; /* 接收方IP地址 */
} ARP_PARAM;                 

void makeArpMsg(ARP_PARAM *pArpMsg, unsigned char *srcMac, unsigned char *srcIp, unsigned char *dstMac, unsigned char *dstIp, int op)
{
    if (NULL == pArpMsg || NULL == srcMac || NULL == srcIp || NULL == dstMac || NULL == dstIp)
    {
        printf("param is null!\n");
        return;
    }
    /*Ether*/
    memcpy(pArpMsg->nSrcMac, srcMac, sizeof(pArpMsg->nSrcMac));
    memset(pArpMsg->nDstMac, 0xff, sizeof(pArpMsg->nDstMac)); /*广播地址ff:ff:ff:ff:ff:ff*/
    pArpMsg->nProto = htons(ETH_P_ARP);
    /*ARP*/
    pArpMsg->hardwareType = htons(ARPHRD_ETHER);
    pArpMsg->protoType = htons(ETH_P_IP);
    pArpMsg->hardwareLen = 6; /*mac长度为6字节*/
    pArpMsg->protoLen = 4;    /*协议长度为4字节,代表ipv4*/
    pArpMsg->optionCode = htons(op == 1 ? ARPOP_REQUEST : ARPOP_REPLY);
    /*ARP报文请求地址填写*/
    memcpy(pArpMsg->srcMac, srcMac, sizeof(pArpMsg->srcMac));
    memcpy(pArpMsg->dstMac, dstMac, sizeof(pArpMsg->dstMac));
    memcpy(pArpMsg->szSrcIp, srcIp, sizeof(pArpMsg->szSrcIp));
    memcpy(pArpMsg->szDstIp, dstIp, sizeof(pArpMsg->szDstIp));
}

int main()
{
    /*arp*/
    ARP_PARAM stuMsg;
    unsigned char srcMac[6] = {0x00, 0x0c, 0x29, 0xf7, 0x7b, 0x0d}; // 源mac地址, ether 00:0c:29:f7:7b:0d
    unsigned char dstMac[6] = {0};
    unsigned int uSrcIp = 0;
    unsigned int uDstIp = 0;

    memset(&stuMsg, 0, sizeof(stuMsg));
    /*填写源ip 和目的ip*/
    uSrcIp = inet_addr("192.168.68.113");
    uDstIp = inet_addr("192.168.68.48");

    /*op为1代表arp报文类型为请求包*/
    makeArpMsg(&stuMsg, srcMac, (unsigned char *)&uSrcIp, dstMac, (unsigned char *)&uDstIp, 1);
    /*创建原始套接字*/
    int arpFd = socket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
    /*设置socket属性为广播*/
    int opt = 1;
    setsockopt(arpFd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
    /*设置发送超时 避免阻塞*/
    struct timeval stuTimeout;
    stuTimeout.tv_sec = 5;
    stuTimeout.tv_usec = 0;
    setsockopt(arpFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&stuTimeout, sizeof(stuTimeout));

    struct sockaddr sock_addr; /* for interface name */
    memset(&sock_addr, 0, sizeof(sock_addr));
    /*指定网卡发送*/
    memcpy(&sock_addr.sa_data, "ens33", strlen("ens33"));

    char recvarp[42] = {0};
    while (1)
    {

        int iRet = sendto(arpFd, &stuMsg, sizeof(stuMsg), 0, &sock_addr, sizeof(sock_addr));
        if (iRet < 0)
        {
            printf("send time out\n");
        }
        else
        {
            printf("send success\n");
        }

        int len = sizeof(sock_addr);
        if (recvfrom(arpFd, recvarp, 42, 0, &sock_addr, &len) == 42)
        {
            memcpy(dstMac, recvarp + 22, 6);

            // 以太网的目的MAC
            struct ether_header *h1 = (struct ether_header *)recvarp;
            // ARP包
            struct ether_arp *arp = (struct ether_arp *)(recvarp + 14); // 以太网的源MAC6个字节 ,目的MAC 6个字节,类型为2字节
            int i = 0;

            // printf("目的MAC:");
            // for (i = 0; i < ETH_ALEN; i++)
            // {
            //     printf("%02x-", h1->ether_dhost[i]);
            // }
            // printf("\n");
            // // 源MAC地址
            // printf("源MAC:");
            // for (i = 0; i < ETH_ALEN; i++)
            // {
            //     printf("%02x-", h1->ether_shost[i]);
            // }
            // printf("\n");
            if ((ntohs)(arp->arp_op) == 2) // 判断是否是ARP响应包,如果是操作方式码为2
            {
                // 硬件类型
                printf("硬件类型:%0x\n", (ntohs)(arp->arp_hrd)); // 1代表硬件接口为以太网接口
                // 协议类型
                printf("协议类型:%0x\n", (ntohs)(arp->arp_pro)); // 0x800代表高层协议为IP
                // 硬件地址长度
                printf("硬件地址长度:%0x\n", arp->arp_hln);
                // 协议地址长度
                printf("协议地址长度:%0x\n", arp->arp_pln);
                // 发送方的MAC地址
                printf("发送方的MAC:");
                for (i = 0; i < ETH_ALEN; i++)
                {
                    printf("%02x-", arp->arp_sha[i]);
                }

                printf("\n");

                printf("发送方的IP:");
                char ip[16];
                inet_ntop(AF_INET, arp->arp_spa, &ip, 16); // arp_spa是一个unsigned char数组
                printf("%s\n", ip);

                break;
            }

            sleep(1);
        }
    }

    makeArpMsg(&stuMsg, srcMac, (unsigned char *)&uSrcIp, dstMac, (unsigned char *)&uDstIp, 1);
    while (1)
    {
        if (sendto(arpFd, &stuMsg, sizeof(stuMsg), 0, &sock_addr, sizeof(sock_addr)) == 42)
        {
            printf("发送ARP\n");
        }
        else
        {
            perror("发送");
            return EXIT_FAILURE;
        }
        sleep(1);
    }

    close(arpFd);

    return 0;
}

相关文章:

  • 数据结构每日一题day3(顺序表)★★★★★
  • css/scss(at-rules)基础使用(basic use)
  • LangChain开发(九)基于Rag实现文档问答
  • 啸叫抑制(AFS)从算法仿真到工程源码实现-第四节-数据仿真
  • Day15 -实例 端口扫描工具 WAF识别工具的使用
  • 【MyBatisPlus】MyBatisPlus介绍与使用
  • spring boot + thymeleaf整合完整例子
  • ES6-Symbol
  • CTF题目《高明的黑客》(强网杯 2019)Write up
  • 靶场(十八)---小白心得思路分享---shenzi
  • 数据库三级填空+应用(2)
  • 使用 gone.WrapFunctionProvider 快速接入第三方服务
  • vue数字公式篇 Tinymce结合使用(二)
  • Python图像处理——基于CSRNet的人群密度检测系统(Pytorch框架)
  • 【Spring AI】基于专属知识库的RAG智能问答小程序开发——功能优化:用户鉴权相关工具类代码
  • 基于深度学习的图像识别技术在智能安防中的应用
  • 设计模式代码
  • 【sylar-webserver】5 协程调度模块
  • Django之旅:第六节--mysql数据库操作增删改查(二)
  • 【程序人生】我的holland原书版职业测试分析
  • 浙江官宣:五一假期,没电、没气、没油车辆全部免费拖离高速
  • 烟花、美食和购物优惠都安排上了,上海多区开启热闹模式
  • 总有黑眼圈是因为“虚”吗?怎么睡才能改善?
  • 物业也能成为居家养老“服务员”,上海多区将开展“物业+养老”试点
  • 北京公园使用指南
  • 国家发改委回应美加征关税:典型的单边主义霸凌做法