ARP请求和应答使用C套接字编程

ARP请求和应答使用C套接字编程

本文介绍了ARP请求和应答使用C套接字编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想接收和的Linux(Ubuntu的)结果使用C语言编程发送ARP数据包
我的程序工作正常(即运行没有任何错误),但我不能跟踪使用Wireshark的数据包。

源$ C ​​$ C

 的#include< SYS / socket.h中>
#包括LT&; SYS / ioctl.h>
#包括LT&; SYS / time.h中>#包括LT&; ASM / types.h中>#包括LT&;&math.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&signal.h中GT;#包括LT&; Linux的/ if_packet.h>
#包括LT&; Linux的/ if_ether.h>
#包括LT&; Linux的/ if_arp.h>#定义BUF_SIZE 42
#定义DEVICEeth0的
#定义ETH_P_NULL为0x0
#定义ETH_MAC_LEN ETH_ALEN
#定义ETH_ARP 0x0806INT S = 0; / * * Socketdescriptor /
无效*缓冲区= NULL;
长total_packets = 0;
长answered_pa​​ckets = 0;无效SIGINT(INT正负号);结构__attribute __((包装))arp_header
{
    无符号短arp_hd;
    无符号短arp_pr;
    unsigned char型arp_hdl;
    unsigned char型arp_prl;
    无符号短arp_op;
    unsigned char型arp_sha [6];
    unsigned char型arp_spa [4];
    unsigned char型arp_dha [6];
    unsigned char型arp_dpa [4];
};
诠释主要(无效){
    缓冲=(无效*)malloc的(BUF_SIZE); / *缓冲区以太帧* /
    无符号字符* etherhead =缓冲; / *指向Ethenet头* /
    结构ethhdr * EH =(结构ethhdr *)etherhead; / *另一个指针
                                                    以太网帧头* /
    无符号字符* arphead =缓冲区+ 14;
    结构arp_header *啊;
    unsigned char型src_mac [6]; / *我们的MAC地址* /    结构的ifreq IFR;
    结构sockaddr_ll socket_address;
    INT的ifIndex = 0; / *以太网接口指数* /
    INT I;
    INT长; / *接收的分组的长度* /
    INT发送;    的printf(服务器开始,进入initialiation相... \\ n);    / *打开套接字* /
    S =插座(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    如果(S == -1){
        PERROR(插座());
        出口(1);
    }
    的printf(成功打开插座:%I \\ N,S);    / *检索以太网接口索引* /
    函数strncpy(ifr.ifr_name,装置IFNAMSIZ);
    如果(的ioctl(S,SIOCGIFINDEX,&安培; IFR)== -1){
        PERROR(SIOCGIFINDEX);
        出口(1);
    }
    索引序号= ifr.ifr_ifindex;
    的printf(顺利地拿到了接口索引:%I \\ N的ifIndex);    / *检索对应的MAC * /
    如果(的ioctl(S,SIOCGIFHWADDR,&安培; IFR)== -1){
        PERROR(SIOCGIFINDEX);
        出口(1);
    }
    对于(I = 0; I&10 6;我++){
        src_mac [I] = ifr.ifr_hwaddr.sa_data [I]
    }
    的printf(成功得到了我们的MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
        src_mac [0],src_mac [1],src_mac [2],src_mac [3],src_mac [4],src_mac [5]);    / * prepare sockaddr_ll * /
    socket_address.sll_family = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_IP);
    socket_address.sll_ifindex = ifIndex的;
    socket_address.sll_hatype = ARPHRD_ETHER;
    socket_address.sll_pkttype = PACKET_OTHERHOST;
    socket_address.sll_halen = 0;
    socket_address.sll_addr [6] = 0×00;
    socket_address.sll_addr [7] = 0×00;
    / *建立信号处理程序* /
    信号(SIGINT,SIGINT);
    的printf(为SIGINT \\ n成功建立信号处理程序);
    的printf(我们在生产状态,等待进入的数据包.... \\ n);    而(1){
        / *等待进入的数据包... * /
        长度= recvfrom的(S,缓冲器,BUF_SIZE,0,NULL,NULL);
        如果(长度== -1)
        {
            PERROR(recvfrom的());
            出口(1);
        }
        如果(htons(EH-GT&; h_proto)== 0x806)
        {            unsigned char型buf_arp_dha [6];
            unsigned char型buf_arp_dpa [4];            啊=(结构arp_header *)arphead;
            如果(htons(AH-GT&;!arp_op)= 0×0001)
                继续;
            的printf(缓冲区----------------%S \\ n,(字符*)啊);
            的printf(H / D型:%×PROTO TYPE:%X \\ n,AH-GT&; arp_hd,AH-GT&; arp_pr);
            的printf(H / D一愣:%×PROTO一愣:%X \\ n,AH-GT&; arp_hdl,AH-GT&; arp_prl);
            的printf(操作:%X \\ n,AH-GT&; arp_op);
            的printf(源MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                AH-> arp_sha [0],
                AH-> arp_sha [1],
                AH-> arp_sha [2],
                AH-> arp_sha [3],
                AH-> arp_sha [4]
                AH-> arp_sha [5]
            );
            的printf(发送方IP地址:%02D:%02D:%02D:%02D \\ N,
                AH-> arp_spa [0],
                AH-> arp_spa [1],
                AH-> arp_spa [2],
                AH-> arp_spa [3]
            );
            if(ah->arp_spa[0]==10&&ah->arp_spa[1]==00&&ah->arp_spa[2]==00&&ah->arp_spa[3]==01)
            {
                的printf(发件人IP是.............巴姆巴姆............................. ............. \\ n);
                系统(命令ARP -s 10.0.0.1 00:1E:73:91:04:0D);
            }
            输出(目标MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                AH-> arp_dha [0],
                AH-> arp_dha [1],
                AH-> arp_dha [2],
                AH-> arp_dha [3],
                AH-> arp_dha [4]
                AH-> arp_dha [5]
            );
            输出(目标IP地址:%02D:%02D:%02D:%02D \\ N,
                AH-> arp_dpa [0],
                AH-> arp_dpa [1],
                AH-> arp_dpa [2],
                AH-> arp_dpa [3]
            );            的printf(+++++++++++++++++++++++++++++++++++++++ \\ n);
            的printf(以太DST MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                EH-> h_dest [0],
                EH-> h_dest [1],
                EH-> h_dest [2],
                EH-> h_dest [3],
                EH-> h_dest [4]
                EH-> h_dest [5]
            );
            的printf(以太SRC MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                EH-> h_source [0],
                EH-> h_source [1],
                EH-> h_source [2],
                EH-> h_source [3],
                EH-> h_source [4]
                EH-> h_source [5]
            );
            的memcpy((无效*)etherhead,(常量无效*)(etherhead + ETH_MAC_LEN)
                ETH_MAC_LEN);
            的memcpy((无效*)(etherhead + ETH_MAC_LEN),(常量无效*)src_mac,
                ETH_MAC_LEN);
            EH-GT&; h_proto = ETH_ARP;
            printf(\"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \\ n);
            的printf(以太DST MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                EH-> h_dest [0],
                EH-> h_dest [1],
                EH-> h_dest [2],
                EH-> h_dest [3],
                EH-> h_dest [4]
                EH-> h_dest [5]
            );
            的printf(以太SRC MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                EH-> h_source [0],
                EH-> h_source [1],
                EH-> h_source [2],
                EH-> h_source [3],
                EH-> h_source [4]
                EH-> h_source [5]
            );
            AH-GT&; arp_hd = ntohs和(AH-GT&; arp_hd);
            AH-GT&; arp_pr = ntohs和(AH-GT&; arp_pr);            AH-GT&; arp_op = 0×0002;            buf_arp_dpa [0] = AH-> arp_dpa [0];
            buf_arp_dpa [1] = AH-> arp_dpa [1];
            buf_arp_dpa [2] = AH-> arp_dpa [2];
            buf_arp_dpa [3] = AH-> arp_dpa [3];            AH-> arp_dha [0] = AH-> arp_sha [0];
            AH-> arp_dha [1] = AH-> arp_sha [1];
            AH-> arp_dha [2] = AH-> arp_sha [2];
            AH-> arp_dha [3] = AH-> arp_sha [3];
            AH-> arp_dha [4] = AH-> arp_sha [4];
            AH-> arp_dha [5] = AH-> arp_sha [5];            AH-> arp_dpa [0] = AH-> arp_spa [0];
            AH-> arp_dpa [1] = AH-> arp_spa [1];
            AH-> arp_dpa [2] = AH-> arp_spa [2];
            AH-> arp_dpa [3] = AH-> arp_spa [3];            AH-> arp_spa [0] = buf_arp_dpa [0];
            AH-> arp_spa [1] = buf_arp_dpa [1];
            AH-> arp_spa [2] = buf_arp_dpa [2];
            AH-> arp_spa [3] = buf_arp_dpa [3];
            //改变发送者的MAC地址
            AH-> arp_sha [0] = 0×00;
            AH-> arp_sha [1] = 0X1E;
            AH-> arp_sha [2] = 0x73;
            AH-> arp_sha [3] = 0x78;
            AH-> arp_sha [4] = 0x9A执行;
            AH-> arp_sha [5] =符进行;            socket_address.sll_addr [0] = EH-> h_dest [0];
            socket_address.sll_addr [1] = EH-> h_dest [1];
            socket_address.sll_addr [2] = EH-> h_dest [2];
            socket_address.sll_addr [3] = EH-> h_dest [3];
            socket_address.sll_addr [4] = EH-> h_dest [4];
            socket_address.sll_addr [5] = EH-> h_dest [5];
            的printf(======================================= \\ n);
            的printf(源MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                AH-> arp_sha [0],
                AH-> arp_sha [1],
                AH-> arp_sha [2],
                AH-> arp_sha [3],
                AH-> arp_sha [4]
                AH-> arp_sha [5]
            );
            的printf(发送方IP地址:%02D:%02D:%02D:%02D \\ N,
                AH-> arp_spa [0],
                AH-> arp_spa [1],
                AH-> arp_spa [2],
                AH-> arp_spa [3]
            );
            如果((AH-> arp_spa [0] == 10安培;&安培; AH-> arp_spa [1] == 0安培;&安培; AH-> arp_spa [2] == 0安培;&安培; AH- > arp_spa [3] == 1))
                printf(\"------------------------------------------10.0.0.1-----------------------------------------\
\");
            输出(目标MAC地址:%02X:%02X:%02X:%02X:%02X:%02X \\ n
                AH-> arp_dha [0],
                AH-> arp_dha [1],
                AH-> arp_dha [2],
                AH-> arp_dha [3],
                AH-> arp_dha [4]
                AH-> arp_dha [5]
            );
            输出(目标IP地址:%02D:%02D:%02D:%02D \\ N,
                AH-> arp_dpa [0],
                AH-> arp_dpa [1],
                AH-> arp_dpa [2],
                AH-> arp_dpa [3]
            );
            的printf(H / D型:%×PROTO TYPE:%X \\ n,AH-GT&; arp_hd,AH-GT&; arp_pr);
            的printf(H / D一愣:%×PROTO一愣:%X \\ n,AH-GT&; arp_hdl,AH-GT&; arp_prl);
            的printf(操作:%X \\ n,AH-GT&; arp_op);            送= SENDTO(S,缓冲器,BUF_SIZE,0,(结构
                的sockaddr *)及socket_address,sizeof的(socket_address));
            如果(发送== -1)
            {
                PERROR(SENDTO());
                出口(1);
            }            answered_pa​​ckets ++;        }        total_packets ++;    }
}无效SIGINT(INT正负号){
    /*清理.......*/    结构的ifreq IFR;    如果(S == -1)
        返回;    函数strncpy(ifr.ifr_name,装置IFNAMSIZ);
    的ioctl(S,SIOCGIFFLAGS,&安培; IFR);
    ifr.ifr_flags&安培; =〜IFF_PROMISC;
    的ioctl(S,SIOCSIFFLAGS,&安培; IFR);
    接近(S);    免费(缓冲);    的printf(服务器终端.... \\ n);    的printf(完全接受:%ld的数据包的\\ n,total_packets);
    的printf(%回答LD包\\ n,answered_pa​​ckets);
    出口(0);
}


解决方案

一对夫妇的事情,才能上线/空你的数据包。


  • 的ARP应答正确.sll_protocol是ETH_P_ARP,从< Linux的/ if_ether.h>

  • 设置AH-> arp_op时出现在字节顺序错误。这是byteorder 2字节的领域的网络,所以使用htons()。


  • 在一般情况下,code是关于网络和主机byteorder有点困惑。目前,它发出的答复很错位,但我不清楚这是否是code的恶意,或事故。在要发送实时,正确的IP地址,使用htonl和htons的情况下,构建回复时。


要解决的字节顺序:


  • 正确包括< ARPA / inet.h>

  • 使用htons(),htonl()ntohs和()和ntohl(),始终如一。它们的实施​​使得它NOP,如果不需要你的平台上。

  • 当设置数据从主机发送出去,总是hton *处理它()

  • 当从网间preting数据,总是ntoh *()之前与局部变量比较。

在总之,我做的改变是1).sll_protocol = htons(ETH_P_ARP)。 (发送数据时)2)AH-> arp_op = htons(ARPOP_REPLY)(在回复ARP)3)删除了无意义ntohs和()的AH-> arp_hd和AH-> arp_pr。你不想把数据转换中的一些比较5)其他一些小修正6)禁止该位做系统填充发送缓冲区(除非你真的真的实际做)4)增加ntohs和()的转换和正确定义何时举办byteorder (须藤...)!

全部code。在。这里是一个差异:

  thuovila @ GLX:〜/ src目录/ SO / ARP $差异arp2.c arp_orig.c
13D12
< #包括LT&; ARPA / inet.h>
20c19
< #定义设备的eth1
---
> #定义DEVICEeth0的
25c24
<的int = -1; / * * Socketdescriptor /
---
> INT S = 0; / * * Socketdescriptor /
92c91
< socket_address.sll_protocol = htons(ETH_P_ARP);
---
> socket_address.sll_protocol = htons(ETH_P_IP);
95c94
< socket_address.sll_pkttype = 0; // PACKET_OTHERHOST;
---
> socket_address.sll_pkttype = PACKET_OTHERHOST;
112c111
<如果(ntohs和(EH-GT&; h_proto)== ETH_P_ARP)
---
>如果(htons(EH-GT&; h_proto)== 0x806)
119c118
<如果(ntohs和(AH-GT&;!arp_op)= ARPOP_REQUEST)
---
>如果(htons(AH-GT&;!arp_op)= 0×0001)
139d137
< #如果0
145d142
< #万一
182c179
< EH-GT&; h_proto = htons(ETH_P_ARP);
---
> EH-GT&; h_proto = ETH_ARP;
200,201c197,198
< // AH-GT&; arp_hd = ntohs和(AH-GT&; arp_hd);
< // AH-GT&; arp_pr = ntohs和(AH-GT&; arp_pr);
---
> AH-GT&; arp_hd = ntohs和(AH-GT&; arp_hd);
> AH-GT&; arp_pr = ntohs和(AH-GT&; arp_pr);
203c200
< AH-GT&; arp_op = htons(ARPOP_REPLY);
---
> AH-GT&; arp_op = 0×0002;

修改 Wireshark的一些建议。捕获的醚原0x0806 的(或 ARP 的简称)。使用捕获​​任何数据包的伪设备。你的数据包应该成为可见的。

在Linux上,如果你想从干涉,停止使用网络堆栈:回声8>的/ proc / SYS /网/的IPv4 / conf目录/所有/ arp_ignore

编辑#2 我不能完全肯定的ETH_P_ARP。这可能是对我而言轻而易举的判断。使用ETH_P_IP是正确的ARP报头字段,但是我不知道一个用于数据包插座sll_protocol其中。还要注意, socket_address.sll_pkttype = PACKET_OTHERHOST; 发送时没有任何影响(见男子7包)。另外,强制性SO观察,你应该总是使用至少(使用gcc或铛时)作为编译标志-Wall。

编辑#3 我改变了计划多一点。并相应更新了答案和差异。令人惊奇的是它确实似乎,该.sll_protocol需要ETH_P_ARP。我的副本中的 7人包的甚而不说出来是用于什么,但该数据包犯规出门就丝为ARP离不开它了。

I am trying to receive and send arp packets using c programming in Linux (Ubuntu)
My program works fine (i.e. runs without any error), but I cannot trace the packets using Wireshark.

source code:

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <asm/types.h>

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

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

#define BUF_SIZE 42
#define DEVICE "eth0"
#define ETH_P_NULL 0x0
#define ETH_MAC_LEN ETH_ALEN
#define ETH_ARP 0x0806

int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_packets = 0;
long answered_packets = 0;

void sigint(int signum);

struct __attribute__((packed)) arp_header
{
    unsigned short arp_hd;
    unsigned short arp_pr;
    unsigned char arp_hdl;
    unsigned char arp_prl;
    unsigned short arp_op;
    unsigned char arp_sha[6];
    unsigned char arp_spa[4];
    unsigned char arp_dha[6];
    unsigned char arp_dpa[4];
};
int main(void) {
    buffer = (void*)malloc(BUF_SIZE); /*Buffer for Ethernet Frame*/
    unsigned char* etherhead = buffer;  /*Pointer to Ethenet Header*/
    struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to
                                                    ethernet header*/
    unsigned char* arphead = buffer + 14;
    struct arp_header *ah;
    unsigned char src_mac[6];    /*our MAC address*/

    struct ifreq ifr;
    struct sockaddr_ll socket_address;
    int ifindex = 0;     /*Ethernet Interface index*/
    int i;
    int length;  /*length of received packet*/
    int sent;

    printf("Server started, entering initialiation phase...\n");

    /*open socket*/
    s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (s == -1) {
        perror("socket():");
        exit(1);
    }
    printf("Successfully opened socket: %i\n", s);

    /*retrieve ethernet interface index*/
    strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ);
    if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
    ifindex = ifr.ifr_ifindex;
    printf("Successfully got interface index: %i\n", ifindex);

    /*retrieve corresponding MAC*/
    if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
    for (i = 0; i < 6; i++) {
        src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
    }
    printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
        src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);

    /*prepare sockaddr_ll*/
    socket_address.sll_family = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_IP);
    socket_address.sll_ifindex = ifindex;
    socket_address.sll_hatype = ARPHRD_ETHER;
    socket_address.sll_pkttype = PACKET_OTHERHOST;
    socket_address.sll_halen = 0;
    socket_address.sll_addr[6] = 0x00;
    socket_address.sll_addr[7] = 0x00;
    /*establish signal handler*/
    signal(SIGINT, sigint);
    printf("Successfully established signal handler for SIGINT\n");
    printf("We are in production state, waiting for incoming packets....\n");

    while (1) {
        /*Wait for incoming packet...*/
        length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
        if (length == -1)
        {
            perror("recvfrom():");
            exit(1);
        }
        if(htons(eh->h_proto) == 0x806)
        {

            unsigned char buf_arp_dha[6];
            unsigned char buf_arp_dpa[4];

            ah = (struct arp_header *)arphead;
            if(htons(ah->arp_op) != 0x0001)
                continue;
            printf("buffer is---------------- %s \n",(char*)ah);
            printf("H/D TYPE : %x PROTO TYPE : %x \n",ah->arp_hd,ah->arp_pr);
            printf("H/D leng : %x PROTO leng : %x \n",ah->arp_hdl,ah->arp_prl);
            printf("OPERATION : %x \n", ah->arp_op);
            printf("SENDER MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                ah->arp_sha[0],
                ah->arp_sha[1],
                ah->arp_sha[2],
                ah->arp_sha[3],
                ah->arp_sha[4],
                ah->arp_sha[5]
            );
            printf("SENDER IP address: %02d:%02d:%02d:%02d\n",
                ah->arp_spa[0],
                ah->arp_spa[1],
                ah->arp_spa[2],
                ah->arp_spa[3]
            );
            if(ah->arp_spa[0]==10&&ah->arp_spa[1]==00&&ah->arp_spa[2]==00&&ah->arp_spa[3]==01)
            {
                printf("Sender ip is .............bam bam..........................................\n");
                system("sudo arp -s 10.0.0.1  00:1e:73:91:04:0d");
            }
            printf("TARGET MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                ah->arp_dha[0],
                ah->arp_dha[1],
                ah->arp_dha[2],
                ah->arp_dha[3],
                ah->arp_dha[4],
                ah->arp_dha[5]
            );
            printf("TARGET IP address: %02d:%02d:%02d:%02d\n",
                ah->arp_dpa[0],
                ah->arp_dpa[1],
                ah->arp_dpa[2],
                ah->arp_dpa[3]
            );

            printf("+++++++++++++++++++++++++++++++++++++++\n" );
            printf("ETHER DST MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                eh->h_dest[0],
                eh->h_dest[1],
                eh->h_dest[2],
                eh->h_dest[3],
                eh->h_dest[4],
                eh->h_dest[5]
            );
            printf("ETHER SRC MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                eh->h_source[0],
                eh->h_source[1],
                eh->h_source[2],
                eh->h_source[3],
                eh->h_source[4],
                eh->h_source[5]
            );
            memcpy( (void*)etherhead, (const void*)(etherhead+ETH_MAC_LEN),
                ETH_MAC_LEN);
            memcpy( (void*)(etherhead+ETH_MAC_LEN), (const void*)src_mac,
                ETH_MAC_LEN);
            eh->h_proto = ETH_ARP;
            printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \n");
            printf("ETHER DST MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                eh->h_dest[0],
                eh->h_dest[1],
                eh->h_dest[2],
                eh->h_dest[3],
                eh->h_dest[4],
                eh->h_dest[5]
            );
            printf("ETHER SRC MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                eh->h_source[0],
                eh->h_source[1],
                eh->h_source[2],
                eh->h_source[3],
                eh->h_source[4],
                eh->h_source[5]
            );
            ah->arp_hd = ntohs(ah->arp_hd);
            ah->arp_pr = ntohs(ah->arp_pr);

            ah->arp_op = 0x0002;

            buf_arp_dpa[0] = ah->arp_dpa[0];
            buf_arp_dpa[1] = ah->arp_dpa[1];
            buf_arp_dpa[2] = ah->arp_dpa[2];
            buf_arp_dpa[3] = ah->arp_dpa[3];

            ah->arp_dha[0] = ah->arp_sha[0];
            ah->arp_dha[1] = ah->arp_sha[1];
            ah->arp_dha[2] = ah->arp_sha[2];
            ah->arp_dha[3] = ah->arp_sha[3];
            ah->arp_dha[4] = ah->arp_sha[4];
            ah->arp_dha[5] = ah->arp_sha[5];

            ah->arp_dpa[0] = ah->arp_spa[0];
            ah->arp_dpa[1] = ah->arp_spa[1];
            ah->arp_dpa[2] = ah->arp_spa[2];
            ah->arp_dpa[3] = ah->arp_spa[3];

            ah->arp_spa[0] = buf_arp_dpa[0];
            ah->arp_spa[1] = buf_arp_dpa[1];
            ah->arp_spa[2] = buf_arp_dpa[2];
            ah->arp_spa[3] = buf_arp_dpa[3];
            //change the sender mac address
            ah->arp_sha[0] = 0x00;
            ah->arp_sha[1] = 0x1e;
            ah->arp_sha[2] = 0x73;
            ah->arp_sha[3] = 0x78;
            ah->arp_sha[4] = 0x9a;
            ah->arp_sha[5] = 0x0d;

            socket_address.sll_addr[0] = eh->h_dest[0];
            socket_address.sll_addr[1] = eh->h_dest[1];
            socket_address.sll_addr[2] = eh->h_dest[2];
            socket_address.sll_addr[3] = eh->h_dest[3];
            socket_address.sll_addr[4] = eh->h_dest[4];
            socket_address.sll_addr[5] = eh->h_dest[5];
            printf("=======================================\n" );
            printf("SENDER MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                ah->arp_sha[0],
                ah->arp_sha[1],
                ah->arp_sha[2],
                ah->arp_sha[3],
                ah->arp_sha[4],
                ah->arp_sha[5]
            );
            printf("SENDER IP address: %02d:%02d:%02d:%02d\n",
                ah->arp_spa[0],
                ah->arp_spa[1],
                ah->arp_spa[2],
                ah->arp_spa[3]
            );
            if((ah->arp_spa[0]==10 && ah->arp_spa[1]==0 && ah->arp_spa[2]==0 && ah->arp_spa[3]==1))
                printf("------------------------------------------10.0.0.1-----------------------------------------\n");
            printf("TARGET MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                ah->arp_dha[0],
                ah->arp_dha[1],
                ah->arp_dha[2],
                ah->arp_dha[3],
                ah->arp_dha[4],
                ah->arp_dha[5]
            );
            printf("TARGET IP address: %02d:%02d:%02d:%02d\n",
                ah->arp_dpa[0],
                ah->arp_dpa[1],
                ah->arp_dpa[2],
                ah->arp_dpa[3]
            );
            printf("H/D TYPE : %x PROTO TYPE : %x \n",ah->arp_hd,ah->arp_pr);
            printf("H/D leng : %x PROTO leng : %x \n",ah->arp_hdl,ah->arp_prl);
            printf("OPERATION : %x \n", ah->arp_op);

            sent = sendto(s, buffer, BUF_SIZE, 0, (struct
                sockaddr*)&socket_address, sizeof(socket_address));
            if (sent == -1)
            {
                perror("sendto():");
                exit(1);
            }

            answered_packets++;

        }

        total_packets++;

    }
}

void sigint(int signum) {
    /*Clean up.......*/

    struct ifreq ifr;

    if (s == -1)
        return;

    strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ);
    ioctl(s, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags &= ~IFF_PROMISC;
    ioctl(s, SIOCSIFFLAGS, &ifr);
    close(s);

    free(buffer);

    printf("Server terminating....\n");

    printf("Totally received: %ld packets\n", total_packets);
    printf("Answered %ld packets\n", answered_packets);
    exit(0);
}
解决方案

A couple of things to get your packets on the wire/air.

  • The proper .sll_protocol for the arp reply is ETH_P_ARP, from <linux/if_ether.h>
  • There was an error in endianness when setting ah->arp_op. It is a network byteorder field of 2 octets, so use htons().

  • In general, the code is a little confused about network and host byteorder. It currently sends out the reply very mangled, but it is unclear to me whether that is the malicious intent of the code, or an accident. In the case that you want to send real, correct IP addresses, use htonl and htons, when building the reply.

To fix endianness:

  • Properly include <arpa/inet.h>
  • Use htons(), htonl() ntohs() and ntohl(), always. Their implementation makes it a NOP, if its not needed on your platform.
  • When setting up data to be sent out from host, always process it with hton*()
  • When interpreting data from the network, always ntoh*() it before comparing with local variables.

In summary, the changes I did were 1) .sll_protocol = htons(ETH_P_ARP). (when sending data) 2) ah->arp_op = htons(ARPOP_REPLY) (in the reply arp) 3) Removed the nonsensical ntohs() on ah->arp_hd and ah->arp_pr. You dont want to convert data to host byteorder when populating the send buffer (unless you really really actually do) 4) Added ntohs() conversions and proper defines in some of the comparisons 5) some other small fixes 6) disabled the bit doing system("sudo...")!

Full code at pastebin. Here is a diff:

thuovila@glx:~/src/so/arp$ diff arp2.c arp_orig.c
13d12
< #include <arpa/inet.h>
20c19
< #define DEVICE "eth1"
---
> #define DEVICE "eth0"
25c24
< int s = -1; /*Socketdescriptor*/
---
> int s = 0; /*Socketdescriptor*/
92c91
<       socket_address.sll_protocol = htons(ETH_P_ARP);
---
>       socket_address.sll_protocol = htons(ETH_P_IP);
95c94
<       socket_address.sll_pkttype = 0; //PACKET_OTHERHOST;
---
>       socket_address.sll_pkttype = PACKET_OTHERHOST;
112c111
<               if(ntohs(eh->h_proto) == ETH_P_ARP)
---
>               if(htons(eh->h_proto) == 0x806)
119c118
<                               if(ntohs(ah->arp_op) != ARPOP_REQUEST)
---
>                               if(htons(ah->arp_op) != 0x0001)
139d137
<                               #if 0
145d142
<                               #endif
182c179
<                               eh->h_proto = htons(ETH_P_ARP);
---
>                               eh->h_proto = ETH_ARP;
200,201c197,198
<                               //ah->arp_hd = ntohs(ah->arp_hd);
<                               //ah->arp_pr = ntohs(ah->arp_pr);
---
>                               ah->arp_hd = ntohs(ah->arp_hd);
>                               ah->arp_pr = ntohs(ah->arp_pr);
203c200
<                               ah->arp_op = htons(ARPOP_REPLY);
---
>                               ah->arp_op = 0x0002;

EDIT Some wireshark advice. Capture ether proto 0x0806 (or arp for short). Use the pseudo device that captures any packets. Your packets should become visible.

On linux, if you want to stop the network stack from interfering, use: echo "8" > /proc/sys/net/ipv4/conf/all/arp_ignore

EDIT #2 I am not completely sure about the ETH_P_ARP. It might have been a snap judgement on my part. Using ETH_P_IP is correct in the ARP header field, but Im not sure which one to use for the packet socket sll_protocol. Also notice that socket_address.sll_pkttype = PACKET_OTHERHOST;has no effect when sending (see man 7 packet). Also the mandatory SO observation, that you should always use at least -Wall (when using gcc or clang) as a compilation flag.

EDIT #3 I changed the program a little more. and updated the answer and diff accordingly. Surprisingly it does indeed seem, that .sll_protocol needs to be ETH_P_ARP. My copy of the man 7 packet doesnt even say it is used for anything, but the packet doesnt go out on the wire as ARP without it.

这篇关于ARP请求和应答使用C套接字编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 22:42