您的位置:首页 > 运维架构 > Linux

linux原始套接字-发送ICMP报文

2016-10-11 19:13 411 查看
本程序可以使得一个不存在的ip被ping通,演示了如何通过PF_PACKET SOCK_RAW来接收和发送arp和icmp帧。

1、开启网卡混杂模式。

2、接收 arp request。

3、伪造 arp reply,响应请求者。

4、接收 icmp echo request。

5、伪造 icmp echo reply,响应请求者。

本程序在ubuntu 14.04下编译调试通过。

编译命令:gcc -m32 -g -Wall xping.c

启动参数:./a.out eth1 192.168.2.70

随便找一台电脑 ping 192.168.2.70

稍加改造就可以让一个局域网内的所有的ip都被ping通,因此本示例仅供学习参考。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netpacket/packet.h>
#include <arpa/inet.h>

#ifndef arp_hrd /*android not define struct ether_arp*/
struct ether_arp {
struct arphdr ea_hdr; /* fixed-size header */
u_int8_t arp_sha[ETH_ALEN]; /* sender hardware address */
u_int8_t arp_spa[4]; /* sender protocol address */
u_int8_t arp_tha[ETH_ALEN]; /* target hardware address */
u_int8_t arp_tpa[4]; /* target protocol address */
};
#define arp_hrd ea_hdr.ar_hrd
#define arp_pro ea_hdr.ar_pro
#define arp_hln ea_hdr.ar_hln
#define arp_pln ea_hdr.ar_pln
#define arp_op ea_hdr.ar_op
#endif

#define xprint_log(fmt, ...) \
printf("[%04d]%s() " fmt, __LINE__, __FUNCTION__, ####__VA_ARGS__)
#define xprint_err(fmt, ...) \
printf("[%04d]%s() err: " fmt, __LINE__, __FUNCTION__, ####__VA_ARGS__)

#define xdebug 0
#define xunused __attribute__((unused))

#define HDR_LEN_ETH sizeof(struct ether_header)
#define HDR_LEN_ARP sizeof(struct ether_arp)
#define HDR_LEN_IP sizeof(struct ip)
#define HDR_LEN_ICMP sizeof(struct icmp)

static unsigned char s_frame_data[ETH_FRAME_LEN];
static unsigned int s_frame_size = 0;
static int s_interface_index = -1;
static unsigned char s_interface_mac[ETH_ALEN];
static struct in_addr s_interface_ip;
static unsigned char s_src_mac[ETH_ALEN] = {0x00,0x11,0x22,0x33,0x44,0x55};

static int
xsend_frame_ether(uint8_t *frame, int size, int ifindex, int skfd);
static int
xrecv_frame_ether(uint8_t *frame, int size, int ifindex, int skfd);

static int
xsend_reply_arp(in_addr_t ipaddr, int skfd);
static int
xsend_reply_icmp(in_addr_t ipaddr, int skfd);

static uint16_t
xutil_check_sum(uint16_t* data, int size);
static void
xutil_swap_int(uint32_t *a, uint32_t *b);

static int xunused
xdump_frame_byte(uint8_t *data, int size);
static int xunused
xdump_frame_ether(struct ether_header *eth);
static int xunused
xdump_frame_arp (struct ether_arp *arp);
static int xunused
xdump_frame_ip (struct ip *iph);
static int xunused
xdump_frame_icmp (struct icmp *icmph);

#define __DEFINITION__

static uint16_t
xutil_check_sum(uint16_t* data, int size)
{
unsigned int cksm = 0;

while (size > 1) {
cksm += *data++;
size -= sizeof(uint16_t);
}

if (size) {
cksm += *(uint8_t*)data;
}

cksm = (cksm>>16) + (cksm&0xffff);
cksm += (cksm>>16);

return (uint16_t)(~cksm);
}

static void
xutil_swap_int(uint32_t *a, uint32_t *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
return ;
}

static int
xdump_frame_byte(uint8_t *data, int size)
{
int i;

for(i=0; i<size; i++) {
if((i%16) == 0) {
printf( "[%02x] ", i/16 );
}
printf( "%02x ", data[i] );
if(((i+1)%16) == 0) {
printf( "\n" );
}
}

printf( "\n" );
return 0;
}

static int
xdump_frame_ether(struct ether_header *eth)
{
if (NULL == eth) {
return -1;
}

printf("========frame ether========\n");
printf("type :0x%04x\n", htons(eth->ether_type));
printf("d-mac:%02x-%02x-%02x-%02x-%02x-%02x\n",\
eth->ether_dhost[0], eth->ether_dhost[1], eth->ether_dhost[2], \
eth->ether_dhost[3], eth->ether_dhost[4], eth->ether_dhost[5]);

printf("s-mac:%02x-%02x-%02x-%02x-%02x-%02x\n",\
eth->ether_shost[0], eth->ether_shost[1], eth->ether_shost[2], \
eth->ether_shost[3], eth->ether_shost[4], eth->ether_shost[5]);
return 0;
}

static int
xdump_frame_arp (struct ether_arp *arp)
{
if (NULL == arp) {
return -1;
}

printf("========frame arp ========\n");
printf("arp_hrd=%d \n", htons(arp->arp_hrd));
printf("arp_pro=0x%04x\n", htons(arp->arp_pro));
printf("arp_op =%d \n", htons(arp->arp_op));
printf("arp_sdr=%02x-%02x-%02x-%02x-%02x-%02x %d.%d.%d.%d\n", \
arp->arp_sha[0], arp->arp_sha[1], arp->arp_sha[2], \
arp->arp_sha[3], arp->arp_sha[4], arp->arp_sha[5], \
arp->arp_spa[0], arp->arp_spa[1], arp->arp_spa[2], \
arp->arp_spa[3]);
printf("arp_tgr=%02x-%02x-%02x-%02x-%02x-%02x %d.%d.%d.%d\n", \
arp->arp_tha[0], arp->arp_tha[1], arp->arp_tha[2], \
arp->arp_tha[3], arp->arp_tha[4], arp->arp_tha[5], \
arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], \
arp->arp_tpa[3]);
return 0;
}

static int
xdump_frame_ip(struct ip *iph)
{
if (NULL == iph) {
return -1;
}

printf("========frame ip ========\n");
printf("ip_v =0x%x\n", iph->ip_v ); /* 4位版本号 */
printf("ip_hl =0x%x\n", iph->ip_hl ); /* 4位IP头部长度 32bit */
printf("ip_tos=0x%x\n", iph->ip_tos ); /* 8位服务类型 */
printf("ip_len=0x%x\n", htons(iph->ip_len) ); /*16位数据包总长度 */
printf("ip_id =0x%x\n", htons(iph->ip_id) ); /*16位标志符 */
printf("ip_off=0x%x\n", htons(iph->ip_off) ); /* 3位标记+13位片偏移 */
printf("ip_ttl=0x%x\n", iph->ip_ttl ); /* 8位生存时间 */
printf("ip_p =0x%x\n", iph->ip_p ); /* 8位协议号 */
printf("ip_sum=0x%x\n", htons(iph->ip_sum) ); /*16位首部校验和 */
printf("ip_src=%s \n", inet_ntoa(iph->ip_src)); /*32位源地址 */
printf("ip_dst=%s \n", inet_ntoa(iph->ip_dst)); /*32位目的地址 */
return 0;
}

static int
xdump_frame_icmp (struct icmp *icmph)
{
if (NULL == icmph) {
return -1;
}

printf("========frame icmp ========\n");
printf("icmp_type =0x%x\n", icmph->icmp_type ); /* 8位类型 */
printf("icmp_code =0x%x\n", icmph->icmp_code ); /* 8位代码 */
printf("icmp_cksum=0x%x\n", icmph->icmp_cksum); /* 16位校验和 */
printf("icmp_id =0x%x\n", icmph->icmp_id ); /* 16位识别号 进程id */
printf("icmp_seq =0x%x\n", icmph->icmp_seq ); /* 16位序列号 */
return 0;
}

static int
xsend_frame_ether(uint8_t *frame, int size, int ifindex, int skfd)
{
struct sockaddr_ll sll;
socklen_t sln = 0;

struct sockaddr_ll *psll = NULL;

if (-1 != ifindex) {
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ifindex;
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(ETH_P_ALL);

psll = &sll;
sln = sizeof(struct sockaddr_ll);
}

size = sendto(skfd, frame, size, 0, (struct sockaddr*)psll, sln);
if (size < 0) {
xprint_err("ioctl() SIOCGIFINDEX failed! errno=%d (%s)\n", \
errno, strerror(errno));
}

return size;
}

static int
xrecv_frame_ether(uint8_t *frame, int size, int ifindex, int skfd)
{
struct sockaddr_ll sll;
socklen_t sln = sizeof(struct sockaddr_ll);

struct sockaddr_ll *psll = NULL;
socklen_t *psln = NULL;

if (NULL==frame || size<=0) {
xprint_err("param failed! frame=%p size=%d\n", frame, size);
return -1;
}

if (-1 != ifindex) {
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ifindex;
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(ETH_P_ALL);

psll = &sll;
psln = &sln;
}

memset(frame, 0, size*sizeof(uint8_t));
size = recvfrom(skfd, frame, size, 0, (struct sockaddr*)psll, psln);

if (size < 0) {
xprint_err("recvfrom() failed! errno=%d (%s)\n", \
errno, strerror(errno));
}
return size;
}

static int
xsend_reply_arp(in_addr_t ipaddr, int skfd)
{
struct ether_header *eth = NULL;
struct ether_arp *arp = NULL;

eth = (struct ether_header*)s_frame_data;
arp = (struct ether_arp*)(s_frame_data + HDR_LEN_ETH);

if (*(unsigned int*)arp->arp_tpa != ipaddr) {
return -1;
}

/*ether*/
memcpy(eth->ether_dhost, eth->ether_shost, ETH_ALEN);
memcpy(eth->ether_shost, s_src_mac , ETH_ALEN);

/*arp*/
arp->arp_op = htons(ARPOP_REPLY);
memcpy(arp->arp_tha, arp->arp_sha, ETH_ALEN);
memcpy(arp->arp_tpa, arp->arp_spa, 4);

memcpy(arp->arp_sha, s_src_mac, ETH_ALEN);
memcpy(arp->arp_spa, &ipaddr, 4);

#if xdebug
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("========frame size:%d\n", s_frame_size);
xdump_frame_ether(eth);
xdump_frame_arp (arp);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("\n");
#endif

if (s_frame_size != xsend_frame_ether(\
s_frame_data, s_frame_size, s_interface_index, skfd)) {
return -1;
}

xprint_log("ok. size=%d\n", s_frame_size);
return 0;
}

static int
xsend_reply_icmp(in_addr_t ipaddr, int skfd)
{
struct ip *iph = NULL;
struct ether_header *eth = NULL;
struct icmp *icmph = NULL;

eth = (struct ether_header*)s_frame_data;
iph = (struct ip*)(s_frame_data + HDR_LEN_ETH);
icmph = (struct icmp*)(s_frame_data + HDR_LEN_ETH + HDR_LEN_IP);

if ((iph->ip_p!=IPPROTO_ICMP) || iph->ip_dst.s_addr!=ipaddr) {
return 1;
}

/*ether*/
memcpy(eth->ether_dhost, eth->ether_shost, ETH_ALEN);
memcpy(eth->ether_shost, s_src_mac, ETH_ALEN);

/*ip*/
xutil_swap_int(&(iph->ip_src.s_addr), &(iph->ip_dst.s_addr));
iph->ip_off = 0;
iph->ip_sum = 0;
iph->ip_sum = xutil_check_sum((uint16_t*)iph, HDR_LEN_IP);

/*icmp*/
icmph->icmp_type = ICMP_ECHOREPLY;
icmph->icmp_cksum = 0;
icmph->icmp_cksum = \
xutil_check_sum((uint16_t*)icmph, s_frame_size-HDR_LEN_ETH-HDR_LEN_IP);

#if xdebug
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("========frame size:%d\n", s_frame_size);
xdump_frame_ether(eth );
xdump_frame_ip (iph );
xdump_frame_icmp (icmph);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("\n");
#endif

if (s_frame_size != xsend_frame_ether( \
s_frame_data, s_frame_size, s_interface_index, skfd)) {
return -1;
}

xprint_log("ok. size=%d\n", s_frame_size);
return 0;
}

int main(int argc, char **argv)
{
int skfd = -1;
in_addr_t xping_addr = 0;

if (argc <= 2) {
printf("usage: %s interface ipaddr\n",argv[0]);
printf(" ex: %s eth0 192.168.88.1\n", argv[0]);
return -1;
}

skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (skfd < 0) {
xprint_err("socket() failed! errno=%d (%s)\n", errno, strerror(errno));
return -1;
}

struct ifreq ifr;
bzero(&ifr,sizeof(ifr));
strcpy(ifr.ifr_name, argv[1]);
if (-1 == ioctl(skfd, SIOCGIFINDEX, &ifr)) {
xprint_err("ioctl() SIOCGIFINDEX failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}
s_interface_index = ifr.ifr_ifindex;

if (-1 == ioctl(skfd, SIOCGIFHWADDR, &ifr)) {
xprint_err("ioctl() SIOCGIFHWADDR failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}
memcpy(s_interface_mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);

if (-1 == ioctl(skfd, SIOCGIFADDR, &ifr)) {
xprint_err("ioctl() SIOCGIFADDR failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}
s_interface_ip.s_addr = \
((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr;

if (-1 == ioctl(skfd, SIOCGIFFLAGS, &ifr)) {
xprint_err("ioctl() IFF_PROMISC failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}

if ((ifr.ifr_flags&IFF_PROMISC) != IFF_PROMISC) {
ifr.ifr_flags |= IFF_PROMISC;
if(-1 == ioctl(skfd, SIOCSIFFLAGS, &ifr)) {
xprint_err("ioctl() IFF_PROMISC failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}
}

printf("========host info ========\n");
printf("ifr_ifindex=%d %s\n", s_interface_index, argv[1]);
printf("ifr_hwaddr =%02x-%02x-%02x-%02x-%02x-%02x\n", \
s_interface_mac[0], s_interface_mac[1], s_interface_mac[2],
s_interface_mac[3], s_interface_mac[4], s_interface_mac[5]);
printf("ifr_addr =%s\n", inet_ntoa(s_interface_ip));
printf("ifr_flags =IFF_PROMISC\n");
printf("pid =0x%x\n", getpid());
printf("header_eth =%d\n", HDR_LEN_ETH);
printf("header_arp =%d\n", HDR_LEN_ARP);
printf("header_ip =%d\n", HDR_LEN_IP);
printf("header_icmp=%d\n", HDR_LEN_ICMP);
printf("\n");

printf("press any key continue!\n");
getchar();
printf("waiting for someone ping %s ...\n", argv[2]);

#if 0
int on = 1;
if (0 != setsockopt(skfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) {
xprint_err("setsockopt() IP_HDRINCL failed! errno=%d (%s)\n", \
errno, strerror(errno));
return -1;
}
#endif

xping_addr = inet_addr(argv[2]);

while(1) {
uint16_t ether_type = 0;
struct ether_header* eth = NULL;

memset(s_frame_data, 0x00, sizeof(unsigned char)*ETH_FRAME_LEN);
s_frame_size = xrecv_frame_ether(s_frame_data, ETH_FRAME_LEN, \
s_interface_index, skfd);

eth = (struct ether_header*)s_frame_data;
ether_type = htons(eth->ether_type);

switch(ether_type) {
case ETHERTYPE_ARP: {
xsend_reply_arp(xping_addr, skfd);
break;
}
case ETHERTYPE_IP: {
xsend_reply_icmp(xping_addr, skfd);
break;
}
default: {
break;
}
}
}

close(skfd);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ping socket raw arp icmp