始终没有找到这个模拟多个IP发包的工具,所以自己动手写了一个
因为时间紧迫,也没有去优化,支持多个线程并发发包,希望大家可以对它进行优化和改造,分享给更多有需要的朋友 呵呵
// Created by lijg, 2013-04-28
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 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;
}
阅读(1834) | 评论(0) | 转发(0) |