2013-05-23 14 views
13

Staram się odbierać i wysyłać pakiety ARP za pomocą programowania C w Linux (Ubuntu)
Mój program działa poprawnie (tj przebiega bez błędów), ale nie mogę śledzić pakiety używając Wireshark.żądanie ARP i odpowiadanie za pomocą c gniazdo programowania

kod źródłowy:

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

Najlepsza forma [ASK @ Wireshark] (http://ask.wireshark.org/questions/), robi to pokazuje pakiety dla innych aplikacji na komputerze ** ** –

+0

Tak, można zobaczyć pakiety inne aplikacje. – dsharew

+0

Problem musi pochodzić z kodu, ale kompilator nie może go wykryć. – dsharew

Odpowiedz

5

Kilka rzeczy, aby uzyskać pakiety na drucie/powietrze.

  • Prawidłowe .sll_protocol za odpowiedź ARP jest ETH_P_ARP z <linux/if_ether.h>
  • Było przy ustalaniu Ah> arp_op błąd w endianness. Jest to pole bajtów sieci 2 oktety, więc użyj htons().

  • Ogólnie rzecz biorąc, kod jest trochę mylony co do sieci i hosta. Obecnie wysyła bardzo zmasowaną odpowiedź, ale nie jest dla mnie jasne, czy jest to złośliwa intencja kodu, czy wypadek. W przypadku, gdy chcesz wysłać prawdziwe, poprawne adresy IP, użyj htonl i htons podczas budowania odpowiedzi.

Aby rozwiązać endianness:

  • Właściwie to <arpa/inet.h>
  • Używaj htons(),() ntohs htonl() i ntohl(), zawsze. Ich implementacja czyni NOP, jeśli nie jest potrzebny na twojej platformie.
  • Podczas konfigurowania danych do wysłania z hosta, zawsze przetwarzaj go htonem *()
  • Podczas interpretowania danych z sieci, zawsze ntoh *() przed porównaniem ze zmiennymi lokalnymi.

Podsumowując, zmiany, które wprowadziłem, to 1) .sll_protocol = htons (ETH_P_ARP). (przy wysyłaniu danych) 2) ah-> arp_op = htons (ARPOP_REPLY) (w odpowiedzi arp) 3) Usunięto bezsensowne ntohs() na ah-> arp_hd i ah-> arp_pr. Nie chcesz konwertować danych do bajtu hosta podczas zapełniania bufora wysyłania (chyba, że ​​tak naprawdę to robisz) 4) Dodano konwersje ntohs() i poprawne definicje w niektórych porównaniach 5) niektóre inne małe poprawki 6) wyłączyły system bitowy ("sudo ...")!

Pełny kod na pastebin. Tu jest diff:

[email protected]:~/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 Kilka rad Wireshark. Przechwyć ether proto 0x0806 (lub arp w skrócie). Użyj pseudo urządzenia, które przechwytuje jakiekolwiek pakiety. Twoje pakiety powinny stać się widoczne.

na Linuksie, jeśli chcesz zatrzymać stos sieciowy od ingerencji, użycie: echo "8">/proc/sys/net/ipv4/conf/all/arp_ignore

EDIT # 2 jestem nie jestem całkowicie pewien ETH_P_ARP. To mógł być krótki osąd z mojej strony. Użycie ETH_P_IP jest poprawne w polu nagłówka ARP, ale nie jestem pewien, którego użyć do gniazda pakietów sll_protocol.Zauważ również, że socket_address.sll_pkttype = PACKET_OTHERHOST; nie ma żadnego wpływu na wysyłanie (patrz pakiet 7 man). Również obowiązkowa obserwacja SO, że powinieneś zawsze używać co najmniej -Wall (gdy używasz gcc lub clang) jako flagi kompilacji.

EDYCJA # 3 Zmieniłem nieco program. i zaktualizował odpowiedź i odpowiednio się do niej dostosował. Zaskakująco wygląda na to, że .sll_protocol musi być ETH_P_ARP. Moja kopia pakietu 7 nie mówi, że jest używana do czegokolwiek, ale pakiet nie wychodzi z niego jako ARP bez niego.

+0

Użyłem twojego kodu, ale problem wciąż nie został rozwiązany. – dsharew

+0

Czy to wciąż ten sam problem? Wydawało się, że działa to dla mnie. Widziałem pakiety wychodzące i wireshark zgłosił wykrycie kolizji ARP/duplikatu MAC. Również gospodarze wysyłający żądanie ARP zdawali się akceptować odpowiedź od siebie. – thuovila

4

Wiem, że to bardzo stary post. Ten kod bardzo mi pomógł. Zmodyfikowałem kod, aby wysłać żądanie ARP do adresu IP i wyodrębnić adres MAC z odpowiedzi. Proszę znaleźć poniżej mojego kodu

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

Bardzo dziękuję jeszcze raz Arun Kumar P

+0

Dzięki za kod, użyłem go jako bazy dla mojego dobrego kodu –

6

wziąłem kod user6343961 za, czy jakieś czyszczenie i forniru i realizowane wsparcie dla automatycznego uzyskania adresu IP interfejsu. Również parametry pochodzą z CLI zamiast z twardego kodu. Funkcja bind() służy również do pobierania ARP z interfejsu, który chcemy. Baw się dobrze. Ten kod działa dla mnie.

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

+1. Ale użyj instrukcji if-else zamiast + if. To po prostu brudne, jak jedzenie bez uprzedniego mycia rąk. Usuń również wszystkie nieużywane zmienne. – zoran404

+0

Muszę się nie zgodzić na temat goto, IHMO, które jest najczystszym sposobem na obsługę błędów i zwalnianie pamięci. Widziałem alternatywne rozwiązania i nic nie jest bliskie. To jest jedyny sposób, w jaki sposób goto powinien być kiedykolwiek użyty, tzn. Aby przejść do końca, w którym robisz pewne zwalnianie przed zwróceniem wartości. Oto przykładowa dyskusja na ten temat: http://stackoverflow.com/questions/570317/what-is-the-best-way-to-free-memory-after-returning-from-an-error –

+0

Nie widzisz tego całkiem dosłownie napisałeś blok "if-else"? Jedyna różnica polega na tym, że użyłeś słowa kluczowego 'goto' zamiast słowa kluczowego' else'. – zoran404

Powiązane problemy