我从这个页面有这个代码: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
它正在发挥作用 . 但是它只在源MAC地址正确时才有效 . 例如:我的mac是: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
这个数据包来到目标设备,但是当我更改源mac时它没有 .
我正在使用tcpdump来检查它,我在源设备和目标设备上看不到任何arp数据包 .
内核是否有限制发送另一个源mac?
我该如何解决?
1 回答
只要有以下内容就没有限制:
你的操作系统支持它(适用于Linux,不能100%用于Windows,但它当然可以工作,因为它适用于Hyper-V桥接 - 你可能需要做一些调整) - 归功于@caffeinatedmonkey
交换机支持它
我提到了第二点,因为公司环境中的许多交换机被设置为过滤掉他们所看到的伪造的MAC回复,为每个端口等要求单个MAC,以确保安全并防止L2环路 .
如果您想要工作源代码,请查找arping或garpd的来源,并观察它如何做无偿/未经请求的arp .