当前位置: 首页 > 面试题库 >

使用C套接字编程进行arp请求和回复

支嘉祥
2023-03-14
问题内容

我正在尝试在 Linux(Ubuntu)中 使用c编程来接收和发送arp数据包。
我的程序运行正常(即运行无任何错误),但是我无法使用Wireshark跟踪数据包。

源代码

#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);
}

问题答案:

有几件事情可以使您的数据包通过有线/空中传输。

  • 适用于arp回复的.sll_protocol是ETH_P_ARP,来自 <linux/if_ether.h>
  • 设置ah-> arp_op时,字节序错误。它是2个字节的网络字节序字段,因此请使用htons()。

  • 通常,该代码对网络和主机字节顺序有些困惑。当前,它发出的答复非常混乱,但是我不清楚这是代码的恶意意图还是事故。如果要发送真实,正确的IP地址,请在构建回复时使用htonl和htons。

要修复字节顺序:

  • 正确包含 <arpa/inet.h>
  • 始终使用htons(),htonl()ntohs()和ntohl()。它们的实现使其成为NOP(如果您的平台上不需要)。
  • 设置要从主机发送的数据时,请始终使用hton *()处理它
  • 解释来自网络的数据时,在与局部变量进行比较之前,请始终先进行ntoh *()。

总而言之,我所做的更改是1).sll_protocol = htons(ETH_P_ARP)。(在发送数据时)2)ah-> arp_op =
htons(ARPOP_REPLY)(在回复arp中)3)删除了ah-> arp_hd和ah->
arp_pr上的毫无意义的ntohs()。填充发送缓冲区时,您不希望将数据转换为主机字节序(除非您实际上确实如此)4)在某些比较中添加了ntohs()转换并进行了适当的定义5)其他一些小的修正6)禁用了位处理系统(“
sudo …”)!

在pastebin的完整代码。这是一个差异:

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;

编辑 一些wireshark建议。捕获 以太原型0x0806 (或简称 arp )。使用捕获任何数据包的伪设备。您的数据包应该变得可见。

在Linux上,如果要停止网络堆栈的干扰,请使用:echo“ 8”> / proc / sys / net / ipv4 / conf / all /
arp_ignore

编辑#2
我不确定ETH_P_ARP。就我而言,这可能是个快速的判断。在ARP标头字段中使用ETH_P_IP是正确的,但是我不确定用于数据包套接字sll_protocol的哪个。另请注意,socket_address.sll_pkttype = PACKET_OTHERHOST;发送时无效(请参见man 7数据包)。同样是强制性的SO观察,即应始终 至少 使用-
Wall(使用gcc或clang时)作为编译标志。

编辑#3 我改变了一点程序。并相应地更新了答案和差异。确实确实令人惊讶的是,.sll_protocol必须是ETH_P_ARP。我的 man
7数据包
副本甚至没有说它用于任何用途,但是如果没有它,该数据包就不会像ARP一样直接发送出去。



 类似资料:
  • 本文向大家介绍在Python中使用多线程进行套接字编程?,包括了在Python中使用多线程进行套接字编程?的使用技巧和注意事项,需要的朋友参考一下 多线程概念 多线程是几乎所有现代编程语言(尤其是python)的核心概念,因为它的线程实现简单。 线程是程序内的子程序,可以独立于代码的其他部分执行。线程在同一上下文中执行,以共享程序的可运行资源(如内存)。 当在一个进程中,我们同时执行多个线程时,称

  • 先说明我的问题。我已经在这里张贴了另一个类似的问题:PrintStream不能正确打印unicode字符(UTF-16 ),但不知何故我没有设法克服这个问题。 我想从android打印到网络打印机(施乐WC 24 PCL或者爱普生XP-600)。< br >假设: 我有以下文字: 然后我用“ISO-8859-7”、“Windows-1253”(希腊字符)调用以下代码: 但是打印机的结果(在ecli

  • 问题内容: 我正在尝试使用请求获取正确的编码。 不管我做什么,丹麦字符的编码都不对。 有什么想法吗? 问题答案: 也许您的麻烦在于标题。假设您的标题为 如果是这样,您有2种方法可以解决此问题: 删除此标题 使用以下代码解压缩数据: });

  • 我是Java和JavaFX的新手,所以请原谅我的新手问题。在过去的几天里,我一直在寻找我正在努力做的事情的例子,但是没有找到任何答案。下面是我正在尝试做的:我试图创建一个简单的javafx GUI客户端套接字应用程序,使用场景生成器连接到服务器并发送/接收数据。很简单,但是当我试图在JavaFX中实现它时,我的图形用户界面冻结了。我研究发现,原因是套接字通信占用了所有的时间,javafx GUI无

  • 问题内容: 我想在Unix套接字上使用node-ipc在NodeJS和C程序之间进行通信,根据该主页,这是最快的选择。(它们将在同一台计算机上)。该软件包声称它可以与C程序通信。(我必须进行健全性检查)。 问题在于示例没有提供示例C代码,而且我几乎不知道如何让他们交谈。 谁能指出我一个C代码示例以匹配那些客户机/服务器示例?例如,我将如何改编本教程以在C中使用unix管道(假设我还没有完全脱离轨道

  • 在本节中,我们将讨论和学习一个名为MITMf(man-in-the-middle framework)的工具。这个工具允许我们运行一些MITM攻击。在本节中,我们将使用基本的ARP中毒攻击,就像在上一节中所做的那样。我们将使用我们的Wi-Fi卡进行这些攻击。可以使用以太网虚拟卡代替Wi-Fi卡。 使用命令来查看网卡接口,卡使用IP 连接到互联网网络: 在Windows机器上运行以查看我们的MAC地