web-dev-qa-db-fra.com

requête et réponse arp en utilisant la programmation de socket c

J'essaie de recevoir et d'envoyer des paquets arp en utilisant la programmation c dans Linux (Ubuntu)
Mon programme fonctionne correctement (c'est-à-dire qu'il s'exécute sans aucune erreur), mais je ne peux pas tracer les paquets à l'aide de Wireshark.

code source:

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

Un couple de choses pour obtenir vos paquets sur le fil/l'air.

  • Le .sll_protocol approprié pour la réponse arp est ETH_P_ARP, de <linux/if_ether.h>
  • Il y avait une erreur d'endianisme lors de la définition de ah-> arp_op. Il s'agit d'un champ d'ordre d'octets réseau de 2 octets, utilisez donc htons ().

  • En général, le code est un peu confus au sujet du réseau et de l'ordre des octets de l'hôte. Il envoie actuellement la réponse très mutilé, mais il n'est pas clair pour moi si c'est l'intention malveillante du code, ou un accident. Dans le cas où vous souhaitez envoyer des adresses IP réelles et correctes, utilisez htonl et htons lors de la création de la réponse.

Pour corriger l'endianité:

  • Incluez correctement <arpa/inet.h>
  • Utilisez toujours htons (), htonl () ntohs () et ntohl (). Leur implémentation en fait un NOP, si ce n'est pas nécessaire sur votre plateforme.
  • Lors de la configuration des données à envoyer depuis l'hôte, traitez-les toujours avec hton * ()
  • Lors de l'interprétation des données du réseau, toujours ntoh * () avant de comparer avec les variables locales.

En résumé, les modifications que j'ai apportées ont été 1) .sll_protocol = htons (ETH_P_ARP). (lors de l'envoi de données) 2) ah-> arp_op = htons (ARPOP_REPLY) (dans l'arp de réponse) 3) Suppression des ntohs absurdes () sur ah-> arp_hd et ah-> arp_pr. Vous ne voulez pas convertir les données en ordre d'octet hôte lors du remplissage du tampon d'envoi (sauf si vous le faites vraiment vraiment) 4) Ajout de conversions ntohs () et définitions appropriées dans certaines des comparaisons 5) quelques autres petites corrections 6) désactivé le système faisant le bit ("Sudo ...")!

Code complet à Pastebin . Voici un 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;

[~ # ~] éditez [~ # ~] Quelques conseils de Wirehark. Capture ether proto 0x0806 (ou arp pour faire court). Utilisez le pseudo périphérique qui capture tous les paquets. Vos paquets devraient devenir visibles.

Sous Linux, si vous voulez empêcher la pile réseau d'interférer, utilisez: echo "8">/proc/sys/net/ipv4/conf/all/arp_ignore

EDIT # 2 Je ne suis pas complètement sûr de l'ETH_P_ARP. Cela aurait pu être un jugement instantané de ma part. L'utilisation de ETH_P_IP est correcte dans le champ d'en-tête ARP, mais je ne sais pas lequel utiliser pour le socket de paquet sll_protocol. Notez également que socket_address.sll_pkttype = PACKET_OTHERHOST;n'a aucun effet lors de l'envoi (voir paquet man 7). Aussi l'observation obligatoire SO, que vous devez toujours utiliser au moins -Wall (lors de l'utilisation de gcc ou clang) comme un indicateur de compilation.

EDIT # 3 J'ai changé un peu plus le programme. et mis à jour la réponse et diff en conséquence. Étonnamment, il semble en effet que .sll_protocol doive être ETH_P_ARP. Ma copie du paquet man 7 ne dit même pas qu'il est utilisé pour quoi que ce soit, mais le paquet ne sort pas sur le fil comme ARP sans lui.

6
thuovila

J'ai pris le code de user6343961, fait un peu de nettoyage et d'épissage et mis en œuvre le support pour obtenir automatiquement l'adresse IP de l'interface. Les paramètres proviennent également de CLI au lieu du codage en dur. bind () est également utilisé pour obtenir uniquement ARP à partir de l'interface que nous voulons. S'amuser. Ce code fonctionne pour moi.

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>  //htons etc

#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60

#define debug(x...) printf(x);printf("\n");
#define info(x...) printf(x);printf("\n");
#define warn(x...) printf(x);printf("\n");
#define err(x...) printf(x);printf("\n");

struct arp_header {
    unsigned short hardware_type;
    unsigned short protocol_type;
    unsigned char hardware_len;
    unsigned char protocol_len;
    unsigned short opcode;
    unsigned char sender_mac[MAC_LENGTH];
    unsigned char sender_ip[IPV4_LENGTH];
    unsigned char target_mac[MAC_LENGTH];
    unsigned char target_ip[IPV4_LENGTH];
};

/*
 * Converts struct sockaddr with an IPv4 address to network byte order uin32_t.
 * Returns 0 on success.
 */
int int_ip4(struct sockaddr *addr, uint32_t *ip)
{
    if (addr->sa_family == AF_INET) {
        struct sockaddr_in *i = (struct sockaddr_in *) addr;
        *ip = i->sin_addr.s_addr;
        return 0;
    } else {
        err("Not AF_INET");
        return 1;
    }
}

/*
 * Formats sockaddr containing IPv4 address as human readable string.
 * Returns 0 on success.
 */
int format_ip4(struct sockaddr *addr, char *out)
{
    if (addr->sa_family == AF_INET) {
        struct sockaddr_in *i = (struct sockaddr_in *) addr;
        const char *ip = inet_ntoa(i->sin_addr);
        if (!ip) {
            return -2;
        } else {
            strcpy(out, ip);
            return 0;
        }
    } else {
        return -1;
    }
}

/*
 * Writes interface IPv4 address as network byte order to ip.
 * Returns 0 on success.
 */
int get_if_ip4(int fd, const char *ifname, uint32_t *ip) {
    int err = -1;
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(struct ifreq));
    if (strlen(ifname) > (IFNAMSIZ - 1)) {
        err("Too long interface name");
        goto out;
    }

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
        perror("SIOCGIFADDR");
        goto out;
    }

    if (int_ip4(&ifr.ifr_addr, ip)) {
        goto out;
    }
    err = 0;
out:
    return err;
}

/*
 * Sends an ARP who-has request to dst_ip
 * on interface ifindex, using source mac src_mac and source ip src_ip.
 */
int send_arp(int fd, int ifindex, const unsigned char *src_mac, uint32_t src_ip, uint32_t dst_ip)
{
    int err = -1;
    unsigned char buffer[BUF_SIZE];
    memset(buffer, 0, sizeof(buffer));

    struct sockaddr_ll socket_address;
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);
    socket_address.sll_ifindex = ifindex;
    socket_address.sll_hatype = htons(ARPHRD_ETHER);
    socket_address.sll_pkttype = (PACKET_BROADCAST);
    socket_address.sll_halen = MAC_LENGTH;
    socket_address.sll_addr[6] = 0x00;
    socket_address.sll_addr[7] = 0x00;

    struct ethhdr *send_req = (struct ethhdr *) buffer;
    struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
    int index;
    ssize_t ret, length = 0;

    //Broadcast
    memset(send_req->h_dest, 0xff, MAC_LENGTH);

    //Target MAC zero
    memset(arp_req->target_mac, 0x00, MAC_LENGTH);

    //Set source mac to our MAC address
    memcpy(send_req->h_source, src_mac, MAC_LENGTH);
    memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
    memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);

    /* Setting protocol of the packet */
    send_req->h_proto = htons(ETH_P_ARP);

    /* Creating ARP request */
    arp_req->hardware_type = htons(HW_TYPE);
    arp_req->protocol_type = htons(ETH_P_IP);
    arp_req->hardware_len = MAC_LENGTH;
    arp_req->protocol_len = IPV4_LENGTH;
    arp_req->opcode = htons(ARP_REQUEST);

    debug("Copy IP address to arp_req");
    memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
    memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));

    ret = sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address));
    if (ret == -1) {
        perror("sendto():");
        goto out;
    }
    err = 0;
out:
    return err;
}

/*
 * Gets interface information by name:
 * IPv4
 * MAC
 * ifindex
 */
int get_if_info(const char *ifname, uint32_t *ip, char *mac, int *ifindex)
{
    debug("get_if_info for %s", ifname);
    int err = -1;
    struct ifreq ifr;
    int sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (sd <= 0) {
        perror("socket()");
        goto out;
    }
    if (strlen(ifname) > (IFNAMSIZ - 1)) {
        printf("Too long interface name, MAX=%i\n", IFNAMSIZ - 1);
        goto out;
    }

    strcpy(ifr.ifr_name, ifname);

    //Get interface index using name
    if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        goto out;
    }
    *ifindex = ifr.ifr_ifindex;
    printf("interface index is %d\n", *ifindex);

    //Get MAC address of the interface
    if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        goto out;
    }

    //Copy mac address to output
    memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);

    if (get_if_ip4(sd, ifname, ip)) {
        goto out;
    }
    debug("get_if_info OK");

    err = 0;
out:
    if (sd > 0) {
        debug("Clean up temporary socket");
        close(sd);
    }
    return err;
}

/*
 * Creates a raw socket that listens for ARP traffic on specific ifindex.
 * Writes out the socket's FD.
 * Return 0 on success.
 */
int bind_arp(int ifindex, int *fd)
{
    debug("bind_arp: ifindex=%i", ifindex);
    int ret = -1;

    // Submit request for a raw socket descriptor.
    *fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (*fd < 1) {
        perror("socket()");
        goto out;
    }

    debug("Binding to ifindex %i", ifindex);
    struct sockaddr_ll sll;
    memset(&sll, 0, sizeof(struct sockaddr_ll));
    sll.sll_family = AF_PACKET;
    sll.sll_ifindex = ifindex;
    if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
        perror("bind");
        goto out;
    }

    ret = 0;
out:
    if (ret && *fd > 0) {
        debug("Cleanup socket");
        close(*fd);
    }
    return ret;
}

/*
 * Reads a single ARP reply from fd.
 * Return 0 on success.
 */
int read_arp(int fd)
{
    debug("read_arp");
    int ret = -1;
    unsigned char buffer[BUF_SIZE];
    ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
    int index;
    if (length == -1) {
        perror("recvfrom()");
        goto out;
    }
    struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
    struct arp_header *arp_resp = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
    if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
        debug("Not an ARP packet");
        goto out;
    }
    if (ntohs(arp_resp->opcode) != ARP_REPLY) {
        debug("Not an ARP reply");
        goto out;
    }
    debug("received ARP len=%ld", length);
    struct in_addr sender_a;
    memset(&sender_a, 0, sizeof(struct in_addr));
    memcpy(&sender_a.s_addr, arp_resp->sender_ip, sizeof(uint32_t));
    debug("Sender IP: %s", inet_ntoa(sender_a));

    debug("Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X",
          arp_resp->sender_mac[0],
          arp_resp->sender_mac[1],
          arp_resp->sender_mac[2],
          arp_resp->sender_mac[3],
          arp_resp->sender_mac[4],
          arp_resp->sender_mac[5]);

    ret = 0;

out:
    return ret;
}

/*
 *
 * Sample code that sends an ARP who-has request on
 * interface <ifname> to IPv4 address <ip>.
 * Returns 0 on success.
 */
int test_arping(const char *ifname, const char *ip) {
    int ret = -1;
    uint32_t dst = inet_addr(ip);
    if (dst == 0 || dst == 0xffffffff) {
        printf("Invalid source IP\n");
        return 1;
    }

    int src;
    int ifindex;
    char mac[MAC_LENGTH];
    if (get_if_info(ifname, &src, mac, &ifindex)) {
        err("get_if_info failed, interface %s not found or no IP set?", ifname);
        goto out;
    }
    int arp_fd;
    if (bind_arp(ifindex, &arp_fd)) {
        err("Failed to bind_arp()");
        goto out;
    }

    if (send_arp(arp_fd, ifindex, mac, src, dst)) {
        err("Failed to send_arp");
        goto out;
    }

    while(1) {
        int r = read_arp(arp_fd);
        if (r == 0) {
            info("Got reply, break out");
            break;
        }
    }

    ret = 0;
out:
    if (arp_fd) {
        close(arp_fd);
        arp_fd = 0;
    }
    return ret;
}

int main(int argc, const char **argv) {
    int ret = -1;
    if (argc != 3) {
        printf("Usage: %s <INTERFACE> <DEST_IP>\n", argv[0]);
        return 1;
    }
    const char *ifname = argv[1];
    const char *ip = argv[2];
    return test_arping(ifname, ip);
}
8
Mikko Korkalo

Je sais que c'est un très vieux poste. Ce code m'a beaucoup aidé. J'ai modifié le code pour envoyer une demande ARP à une adresse IP et extraire l'adresse MAC de la réponse. Veuillez trouver ci-dessous mon 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 PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define PROTOCOL_TYPE 0x800
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60

struct arp_header
{
        unsigned short hardware_type;
        unsigned short protocol_type;
        unsigned char hardware_len;
        unsigned char  protocol_len;
        unsigned short opcode;
        unsigned char sender_mac[MAC_LENGTH];
        unsigned char sender_ip[IPV4_LENGTH];
        unsigned char target_mac[MAC_LENGTH];
        unsigned char target_ip[IPV4_LENGTH];
};

int main()
{
        int sd;
        unsigned char buffer[BUF_SIZE];
        unsigned char source_ip[4] = {10,222,190,160};
        unsigned char target_ip[4] = {10,222,190,139};
        struct ifreq ifr;
        struct ethhdr *send_req = (struct ethhdr *)buffer;
        struct ethhdr *rcv_resp= (struct ethhdr *)buffer;
        struct arp_header *arp_req = (struct arp_header *)(buffer+ETH2_HEADER_LEN);
        struct arp_header *arp_resp = (struct arp_header *)(buffer+ETH2_HEADER_LEN);
        struct sockaddr_ll socket_address;
        int index,ret,length=0,ifindex;

memset(buffer,0x00,60);
        /*open socket*/
        sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if (sd == -1) {
                perror("socket():");
                exit(1);
        }
        strcpy(ifr.ifr_name,"eth1.30");
    /*retrieve ethernet interface index*/
    if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        exit(1);
    }
    ifindex = ifr.ifr_ifindex;
printf("interface index is %d\n",ifindex);

        /*retrieve corresponding MAC*/
        if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
                perror("SIOCGIFINDEX");
                exit(1);
        }
close (sd);

        for (index = 0; index < 6; index++)
        {

                send_req->h_dest[index] = (unsigned char)0xff;
                arp_req->target_mac[index] = (unsigned char)0x00;
                /* Filling the source  mac address in the header*/
                send_req->h_source[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
                arp_req->sender_mac[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
                socket_address.sll_addr[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
        }
        printf("Successfully got eth1 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                        send_req->h_source[0],send_req->h_source[1],send_req->h_source[2],
                        send_req->h_source[3],send_req->h_source[4],send_req->h_source[5]);
        printf(" arp_reqMAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                        arp_req->sender_mac[0],arp_req->sender_mac[1],arp_req->sender_mac[2],
                        arp_req->sender_mac[3],arp_req->sender_mac[4],arp_req->sender_mac[5]);
        printf("socket_address MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
                        socket_address.sll_addr[0],socket_address.sll_addr[1],socket_address.sll_addr[2],
                        socket_address.sll_addr[3],socket_address.sll_addr[4],socket_address.sll_addr[5]);

        /*prepare sockaddr_ll*/
        socket_address.sll_family = AF_PACKET;
        socket_address.sll_protocol = htons(ETH_P_ARP);
        socket_address.sll_ifindex = ifindex;
        socket_address.sll_hatype = htons(ARPHRD_ETHER);
        socket_address.sll_pkttype = (PACKET_BROADCAST);
        socket_address.sll_halen = MAC_LENGTH;
        socket_address.sll_addr[6] = 0x00;
        socket_address.sll_addr[7] = 0x00;

        /* Setting protocol of the packet */
        send_req->h_proto = htons(ETH_P_ARP);

        /* Creating ARP request */
        arp_req->hardware_type = htons(HW_TYPE);
        arp_req->protocol_type = htons(ETH_P_IP);
        arp_req->hardware_len = MAC_LENGTH;
        arp_req->protocol_len =IPV4_LENGTH;
        arp_req->opcode = htons(ARP_REQUEST);
        for(index=0;index<5;index++)
        {
                arp_req->sender_ip[index]=(unsigned char)source_ip[index];
                arp_req->target_ip[index]=(unsigned char)target_ip[index];
        }
  // Submit request for a raw socket descriptor.
  if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
    perror ("socket() failed ");
    exit (EXIT_FAILURE);
  }

buffer[32]=0x00;
        ret = sendto(sd, buffer, 42, 0, (struct  sockaddr*)&socket_address, sizeof(socket_address));
        if (ret == -1)
        {
                perror("sendto():");
                exit(1);
        }
        else
        {
                printf(" Sent the ARP REQ \n\t");
                for(index=0;index<42;index++)
                {
                        printf("%02X ",buffer[index]);
                        if(index % 16 ==0 && index !=0)
                        {printf("\n\t");}
                }
        }
printf("\n\t");
        memset(buffer,0x00,60);
        while(1)
        {
                length = recvfrom(sd, buffer, BUF_SIZE, 0, NULL, NULL);
                if (length == -1)
                {
                        perror("recvfrom():");
                        exit(1);
                }
                if(htons(rcv_resp->h_proto) == PROTO_ARP)
                {
                        //if( arp_resp->opcode == ARP_REPLY )
                        printf(" RECEIVED ARP RESP len=%d \n",length);
                        printf(" Sender IP :");
                        for(index=0;index<4;index++)
                                printf("%u.",(unsigned int)arp_resp->sender_ip[index]);

                        printf("\n Sender MAC :");
                        for(index=0;index<6;index++)
                                printf(" %02X:",arp_resp->sender_mac[index]);

                        printf("\nReceiver  IP :");
                        for(index=0;index<4;index++)
                                printf(" %u.",arp_resp->target_ip[index]);

                        printf("\n Self MAC :");
                        for(index=0;index<6;index++)
                                printf(" %02X:",arp_resp->target_mac[index]);

                        printf("\n  :");

                        break;
                }
        }

        return 0;
}

Merci encore une fois Arun Kumar P

5
user6343961