原始套接字--icmp相关

icmp请求

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <sys/time.h>

/* icmp报文长度 */
#define ICMP_PACKET_LEN sizeof(struct icmp)

void err_exit(const char *err_msg)
{
    perror(err_msg);
    exit(1);
}

/* 校验和 */
unsigned short check_sum(unsigned short *addr, int len)
{
    int nleft = len;
    int sum = 0;
    unsigned short *w = addr;
    unsigned short answer = 0;

    while(nleft > 1)
    {
        sum += *w++;
        nleft -= 2;
    }
    if(nleft == 1)
    {
        *(unsigned char *)(&answer) = *(unsigned char *)w;
        sum += answer;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;

    return answer;
}

/* 填充icmp报文 */
struct icmp *fill_icmp_packet(int icmp_type, int icmp_sequ)
{
    struct icmp *icmp_packet;

    icmp_packet = (struct icmp *)malloc(ICMP_PACKET_LEN);
    icmp_packet->icmp_type = icmp_type;
    icmp_packet->icmp_code = 0;
    icmp_packet->icmp_cksum = 0;
    icmp_packet->icmp_id = htons(getpid());
    icmp_packet->icmp_seq = htons(icmp_sequ);
    /* 发送时间 */
    gettimeofday((struct timeval *)icmp_packet->icmp_data, NULL);
    /* 校验和 */
    icmp_packet->icmp_cksum = check_sum((unsigned short *)icmp_packet, ICMP_PACKET_LEN);

    return icmp_packet;
}

/* 发送icmp请求 */
void icmp_request(const char *dst_ip, int icmp_type, int icmp_sequ)
{
    struct sockaddr_in dst_addr;
    struct icmp *icmp_packet;
    int sockfd, ret_len;
    char buf[ICMP_PACKET_LEN];

    /* 请求的地址 */
    bzero(&dst_addr, sizeof(struct sockaddr_in));
    dst_addr.sin_family = AF_INET;
    dst_addr.sin_addr.s_addr = inet_addr(dst_ip);

    if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        err_exit("sockfd()");

    /* icmp包 */
    icmp_packet = fill_icmp_packet(icmp_type, icmp_sequ);
    memcpy(buf, icmp_packet, ICMP_PACKET_LEN);

    /* 发送请求 */
    ret_len = sendto(sockfd, buf, ICMP_PACKET_LEN, 0, (struct sockaddr *)&dst_addr, sizeof(struct sockaddr_in));
    if (ret_len > 0)
        printf("sendto() ok!!!
");

    close(sockfd);
}

int main(int argc, const char *argv[])
{
    if (argc != 2)
    {
        printf("usage:%s dst_ip
", argv[0]);
        exit(1);
    }

    /* 发送icmp请求 */
    icmp_request(argv[1], 8, 1);

    return 0;
}

icmp接收

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

/* IP首部长度 */
#define IP_HEADER_LEN sizeof(struct ip)
/* icmp报文长度 */
#define ICMP_PACKET_LEN sizeof(struct icmp)
/* IP + ICMP长度 */
#define IP_ICMP_PACKET_LEN IP_HEADER_LEN + ICMP_PACKET_LEN

void err_exit(const char *err_msg)
{
    perror(err_msg);
    exit(1);
}

/* 计算发送时间与接收时间的毫秒差 */
float time_interval(struct timeval *recv_time, struct timeval *send_time)
{
    float msec = 0;

    /* 如果接收的时间微妙小于发送的微妙 */
    if (recv_time->tv_usec < send_time->tv_usec)
    {
        recv_time->tv_sec -= 1;
        recv_time->tv_usec += 1000000;
    }
    msec = (recv_time->tv_sec - send_time->tv_sec) * 1000.0 + (recv_time->tv_usec - send_time->tv_usec) / 1000.0;

    return msec;
}

int main(void)
{
    struct ip *ip_header;
    struct icmp *icmp_packet;
    char buf[IP_ICMP_PACKET_LEN];
    struct timeval *recv_timeval, *send_timeval;
    int sockfd, ret_len;

    if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        err_exit("sockfd()");

    recv_timeval = malloc(sizeof(struct timeval));
    while (1)
    {
        ret_len = recv(sockfd, buf, IP_ICMP_PACKET_LEN, 0);
        if (ret_len > 0)
        {
            /* 接收时间 */
            gettimeofday(recv_timeval, NULL);
            /* 取出ip首部 */
            /* 取出icmp报文 */
            ip_header = (struct ip *)buf;
            icmp_packet = (struct icmp *)(buf + IP_HEADER_LEN);
            /* 取出发送时间 */
            send_timeval = (struct timeval *)icmp_packet->icmp_data;
            printf("===============================
");
            printf("from ip:%s
", inet_ntoa(ip_header->ip_src));
            printf("icmp_type:%d
", icmp_packet->icmp_type);
            printf("icmp_code:%d
", icmp_packet->icmp_code);
            printf("time interval:%.3fms
", time_interval(recv_timeval, send_timeval));
        }
    }

    free(recv_timeval);
    close(sockfd);
    return 0;
}

arp-icmp应答伪装

#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] = {0x38,0x97,0xd6,0x51,0xa0,0x02};


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( "
" );
        }
    }

    printf( "
" );
    return 0;
}

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

    printf("========frame ether========
");
    printf("type :0x%04x
", htons(eth->ether_type));
    printf("d-mac:%02x-%02x-%02x-%02x-%02x-%02x
",
        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
",
        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  ========
");
    printf("arp_hrd=%d    
", htons(arp->arp_hrd));
    printf("arp_pro=0x%04x
", htons(arp->arp_pro));
    printf("arp_op =%d    
", htons(arp->arp_op));
    printf("arp_sdr=%02x-%02x-%02x-%02x-%02x-%02x %d.%d.%d.%d
", 
        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
", 
        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   ========
");
    printf("ip_v  =0x%x
", iph->ip_v             ); /* 4位版本号           */
    printf("ip_hl =0x%x
", iph->ip_hl            ); /* 4位IP头部长度 32bit */
    printf("ip_tos=0x%x
", iph->ip_tos           ); /* 8位服务类型         */
    printf("ip_len=0x%x
", htons(iph->ip_len)    ); /*16位数据包总长度     */
    printf("ip_id =0x%x
", htons(iph->ip_id)     ); /*16位标志符           */
    printf("ip_off=0x%x
", htons(iph->ip_off)    ); /* 3位标记+13位片偏移  */
    printf("ip_ttl=0x%x
", iph->ip_ttl           ); /* 8位生存时间         */
    printf("ip_p  =0x%x
", iph->ip_p             ); /* 8位协议号           */
    printf("ip_sum=0x%x
", htons(iph->ip_sum)    ); /*16位首部校验和       */
    printf("ip_src=%s  
", inet_ntoa(iph->ip_src)); /*32位源地址           */
    printf("ip_dst=%s  
", inet_ntoa(iph->ip_dst)); /*32位目的地址         */
    return 0;
}

static int 
xdump_frame_icmp (struct icmp *icmph)
{
    if (NULL == icmph) {
        return -1;
    }
    
    printf("========frame icmp ========
");
    printf("icmp_type =0x%x
", icmph->icmp_type ); /*  8位类型          */
    printf("icmp_code =0x%x
", icmph->icmp_code ); /*  8位代码          */
    printf("icmp_cksum=0x%x
", icmph->icmp_cksum); /* 16位校验和        */
    printf("icmp_id   =0x%x
", icmph->icmp_id   ); /* 16位识别号 进程id */
    printf("icmp_seq  =0x%x
", 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)
", 
            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
", 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)
", 
            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("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
");
    printf("========frame size:%d
", s_frame_size);
    xdump_frame_ether(eth);
    xdump_frame_arp  (arp);
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
");
    printf("
");
#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
", 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("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
");
    printf("========frame size:%d
", s_frame_size);
    xdump_frame_ether(eth  );
    xdump_frame_ip   (iph  );
    xdump_frame_icmp (icmph);
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
");
    printf("
");
#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
", 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
",argv[0]);
        printf("   ex: %s eth0 192.168.88.1
", argv[0]);
        return -1;
    }

    skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (skfd < 0) {
        xprint_err("socket() failed! errno=%d (%s)
", 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)
", 
            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)
", 
            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)
", 
            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)
", 
            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)
", 
                errno, strerror(errno));
            return -1;
        }
    }

    printf("========host info  ========
");
    printf("ifr_ifindex=%d %s
", s_interface_index, argv[1]);
    printf("ifr_hwaddr =%02x-%02x-%02x-%02x-%02x-%02x
", 
        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
", inet_ntoa(s_interface_ip));
    printf("ifr_flags  =IFF_PROMISC
");
    printf("pid        =0x%x
", getpid());
    printf("header_eth =%d
", HDR_LEN_ETH);
    printf("header_arp =%d
", HDR_LEN_ARP);
    printf("header_ip  =%d
", HDR_LEN_IP);
    printf("header_icmp=%d
", HDR_LEN_ICMP);
    printf("
");

    printf("press any key continue!
");
    getchar();
    printf("waiting for someone ping %s ...
", 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)
", 
            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;
}
原文地址:https://www.cnblogs.com/tla001/p/6592418.html