简体   繁体   中英

Why arp reply is not sending?

I have this code from this page: http://usuaris.tinet.cat/sag/send_arp.htm

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

// replace following by
// #include 
// for windows migrating start ...

#include <netdb.h>
#include <sys/socket.h>
// --- not required by RH --- #include <linux/in.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>

// http://en.wikipedia.org/wiki/Address_Resolution_Protocol
//   hlen          - Ethernet addresses size is 6.
//   plen          - IPv4 address size is 4.
//   frtype        - 0x0806 = ARP - http://en.wikipedia.org/wiki/EtherType
//   htype         - Ethernet is 1.
//   Protocol type - for IPv4, this has the value 0x0800
//   Operation     - specifies the operation that the sender is performing: 1 for request, 2 for reply.

#define ETH_HW_ADDR_LEN 6
#define IP_ADDR_LEN     4
#define ARP_FRAME_TYPE  0x0806
#define ETHER_HW_TYPE   1
#define IP_PROTO_TYPE   0x0800
#define OP_ARP_REQUEST  2

#define DEFAULT_DEVICE "wlan0"

char usage[]={"send_arp: sends out custom ARP packet. yuri volobuev'97\n\
\tusage: send_arp src_ip_addr src_hw_addr targ_ip_addr tar_hw_addr\n\n"};

struct arp_packet {
  u_char  targ_hw_addr[ETH_HW_ADDR_LEN];
  u_char  src_hw_addr[ETH_HW_ADDR_LEN];
  u_short frame_type;
  u_short hw_type;
  u_short prot_type;
  u_char  hw_addr_size;
  u_char  prot_addr_size;
  u_short op;
  u_char  sndr_hw_addr[ETH_HW_ADDR_LEN];
  u_char  sndr_ip_addr[IP_ADDR_LEN];
  u_char  rcpt_hw_addr[ETH_HW_ADDR_LEN];
  u_char  rcpt_ip_addr[IP_ADDR_LEN];
  u_char  padding[18];
};

void die(char *);
void get_ip_addr(struct in_addr*,char*);
void get_hw_addr(char*,char*);

int main ( int argc, char** argv ) {

  struct in_addr src_in_addr, targ_in_addr;
  struct arp_packet pkt;
  struct sockaddr sa;
  int sock;

  if ( argc != 5 ) die(usage) ;

  sock = socket( AF_INET, SOCK_PACKET, htons(ETH_P_RARP) ) ;
  if ( sock < 0 ){
    perror("socket");
    exit(1);
  }

  pkt.frame_type     = htons(ARP_FRAME_TYPE);
  pkt.hw_type        = htons(ETHER_HW_TYPE);
  pkt.prot_type      = htons(IP_PROTO_TYPE);
  pkt.hw_addr_size   = ETH_HW_ADDR_LEN;
  pkt.prot_addr_size = IP_ADDR_LEN;
  pkt.op             = htons(OP_ARP_REQUEST);

  get_hw_addr( pkt.targ_hw_addr, argv[4] );
  get_hw_addr( pkt.rcpt_hw_addr, argv[4] );
  get_hw_addr( pkt.src_hw_addr,  argv[2] );
  get_hw_addr( pkt.sndr_hw_addr, argv[2] );

  get_ip_addr( &src_in_addr,  argv[1] );
  get_ip_addr( &targ_in_addr, argv[3] );

  memcpy( pkt.sndr_ip_addr, &src_in_addr,  IP_ADDR_LEN );
  memcpy( pkt.rcpt_ip_addr, &targ_in_addr, IP_ADDR_LEN );

  bzero( pkt.padding, 18 );

  strcpy( sa.sa_data, DEFAULT_DEVICE ) ;
  if ( sendto( sock, &pkt,sizeof(pkt), 0, &sa,sizeof(sa) ) < 0 ){
    perror("sendto");
    exit(1);
  }
  exit(0);

} ; // main

// main code end


void die(char* str){
  fprintf(stderr,"%s\n",str);
  exit(1);
} ; // die

void get_ip_addr( struct in_addr* in_addr, char* str ){

  struct hostent *hostp;

  in_addr->s_addr = inet_addr(str);
  if ( in_addr->s_addr == -1 ){
    if( (hostp = gethostbyname(str)))
      bcopy( hostp->h_addr, in_addr, hostp->h_length ) ;
    else {
      fprintf( stderr, "send_arp: unknown host [%s].\n", str ) ;
      exit(1);
    }
  }
} ; // get_ip_addr

void get_hw_addr( char* buf, char* str ){

  int i;
  char c,val;

  for ( i=0 ; i < ETH_HW_ADDR_LEN ; i++ ){
    if( !(c = tolower(*str++))) die("Invalid hardware address");
    if(isdigit(c)) val = c-'0';
    else if(c >= 'a' && c <= 'f') val = c-'a'+10;
    else die("Invalid hardware address");

    *buf = val << 4;
    if( !(c = tolower(*str++))) die("Invalid hardware address");
    if(isdigit(c)) val = c-'0';
    else if(c >= 'a' && c <= 'f') val = c-'a'+10;
    else die("Invalid hardware address");

    *buf++ |= val;

    if (*str == ':') str++ ;
  } ; // for loop
} ; // get_hw_addr

And it's working. However it's only working when source mac address is correct. For example: My mac is: 01:23:45:67:89:AB

./send_arp 192.168.1.1 01:23:45:67:89:AB 192.168.1.2 FF:FF:FF:FF:FF:FF

And this packet comes to target device but when i change source mac it doesn't.

I'm using tcpdump to check it and i don't see any arp packet on source device and on destination device.

Is there any restriction in kernel to send another source mac?

How can I fix it?

There is no restriction so long as:

  • Your OS supports it (works on Linux, can't vouch 100% for Windows but it can certainly be made to work as it works for Hyper-V bridging - there may be some tweak you need to do) - credit to @caffeinatedmonkey
  • The switch supports it

I mention this second point because many switches in a corporate environment are set up to filter out what they see as bogus MAC replies, mandate single MAC per port etc., for security and to prevent L2 loops.

If you want working source code, look for the source for arping or garpd and watch how it does gratuitous / unsolicited arp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM