#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/types.h>
#include <asm/types.h>
#include <features.h> /* 需要里面的 glibc 版本号 */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif
#include <netinet/if_ether.h>
#define INLEN 4
#define MAC_BCAST_ADDR (uint8_t *) "xffxffxffxffxffxff"
void
usage_quit(
char
*arg0);
int
get_ifi(
char
*dev,
char
*mac,
int
macln,
struct
in_addr *lc_addr,
int
ipln);
void
prmac(u_char *ptr);
int
main(
int
argc,
char
**argv)
{
if
(argc != 2)
usage_quit(argv[0]);
int
fd, salen, n;
u_char *mac;
char
recv_buf[120], rep_addr[16];
struct
in_addr lc_addr, req_addr;
struct
sockaddr_ll reqsa, repsa;
struct
arp_pkt {
struct
ether_header eh;
struct
ether_arp ea;
u_char padding[18];
} req;
bzero(&reqsa,
sizeof
(reqsa));
reqsa.sll_family = PF_PACKET;
reqsa.sll_ifindex = if_nametoindex(
"eth0"
);
if
((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) < 0) {
perror
(
"Socket error"
);
exit
(1);
}
mac = (
char
*)
malloc
(ETH_ALEN);
bzero(&req,
sizeof
(req));
if
(get_ifi(
"eth0"
, mac, ETH_ALEN, &lc_addr, INLEN)) {
fprintf
(stderr,
"Error: Get host’s information failed
"
);
exit
(0);
}
printf
(
" Host MAC is: %02x:%02x:%02x:%02x:%02x:%02x
"
,*mac,*(mac+1),*(mac+2),*(mac+3),*(mac+4),*(mac+5));
printf
(
" Host IP is: %s
"
, inet_ntop(AF_INET, &lc_addr, rep_addr, 1024));
memcpy
(req.eh.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy
(req.eh.ether_shost, mac, ETH_ALEN);
req.eh.ether_type = htons(ETHERTYPE_ARP);
req.ea.arp_hrd = htons(ARPHRD_ETHER);
req.ea.arp_pro = htons(ETHERTYPE_IP);
req.ea.arp_hln = ETH_ALEN;
req.ea.arp_pln = INLEN;
req.ea.arp_op = htons(ARPOP_REQUEST);
memcpy
(req.ea.arp_sha, mac, ETH_ALEN);
memcpy
(req.ea.arp_spa, &lc_addr, INLEN);
inet_aton(argv[1], req.ea.arp_tpa);
bzero(recv_buf,
sizeof
(recv_buf));
bzero(&repsa,
sizeof
(repsa));
salen =
sizeof
(
struct
sockaddr_ll);
if
((n = sendto(fd, &req,
sizeof
(req), 0, (
struct
sockaddr *)&reqsa,
sizeof
(reqsa))) <= 0) {
perror
(
"Sendto error"
);
exit
(1);
}
printf
(
"Broadcast arp request of %s, %d bytes be sent
"
, argv[1], n);
while
(1) {
if
((n = recvfrom(fd, recv_buf,
sizeof
(req), 0, (
struct
sockaddr *)&repsa, &salen)) <= 0) {
perror
(
"Recvfrom error"
);
exit
(1);
}
if
(ntohs(*(__be16 *)(recv_buf + 20))==2 && !
memcmp
(req.ea.arp_tpa, recv_buf + 28, 4)) {
printf
(
"Response from %s, %d bytes received
"
, argv[1], n);
printf
(
" Peer IP is: %s
"
, inet_ntop(AF_INET, (
struct
in_addr *)(recv_buf + 28), rep_addr, 1024));
prmac( (u_char *)(recv_buf + 22) );
break
;
}
else
{
printf
(
"Have recive data
"
);
break
;
}
}
free
(mac);
}
int
get_ifi(
char
*dev,
char
* mac,
int
macln,
struct
in_addr *lc_addr,
int
ipln)
{
int
reqfd, n;
struct
ifreq macreq;
reqfd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy
(macreq.ifr_name, dev);
if
(ioctl(reqfd, SIOCGIFHWADDR, ¯eq) != 0)
return
1;
memcpy
(mac, macreq.ifr_hwaddr.sa_data, macln);
if
(ioctl(reqfd, SIOCGIFADDR, ¯eq) != 0)
return
1;
memcpy
(lc_addr, &((
struct
sockaddr_in *)(¯eq.ifr_addr))->sin_addr, ipln);
return
0;
}
void
prmac(u_char *ptr)
{
printf
(
" Peer MAC is: %02x:%02x:%02x:%02x:%02x:%02x
"
,*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
}
void
usage_quit(
char
*arg0)
{
fprintf
(stderr,
"Usage: %s <query_IP>
"
, arg0);
exit
(1);
}