c - Missing ARP packets in SOCK_RAW socket -


source of example: source.

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <unistd.h> #include <arpa/inet.h> #include <linux/if_ether.h> #include <net/if.h> #include <netpacket/packet.h>  struct ethernet {     unsigned char dest[6];     unsigned char source[6];     uint16_t eth_type; };  struct arp {     uint16_t htype;     uint16_t ptype;     unsigned char hlen;     unsigned char plen;     uint16_t oper;     /* addresses */     unsigned char sender_ha[6];     unsigned char sender_pa[4];     unsigned char target_ha[6];     unsigned char target_pa[4]; };  #define eth_hdr_len 14 #define buff_size 2048  #define arp_proto 0x0806  static void dump_arp(struct arp *arp_hdr);  int main(void) {     int sock, err;     void *buffer = null;     ssize_t recvd_size;     struct sockaddr_ll s_ll;     struct ethernet *eth_hdr = null;     struct arp *arp_hdr = null;      if( (sock = socket(af_packet, sock_raw, htons(eth_p_arp))) == -1)     // if( (sock = socket(af_packet, sock_raw, htons(eth_p_all))) == -1)     {         perror("socket(): ");         exit(-1);     }     s_ll.sll_family = af_packet;     s_ll.sll_protocol = htons(eth_p_arp);      //s_ll.sll_protocol = htons(eth_p_arp);     s_ll.sll_ifindex = 0; // ifaces      //s_ll.sll_ifindex = 2 // eth0     if( (err = bind(sock, (struct sockaddr *)&s_ll, sizeof(s_ll))) == -1)     {         perror("bind(): ");         exit(-1);     }      buffer = malloc(buff_size);     while(1)     {         if( (recvd_size = recv(sock, buffer, buff_size, 0)) == -1)         {             perror("recv(): ");             free(buffer);             close(sock);             exit(-1);         }         if(recvd_size <= (sizeof(struct ethernet) + sizeof(struct arp)))         {             printf("short packet. packet len: %d\n", recvd_size);             continue;         }         eth_hdr = (struct ethernet *)buffer;         if(ntohs(eth_hdr->eth_type) != arp_proto)             continue;         arp_hdr = (struct arp *)(buffer+eth_hdr_len);         dump_arp(arp_hdr);     }     free(buffer);     close(sock); }  static void dump_arp(struct arp *arp_hdr) {     uint16_t htype = ntohs(arp_hdr->htype);     uint16_t ptype = ntohs(arp_hdr->ptype);     uint16_t oper = ntohs(arp_hdr->oper);     switch(htype)     {         case 0x0001:             printf("arp htype: ethernet(0x%04x)\n", htype);             break;         default:             printf("arp hype: 0x%04x\n", htype);             break;     }     switch(ptype)     {         case 0x0800:             printf("arp ptype: ipv4(0x%04x)\n", ptype);             break;         default:             printf("arp ptype: 0x%04x\n", ptype);             break;     }     printf("arp hlen: %d\n", arp_hdr->hlen);     printf("arp plen: %d\n", arp_hdr->plen);     switch(oper)     {         case 0x0001:             printf("arp oper: request(0x%04x)\n", oper);             break;         case 0x0002:             printf("arp oper: response(0x%04x)\n", oper);             break;         default:             printf("arp oper: 0x%04x\n", oper);             break;     }     printf("arp sender ha: %02x:%02x:%02x:%02x:%02x:%02x\n",            arp_hdr->sender_ha[0],arp_hdr->sender_ha[1],arp_hdr->sender_ha[2],            arp_hdr->sender_ha[3], arp_hdr->sender_ha[4], arp_hdr->sender_ha[5]);     printf("arp sender pa: %d.%d.%d.%d\n", arp_hdr->sender_pa[0],            arp_hdr->sender_pa[1], arp_hdr->sender_pa[2], arp_hdr->sender_pa[3]);     printf("arp target ha: %02x:%02x:%02x:%02x:%02x:%02x\n",            arp_hdr->target_ha[0],arp_hdr->target_ha[1],arp_hdr->target_ha[2],            arp_hdr->target_ha[3], arp_hdr->target_ha[4], arp_hdr->target_ha[5]);     printf("arp target pa: %d.%d.%d.%d\n", arp_hdr->target_pa[0],            arp_hdr->target_pa[1], arp_hdr->target_pa[2], arp_hdr->target_pa[3]);     printf("arp done =====================\n"); } 

i create socket() af_packet, sock_raw, eth_p_arp args. , bind() on interfaces(it not matter) args( af_packet, eth_p_arp). so, arp packet's must flow through socket.

my host: 192.168.1.2 remote host: 192.168.1.7, host don't contain arp record of 192.167.1.7.

program output, when make ping 192.168.1.7:

 ... arp oper: response(0x0002) arp sender ha: 50:67:f0:94:70:f5 arp sender pa: 192.168.1.7 arp target ha: 00:22:15:a2:d0:c5 arp target pa: 192.168.1.2 arp done ===================== ... arp oper: request(0x0001) arp sender ha: 50:67:f0:94:70:f5 arp sender pa: 192.168.1.7 arp target ha: 00:00:00:00:00:00 arp target pa: 192.168.1.2 arp done ===================== 

my socket got 2 packet's of 4(my_host request , my_host response missed). tcpdump -n -p -i eth0 arp show 4 packet's.

if change eth_p_arp eth_p_all in socket() , bind() 4 packet's goes socket(with ip , others).

why? how fix that?

ps. please tell me address of mailing list, can ask behavior.

kind of late answer, experimented 1 fun. maybe googler/duckduckgoer can benefit.

my suggestion use eth_p_all receive packets, filter them linux socket filter, application receives requested arp packets.

here code. larges changes marked change comment

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <unistd.h> #include <arpa/inet.h> #include <linux/if_ether.h> #include <net/if.h> #include <netpacket/packet.h> #include <linux/filter.h> // change: include lsf  struct ethernet {     unsigned char dest[6];     unsigned char source[6];     uint16_t eth_type; };  struct arp {     uint16_t htype;     uint16_t ptype;     unsigned char hlen;     unsigned char plen;     uint16_t oper;     /* addresses */     unsigned char sender_ha[6];     unsigned char sender_pa[4];     unsigned char target_ha[6];     unsigned char target_pa[4]; };  #define eth_hdr_len 14 #define buff_size 2048  /* change    linux socket filters use berkeley packet filter syntax.     adapted bsds "man 4 bpf" example rarp. */ struct sock_filter arpfilter[] = {     bpf_stmt(bpf_ld+bpf_h+bpf_abs, 12), /* skip 12 bytes */     bpf_jump(bpf_jmp+bpf_jeq+bpf_k, eth_p_arp, 0, 1), /* if eth type != arp                                                          skip next instr. */     bpf_stmt(bpf_ret+bpf_k, sizeof(struct arp) +                  sizeof(struct ethernet)),     bpf_stmt(bpf_ret+bpf_k, 0), /* return, either arp packet or nil */ };  static void dump_arp(struct arp *arp_hdr);  int main(void) {     int sock;     void *buffer = null;     ssize_t recvd_size;     struct ethernet *eth_hdr = null;     struct arp *arp_hdr = null;     struct sock_filter *filter;     struct sock_fprog  fprog;      if( (sock = socket(af_packet, sock_raw, htons(eth_p_all))) == -1)     {         perror("socket(): ");         exit(-1);     }      /* change prepare linux packet filter */     if ((filter = malloc(sizeof(arpfilter))) == null) {         perror("malloc");         close(sock);         exit(1);     }     memcpy(filter, &arpfilter, sizeof(arpfilter));     fprog.filter = filter;     fprog.len = sizeof(arpfilter)/sizeof(struct sock_filter);      /* change add filter */     if (setsockopt(sock, sol_socket, so_attach_filter, &fprog, sizeof(fprog)) == -1) {         perror("setsockopt");         close(sock);         exit(1);     }      buffer = malloc(buff_size);     while(1)     {         if( (recvd_size = recv(sock, buffer, buff_size, 0)) < 0)         {             perror("recv(): ");             free(buffer);             close(sock);             exit(-1);         }         if((size_t)recvd_size < (sizeof(struct ethernet) + sizeof(struct arp)))         {             printf("short packet. packet len: %ld\n", recvd_size);             continue;         }         eth_hdr = (struct ethernet *)buffer;         if(ntohs(eth_hdr->eth_type) != eth_p_arp) {             printf("received wrong ethernet type: %x\n", eth_hdr->eth_type);             exit(1);         }                   arp_hdr = (struct arp *)(buffer+eth_hdr_len);         dump_arp(arp_hdr);     }     free(buffer);     close(sock); }  static void dump_arp(struct arp *arp_hdr) {     uint16_t htype = ntohs(arp_hdr->htype);     uint16_t ptype = ntohs(arp_hdr->ptype);     uint16_t oper = ntohs(arp_hdr->oper);     switch(htype)     {         case 0x0001:             printf("arp htype: ethernet(0x%04x)\n", htype);             break;         default:             printf("arp hype: 0x%04x\n", htype);             break;     }     switch(ptype)     {         case 0x0800:             printf("arp ptype: ipv4(0x%04x)\n", ptype);             break;         default:             printf("arp ptype: 0x%04x\n", ptype);             break;     }     printf("arp hlen: %d\n", arp_hdr->hlen);     printf("arp plen: %d\n", arp_hdr->plen);     switch(oper)     {         case 0x0001:             printf("arp oper: request(0x%04x)\n", oper);             break;         case 0x0002:             printf("arp oper: response(0x%04x)\n", oper);             break;         default:             printf("arp oper: 0x%04x\n", oper);             break;     }     printf("arp sender ha: %02x:%02x:%02x:%02x:%02x:%02x\n",            arp_hdr->sender_ha[0],arp_hdr->sender_ha[1],arp_hdr->sender_ha[2],            arp_hdr->sender_ha[3], arp_hdr->sender_ha[4], arp_hdr->sender_ha[5]);     printf("arp sender pa: %d.%d.%d.%d\n", arp_hdr->sender_pa[0],            arp_hdr->sender_pa[1], arp_hdr->sender_pa[2], arp_hdr->sender_pa[3]);     printf("arp target ha: %02x:%02x:%02x:%02x:%02x:%02x\n",            arp_hdr->target_ha[0],arp_hdr->target_ha[1],arp_hdr->target_ha[2],            arp_hdr->target_ha[3], arp_hdr->target_ha[4], arp_hdr->target_ha[5]);     printf("arp target pa: %d.%d.%d.%d\n", arp_hdr->target_pa[0],            arp_hdr->target_pa[1], arp_hdr->target_pa[2], arp_hdr->target_pa[3]);     printf("arp done =====================\n"); } 

i removed bind() unnecessary , corrected off 1 in comparison of captured packet size. comparison <= sizeof(struct ethernet) + sizeof(struct arp)when should <

short of reading packet socket kernel source, im not now, did not find explanation why example code receives packets addressed hosts ip. op , many examples around internet confirm, when level eth_p_all, outgoing packets received socket. guess implementation choise. might preferrable behaviour applications, e.g. implementing protocol, instead of snooping on existing one.

note speaking of kernel source, not @ sure why lsf/bpf filter works when give 2 byte eth_p_arp without byteorder modifications. think might because of these lines in kernel:

case bpf_s_anc_protocol: = ntohs(skb->protocol); 

from http://lxr.linux.no/#linux+v3.11/net/core/filter.c#l317


Comments

Popular posts from this blog

jquery - How can I dynamically add a browser tab? -

node.js - Getting the socket id,user id pair of a logged in user(s) -

keyboard - C++ GetAsyncKeyState alternative -