模拟多个客户端IP发送udp包

来源:互联网 发布:蓝盾 大数据 编辑:程序博客网 时间:2024/05/23 15:40

始终没有找到这个模拟多个IP发包的工具,所以自己动手写了一个微笑

因为时间紧迫,也没有去优化,支持多个线程并发发包,希望大家可以对它进行优化和改造,分享给更多有需要的朋友 呵呵

// Created by lijg, 2013-04-28



#include <stdio.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>




#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>


#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>


#include <netinet/ip.h>
#include <netinet/udp.h>


// gcc -g udpflood.c -o udpflood -lpthread
// sudo ./udpflood eth0 192.168.123.10 192.168.123.20 198.130.223.141 69 192.168.123.1 10240
// sudo ./udpflood eth0 198.130.223.10 198.130.223.20 198.130.223.141 69 198.130.223.141 102400
// sudo ./udpflood eth0 192.168.123.10 192.168.123.10 198.130.223.141 69 192.168.123.2 1024




/*
 * Ethernet header
 */
typedef struct _EtherHdr
{
    unsigned char ether_dst[6];
    unsigned char ether_src[6];
    unsigned short ether_type;
}  __attribute__ ((__packed__)) EtherHdr;


typedef struct _ARPHdr
{
    unsigned short ar_hrd;       /* format of hardware address   */
    unsigned short ar_pro;       /* format of protocol address   */
    unsigned char ar_hln;        /* length of hardware address   */
    unsigned char ar_pln;        /* length of protocol address   */
    unsigned short ar_op;        /* ARP opcode (command)         */
}   ARPHdr;


typedef struct _EtherARP
{
    ARPHdr ea_hdr;      /* fixed-size header */
    unsigned char arp_sha[6];    /* sender hardware address */
    unsigned char arp_spa[4];    /* sender protocol address */
    unsigned char arp_tha[6];    /* target hardware address */
    unsigned char arp_tpa[4];    /* target protocol address */
}   EtherARP;




struct moptions {
char cmac[6];            // 本机MAC地址
//char svrip[32];
unsigned int svrip;      // 网络序 目标服务器IP
unsigned short svrport;  // 网络序 目标服务器端口
unsigned int gwip;       // 网络序 网关IP
char smac[6];            // 网关MAC地址
unsigned long bps;        // bytes/S
unsigned int cbip, ceip;  // 本机起止IP地址
} gloptions;


#define __LOG(fmt, args...) fprintf(stdout, fmt"\n", ##args)


#define ETHERNET_TYPE_IP              0x0800
#define ETHERNET_TYPE_ARP             0x0806


#define ARPOP_REQUEST   1    /* ARP request                  */
#define ARPOP_REPLY     2    /* ARP reply                    */
#define ARPOP_RREQUEST  3    /* RARP request                 */
#define ARPOP_RREPLY    4    /* RARP reply                   */




//static int s;
static int if_index;
static const char *if_name = "eth0";


static int volatile __exit__ = 0;


static void set_signal(int signo, void (*handler) (void))
{
    struct sigaction sa;


    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = (void (*)(int)) handler;
    sa.sa_flags = SA_RESTART;
    sigaction(signo, &sa, NULL);
}


static int _nonblock (int s, int yes)
{
#ifdef SO_NONBLOCK
    return setsockopt (s, SOL_SOCKET, SO_NONBLOCK, &yes, sizeof (yes));
#else
    int v = fcntl (s, F_GETFL, 0);
    return fcntl (s, F_SETFL, yes ? (v | O_NONBLOCK) : (v & ~O_NONBLOCK));
#endif
}


static int get_ifindex(void)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
int t = socket(PF_INET, SOCK_STREAM, 0);
if (t < 0) {
__LOG("socket error, %s", strerror(errno));
return -1;
}

if (ioctl(t, SIOCGIFINDEX, &ifr) < 0) {
__LOG("ioctl SIOCGIFINDEX error.");
return -1;
}


if_index = ifr.ifr_ifindex;
return if_index;
}


// 获取 接口 eth* 的MAC地址,存储到 @ifmac中
static int nic_gethardaddr(const char* device, unsigned char* ifmac)
{
    //fprintf(stdout, "begin  nic_gethardaddr  \n" );
    struct ifreq ifr;


    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
    
    int s = socket(PF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        fprintf(stderr, "create socket failed\n");
        return -1;
    }


    if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
    {
       fprintf(stderr, "Get Interface \"%s\" hardware address failed, reason: %s\n", device, strerror(errno));
        close(s);
        return -1;
    }
    
    memcpy(ifmac, ifr.ifr_hwaddr.sa_data, 6);


    close(s); //very important
    //fprintf(stdout, "mac = %02x:%02X:%02X:%02X:%02X:%02X\n", ifmac[0], ifmac[1], ifmac[2], ifmac[3], ifmac[4], ifmac[5]);


    return 0;
}


static int pf_bind(int s, int ifidx, short proto)
{
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(struct sockaddr_ll));
sa.sll_family = AF_PACKET;
sa.sll_ifindex = ifidx;
//sa.sll_protocol = htons(ETH_P_ARP);
sa.sll_protocol = proto;

if (bind(s,  (struct sockaddr *)&sa, sizeof(struct sockaddr_ll))) {
__LOG("bind error, %s", strerror(errno));
return -1;
}


return 0;
}


static int decode_raw(char *buf, ssize_t len, struct sockaddr_ll *from)
{
struct ethhdr *eth = (struct ethhdr *)buf;


__LOG("Ethernet header :(0x%04x), len=%ld", ntohs(eth->h_proto), len);
__LOG(" source mac : %02X:%02X:%02X:%02X:%02X:%02X", eth->h_source[0], eth->h_source[1], 
   eth->h_source[2], eth->h_source[3], eth->h_source[4], eth->h_source[5]);
  __LOG(" dest mac :   %02X:%02X:%02X:%02X:%02X:%02X", eth->h_dest[0], eth->h_dest[1], 
   eth->h_dest[2], eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);


return 0;
}


int pfp_write(int s, unsigned char *buffer, int len, int ifidx)
{
        struct sockaddr_ll he;
        he.sll_family   = AF_PACKET;
        he.sll_protocol = htons(ETH_P_ALL);
        he.sll_halen    = ETH_ALEN;
        he.sll_ifindex = ifidx;
        he.sll_pkttype = PACKET_OUTGOING;


        return sendto(s, buffer, (size_t)len, 0, (struct sockaddr *) &he, sizeof(he));
}


static void finish(void)
{
__exit__ = 1;
fprintf(stdout, "system terminate by interruptted\n");
}


/**
 * POSIX线程启动...
 */
int thread_start(pthread_t *thread_id, void* (*thread_function)(void * ), void * para)
{
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
return -1;
}


#if 1
/*退出时自动清除线程资源*/
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
return -1;
}
#endif


/*设置线程为全局调度模式*/
if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) {
return -1;
}


if (pthread_create((pthread_t*)thread_id, &attr, thread_function, para) != 0) {
return -1;
}


pthread_attr_destroy(&attr);
return 0;
}






//请求 host'IP 地址的MAC
static void arp_request(int sock, struct sockaddr_ll *HE, unsigned int srcip, unsigned int dstip)
{
    unsigned char sendbuff[60] = {0};
    char c = 4;


    EtherHdr* eh = (EtherHdr*)sendbuff;
    EtherARP* ap = (EtherARP*)&sendbuff[sizeof(EtherHdr)];


    ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
    ap->ea_hdr.ar_pro = htons(ETH_P_IP);
    ap->ea_hdr.ar_hln = 6;
    ap->ea_hdr.ar_pln = 4;
    ap->ea_hdr.ar_op = htons(ARPOP_REQUEST);


    memcpy(ap->arp_sha, gloptions.cmac, 6);
    *(unsigned int*)&ap->arp_spa[0] = srcip;
    memset(ap->arp_tha, 0x00, 6);
    *(unsigned int*)&ap->arp_tpa[0] = dstip;


    //EtherHdr
    eh->ether_type = htons(ETHERNET_TYPE_ARP);
    memset(eh->ether_dst, 0xff, 6);
    memcpy(eh->ether_src, gloptions.cmac, 6);


    do {
        //sendto(sock, sendbuff, sizeof(sendbuff), 0, (struct sockaddr *) HE, sizeof(*HE));
        int ret = pfp_write(sock, sendbuff, sizeof(sendbuff), if_index);
fprintf(stdout, "\nsend packet from %s, ret = %d, ifidx=%u\n", if_name, ret, if_index);
        usleep(250000);
    } while(--c > 0);


    return;
}


static void arp_reply(int sock, unsigned char* buf, int len)
{
EtherARP* ap = (EtherARP*) (buf + sizeof(struct ether_header));
    
// add by lijg, 2013-05-02 , 接收并处里对端网关发来的ARP请求
do {
if (ntohs(ap->ea_hdr.ar_op) != ARPOP_REQUEST || *(unsigned int *)ap->arp_spa != gloptions.gwip) {
break;
}
unsigned int tpa = ntohl(*(unsigned int *)ap->arp_tpa); // 目标端IP
fprintf(stdout, "the arp request tpa = 0x%08x\n", tpa);
if (tpa < gloptions.cbip || tpa > gloptions.ceip) {
break;  // Not arp request for us
}

// 向对端发送ARP应答报文
unsigned char sendbuff[60] = {0};
EtherHdr* eh = (EtherHdr*)sendbuff;
EtherARP*  rap = (EtherARP*)&sendbuff[sizeof(EtherHdr)];
rap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
rap->ea_hdr.ar_pro = htons(ETH_P_IP);
rap->ea_hdr.ar_hln = 6;
rap->ea_hdr.ar_pln = 4;
rap->ea_hdr.ar_op = htons(ARPOP_REPLY);
memcpy(rap->arp_sha, gloptions.cmac, 6);
*(unsigned int *)&rap->arp_spa[0] = *(unsigned int *)&ap->arp_tpa[0];
memcpy(rap->arp_tha, ap->arp_sha, 6);
*(unsigned int *)&rap->arp_tpa[0] = *(unsigned int *)&ap->arp_spa[0];

eh->ether_type = htons(ETHERNET_TYPE_ARP);
memcpy(eh->ether_dst, gloptions.smac, 6);
memcpy(eh->ether_src, gloptions.cmac, 6);

char c = 2;
while (c-- > 0) {
int ret = pfp_write(sock, sendbuff, sizeof(sendbuff), if_index);
fprintf(stdout, "\nsend arp reply from %s, ret = %d, ifidx=%u\n", if_name, ret, if_index);
usleep(5000);
}

return ;
} while (0);
    
    
// 判断是否为对端网关发来的ARP应答
if (ntohs(ap->ea_hdr.ar_op) != ARPOP_REPLY 
|| *(unsigned int *)ap->arp_spa != gloptions.gwip) {
return;
}
    
memcpy(gloptions.smac, ap->arp_sha, 6);
fprintf(stdout, "recv gateway mac = %02X:%02X:%02X:%02X:%02X:%02X\n", gloptions.smac[0]&0xff, gloptions.smac[1]&0xff, 
gloptions.smac[2]&0xff, gloptions.smac[3]&0xff, gloptions.smac[4]&0xff, gloptions.smac[5]&0xff);


return;
}


static void * thread_recv_pkts(void *args)
{
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));  // All packets
ssize_t rlen;
struct sockaddr_ll from;
int alen = sizeof(from);
char buf[2048];

struct sockaddr_ll me;

me.sll_family = AF_PACKET;
me.sll_ifindex = if_index;
me.sll_protocol = htons(ETH_P_ALL);
if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) {
__LOG("bind raw sock error\n");
goto _EXIT;
}

while (!__exit__) {
rlen = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from, &alen);
if (rlen < 0) {
if (EINTR == errno) continue;

fprintf(stderr, "trp recvfrom error %s\n", strerror(errno));
break;
} else if (0 == rlen) {
__LOG("The peer has closed .");
break;
}


//decode_raw(buf, rlen, &from);

struct ether_header *eh;
eh = (struct ether_header*)buf;


switch(ntohs(eh->ether_type)) {
case ETHERNET_TYPE_ARP:
arp_reply(s, buf, rlen);  // recv process arp reply from gatway ip
break;

case ETH_P_IP:
break;

default :
break;
}
}

_EXIT:
close(s);
return NULL;
}


#define SND_BYTES  1024


static void ethdr_build(unsigned char *buff)
{
EtherHdr* eh;
eh  = (EtherHdr *) buff;
eh->ether_type = htons(ETHERNET_TYPE_IP);
//eh->ether_type = htons(ETHERNET_TYPE_ARP);
memcpy(eh->ether_dst, gloptions.smac, 6);
memcpy(eh->ether_src, gloptions.cmac, 6);
}


static inline __u16 in_csum(__u16 *addr, unsigned int len)
{
    unsigned int nleft = len;
    __u16 *w = addr;
    unsigned int sum = 0;
    __u16 answer = 0;


    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }


    if (nleft == 1) {
        *(__u8 *)(&answer) = *(__u8 *)w;
        sum += answer;
    }


    sum = (sum >> 16) + (sum & 0xffff);   /* add hi 16 to low 16 */
    sum += (sum >> 16);                   /* add carry */
    answer = ~sum;                        /* truncate to 16 bits */
    return answer;
}




static inline unsigned short ip_fast_csum(const void *iph, unsigned int ihl)
{
    unsigned int sum;


    __asm__ __volatile__(
        "movl (%1), %0  ;\n"
        "subl $4, %2    ;\n"
        "jbe 2f     ;\n"
        "addl 4(%1), %0 ;\n"
        "adcl 8(%1), %0 ;\n"
        "adcl 12(%1), %0    ;\n"
"1:     adcl 16(%1), %0 ;\n"
        "lea 4(%1), %1  ;\n"
        "decl %2        ;\n"
        "jne 1b     ;\n"
        "adcl $0, %0    ;\n"
        "movl %0, %2    ;\n"
        "shrl $16, %0   ;\n"
        "addw %w2, %w0  ;\n"
        "adcl $0, %0    ;\n"
        "notl %0        ;\n"
"2:             ;\n"
    /* Since the input registers which are loaded with iph and ihl
       are modified, we must also specify them as outputs, or gcc
       will assume they contain their original values. */
    : "=r" (sum), "=r" (iph), "=r" (ihl)
    : "1" (iph), "2" (ihl)
    : "memory");
    return (unsigned short)sum;
}


static int iphdr_build(unsigned char *buff, unsigned int cip, unsigned char prototype)
{
struct iphdr *iph = (struct iphdr *)buff;
iph->saddr = cip;
iph->daddr = gloptions.svrip;

iph->check = 0;
iph->tos = 0x10;//IPTOS_LOWDELAY
iph->tot_len = htons(SND_BYTES-sizeof(EtherHdr));
iph->ttl = 64;
iph->id = rand();
iph->frag_off = htons(0x4000);//IP_DF
iph->version = 4;
iph->ihl = 5;

iph->protocol = prototype;
iph->check = ip_fast_csum((__u16 *)iph, iph->ihl);
return (iph->ihl << 2);
}


struct pseudohdr
{
unsigned int saddr, daddr;
unsigned char empty;
unsigned char tp;
unsigned int len;
} __attribute__ ((packed));


static void udphdr_build(struct udphdr *uh, int len, unsigned int cip, unsigned short cport)
{
struct pseudohdr *p;

uh->source = cport;
uh->dest = gloptions.svrport;
uh->len = htons(len);
uh->check = 0;
p = (struct pseudohdr *)(((unsigned char *)uh) - sizeof(struct pseudohdr));
memset(p, 0, sizeof(*p));

p->saddr = cip;
p->daddr = gloptions.svrip;

p->tp = IPPROTO_UDP;
p->len = htonl(len);


uh->check = in_csum((unsigned short *)p, sizeof(struct pseudohdr) + len);
}


void rand_buffer(unsigned char *buffer, int len)
{
struct timeval tv;
gettimeofday(&tv, NULL); 
unsigned int seed = tv.tv_usec;
srand(seed);
int ibytes = (int)(len / sizeof(int));
int rbytes = (int)(len % sizeof(int));
int *ibuff = (int *)buffer;
int i;
for (i = 0; i < ibytes; i++) {
ibuff[i] = rand();
}


if (rbytes <= 0) {
return;
}


int tmp = rand();
char *tbuf = (char *)&tmp;
char *rbuf = buffer + ibytes*sizeof(int);
for (i = 0; i < rbytes; i ++, rbuf++, tbuf++) {
*rbuf = *tbuf;
}
}




static void * thread_udp_proc(void *args)
{
unsigned int cip = *(unsigned int *)args;
fprintf(stdout, "client ip = 0x%08x\n", cip);

int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));  // All packets
_nonblock(s, 1);  // 设置为非阻塞模式

struct sockaddr_ll me;

me.sll_family = AF_PACKET;
me.sll_ifindex = if_index;
me.sll_protocol = htons(ETH_P_ALL);
if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) {
__LOG("bind raw sock error\n");
goto _EXIT;
}


arp_request(s, NULL, htonl(cip), gloptions.gwip);  // send arp request packets

unsigned char sbuff[SND_BYTES];
unsigned short cport = htons(10240);
while (!__exit__) {
struct timeval end, curr;
gettimeofday(&end, NULL);
curr = end;
end.tv_sec ++;  // after 1 S
// send packet begining
unsigned long sendbytes = 0;
//fprintf(stdout, "enter send udp packet 1 \n");
while (curr.tv_sec < end.tv_sec || (curr.tv_sec == end.tv_sec && curr.tv_usec < end.tv_usec)) {
if (sendbytes >= gloptions.bps) {
long usecs = (end.tv_sec-curr.tv_sec)*1000000;
usecs += (end.tv_usec-curr.tv_usec);
if (usecs > 0)
usleep(usecs);

fprintf(stdout, "Send over in 1 second \n");
break;
}


int hlen = 20;  // ipv4 hdr length 
hlen += sizeof(EtherHdr);
struct udphdr *uh = (struct udphdr *)(sbuff + hlen);
hlen += sizeof(struct udphdr);
unsigned char *payload = (unsigned char *)(sbuff + hlen);
int pllen = sizeof(sbuff) - hlen;
//fprintf(stdout, "hlen=%d, pllen=%d\n", hlen, pllen);

rand_buffer(payload, pllen);
udphdr_build(uh, pllen+sizeof(struct udphdr), htonl(cip), cport);
iphdr_build(sbuff+sizeof(EtherHdr), htonl(cip), IPPROTO_UDP);
ethdr_build(sbuff);
sendbytes += SND_BYTES;

int ret = pfp_write(s, sbuff, sizeof(sbuff), if_index);
//fprintf(stdout, "\nsend udp packet from %s, ret = %d, ifidx=%u %s\n", if_name, ret, if_index, strerror(errno));

gettimeofday(&curr, NULL);
}
}

_EXIT:
close(s);
return NULL;
}


int main(int argc, char **argv)
{
ssize_t rlen;
//char buf[4096];
struct sockaddr_ll from;
int alen = sizeof(from);

if (argc != 8) {
// 我们需要经过路由测试 
// eth0 -- 发送UDP包的网卡
// 192.168.123.10 192.168.123.20 -- 模拟客户端的起止IP地址
// 198.130.223.141 -- 目标服务器的IP地址
// 20 -- 目标服务器的UDP端口
// 198.130.223.141 -- 路由器的LAN口IP地址 (如果同一网段的话就是目标服务器的IP地址)
// 10240 -- 发送速率 10KB/S
fprintf(stderr, "%s eth0 192.168.123.10 192.168.123.20 198.130.223.141 69 198.130.223.141 10240\n", argv[0]);
return -1;
}
if_name = argv[1];


/*Bind special interface */
get_ifindex();
fprintf(stdout, "if_index=%u\n", if_index);

// 计算起止IP地址
struct in_addr saddr, eaddr;
unsigned int sip, eip;
int count = 0;
inet_aton(argv[2], &saddr);
inet_aton(argv[3], &eaddr);
sip = ntohl(saddr.s_addr);
eip = ntohl(eaddr.s_addr);
count = eip - sip;
count ++;
fprintf(stdout, "sip=0x%08x, eip=0x%08x, count=%d\n", sip, eip, count);
if (count > 253) {
fprintf(stderr, "the client ip net error\n");
return -1;
}
gloptions.cbip = sip;
gloptions.ceip = eip;

nic_gethardaddr(if_name, gloptions.cmac);
fprintf(stdout, "mac = %02X:%02X:%02X:%02X:%02X:%02X\n", gloptions.cmac[0]&0xff, gloptions.cmac[1]&0xff, gloptions.cmac[2]&0xff, 
gloptions.cmac[3]&0xff, gloptions.cmac[4]&0xff, gloptions.cmac[5]&0xff);

struct in_addr svrip;
inet_aton(argv[4], &svrip);
gloptions.svrip = (unsigned int)svrip.s_addr;

inet_aton(argv[6], &svrip);
gloptions.gwip = (unsigned int)svrip.s_addr;

gloptions.svrport = htons(atoi(argv[5]));
gloptions.bps = strtoul((char *)argv[7], (char **)NULL, 10);
fprintf(stdout, "bps = %lu, %lu\n", gloptions.bps, sizeof(gloptions.bps));



//struct ifreq ifr;
//memset(&ifr, 0, sizeof(ifr));
//strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
//ifr.ifr_flags |= IFF_PROMISC;
//if (ioctl(s, SIOCSIFFLAGS, (char*) &ifr) < 0) {
// fprintf(stderr, "Set Interface \"%s\" is promiscous failed\n", if_name);
// close(s);
// return -2;
//}

set_signal(SIGINT, finish);
set_signal(SIGTERM, finish);

pthread_t ptid;
// 启动接收线程
thread_start(&ptid, thread_recv_pkts, (void *)NULL);

int i;
unsigned int *param = (unsigned int *)malloc(sizeof(unsigned int));
for (i = 0; i < count; i ++) {
*param = sip; 
thread_start(&ptid, thread_udp_proc, (void *)param);
sleep(1);
sip ++;

}




/*Receive pkts from low level socket */
while (!__exit__) {

sleep(2);
}

fprintf(stdout, "please waitting ... cleanup\n");
sleep(5);
free(param);
return 0;

}


原创粉丝点击