一款简单易用的 DNS 发包工具

1)执行make,编译
2)修改client.conf
3)根据需要修改要发送的域名 改query_domain
4)根据需要修改发包数量,时间间隔等 改start.sh
5)执行./start.sh
6)查看 ./start.sh print
7)关闭 ./start.sh kill

容易犯的错误
1)client.conf 配置没有改对。源ip和目的ip不能相同。一般来说目的比源大
2)域名后面没有加. 只支持A
3)start.sh路径不对

Makefile

senddns : senddns.o
    gcc -g -o senddns senddns.c
.PHONY : clean
clean :
    rm -f *.o senddns

startdns.sh

if [ "kill" = $1 ]
then
    killall senddns
elif [ "print" = $1 ]
then
    ps -ef|grep senddns|grep -v grep
else
    for((i=1;i<=1;i++))
    do
        /root/senddns/senddns @client.conf 100 1000000 1000&
    done
fi

client.conf

#start source ip
--start_sip 192.168.100.58

#stop source ip
--end_sip   192.168.100.60

#exclude source IP list, space to separate 
--exclude_sip 192.168.100.50 192.168.100.51 192.168.100.52 192.168.100.100

#start source port, must be more than 1024
--start_sport 2000

#stop source port, must be less than 65535
--end_sport 60000

#direction IP
--targetip 192.168.100.100

#direction port
--targetport 53

#query domain list file
--queryfile  query_domain.txt

query_domain.txt

www.sabadeda.com. A
bbs.sabadeda.com. A
edu.paidai.com. A
news.paidai.com. A
z.paidai.com. A
x.paidai.com. A
my.paidai.com. A
bbs.paidai.com. A

senddns.c

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int debug_flag = 0;
void sig_proc(int signum);

#define LOG_DEBUG(fmt, args...)                                     \
    do { if (debug_flag) printf(fmt,##args); } while (0)


typedef struct ip_hdr
{
    unsigned char     h_verlen;
    unsigned char     tos;
    unsigned short    total_len;
    unsigned short    ident;
    unsigned short    frag_and_flags;
    unsigned char     ttl;
    unsigned char     proto;
    unsigned short    checksum;
    unsigned int      sourceIP;
    unsigned int      destIP;
}IP_HEADER;

typedef struct udp_hdr
{
    unsigned short    uh_sport;
    unsigned short    uh_dport;
    unsigned short    uh_length;
    unsigned short    uh_checksum;
}UDP_HEADER;

typedef struct usd_hdr
{
    unsigned long       saddr;
    unsigned long       daddr;
    char                mbz;
    char                ptcl;
    unsigned short      udpl;
}USD_HEADER;

typedef struct dns
{
    unsigned short    tid;
    unsigned short    flags;
    unsigned short    queries;
    unsigned short    answers;
    unsigned short    auth;
    unsigned short    additional;
}DNS_HEADER;

typedef struct query
{
    char *    name;
    unsigned short    type;
    unsigned short    class;
}QUERY_HEADER;

unsigned long long sleeptime, starttime, outcount = 0, max_pkts=0;
int pkt_then_sleep = 0;
FILE *fp_query = NULL;

struct send_conf {
   unsigned int threadnum;
   unsigned int start_sip;
   unsigned int end_sip;
   unsigned int exclude_sip_num;
   unsigned int exclude_sip_list[1024];
   unsigned int start_sport;
   unsigned int end_sport;    
   unsigned int targetip;
   unsigned int targetport;
   unsigned char query_file[1024];
} send_config;

IP_HEADER   IpHeader;
UDP_HEADER  UdpHeader;
USD_HEADER  UsdHeader;
DNS_HEADER  DnsHeader;
QUERY_HEADER    QueryHeader;
char query_domain[1024] = {0};

unsigned short CheckSum(unsigned short * buffer, int size)
{
    unsigned long   cksum = 0;

    while (size > 1)
    {
        cksum += *buffer++;
        size -= sizeof(unsigned short);
    }
    if (size)
    {
        cksum += *(unsigned char *) buffer;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);

    return (unsigned short) (~cksum);
}

void MySleep(unsigned int micro_second)
{
    struct timeval  t_timeval;

    t_timeval.tv_sec = 0;
    t_timeval.tv_usec = micro_second;

    select( 0, NULL, NULL, NULL, &t_timeval );
}

void PaddingQuery( char *buffer, char *domain_name)
{
    char *tmp = (char *)malloc(strlen(domain_name)+1);
    if( NULL == tmp )
    {
        fprintf( stderr, "malloc for query error: %s\n", strerror(errno) );
        exit(-1);
    }
    memset( tmp, 0, strlen(domain_name)+1 );
    memset(query_domain, 0, sizeof(query_domain));

    strncpy(tmp, domain_name, strlen(domain_name));
    strncpy(query_domain, tmp, sizeof(query_domain));

    int length_pos = 0;
    int loop_num = 1;

    char *token = strtok( tmp, "." );
    while( NULL != token )
    {
        if( loop_num == 1 )
        {
            length_pos = 0;
            memset( buffer, strlen(token), 1 );
            strcpy( buffer+length_pos+1, token );

            length_pos = length_pos + strlen(token) + 1;
        }
        else
        {
            memset( buffer+length_pos, strlen(token), 1 );
            strcpy( buffer+length_pos+1, token );

            length_pos = length_pos + strlen(token) + 1;
        }

        token = strtok( NULL, "." );
        loop_num ++;
    }

    free(tmp);
}

void Init( char *buffer, int buffer_size, struct send_conf *sndcfg, char *domain_name)
{

// whole udp packet except ip header and usd_header
    int i;
    int sip;
    int total_packet_len = buffer_size;
    int total_len;
    static int srcip_cnt = 0;

// udp packet with usd_header
    int udp_with_usd_len = total_packet_len - sizeof(IP_HEADER) + sizeof(USD_HEADER);

    char *udp_packet = (char *)malloc( udp_with_usd_len );
    if( NULL == udp_packet )
    {
        fprintf( stderr, "malloc udp packet error: %s\n", strerror(errno) );
        exit(-1);
    }
    memset( udp_packet, 0, udp_with_usd_len );

    IpHeader.h_verlen = (4<<4 | sizeof(IpHeader)/sizeof(unsigned int));
    IpHeader.tos = 0;
    IpHeader.total_len = htons( total_packet_len );
    IpHeader.ident = rand() % 30000 + 9876;
    IpHeader.frag_and_flags = 0x0000;
    IpHeader.ttl = 64;
    IpHeader.proto = IPPROTO_UDP;
    IpHeader.checksum = 0x0000;

// 1.1.1.1 ----------- 250.250.250.250
//    IpHeader.sourceIP = htonl(rand( ) % 4193909242 + 16843009);

    sip = sndcfg->start_sip + srcip_cnt%(sndcfg->end_sip - sndcfg->start_sip);

get_sip_again:    

    for (i = 0; i < sndcfg->exclude_sip_num; i++) {
        if (sip == sndcfg->exclude_sip_list[i]) {
            srcip_cnt++;
            if (sip < sndcfg->end_sip) {
                sip++;
            } else {
                sip = sndcfg->start_sip;
            }
            goto get_sip_again;
        }
    }

    srcip_cnt++;

    IpHeader.sourceIP = htonl(sip);    
    IpHeader.destIP = htonl(sndcfg->targetip);

    UdpHeader.uh_sport = htons(sndcfg->start_sport + outcount%(sndcfg->end_sport - sndcfg->start_sport));    
    UdpHeader.uh_dport = htons(sndcfg->targetport);

    UdpHeader.uh_length = htons(total_packet_len - sizeof(IP_HEADER) );
    UdpHeader.uh_checksum = 0x0000;

    UsdHeader.saddr = IpHeader.sourceIP;
    UsdHeader.daddr = IpHeader.destIP;
    UsdHeader.mbz = 0x00;
    UsdHeader.ptcl = IPPROTO_UDP;
    UsdHeader.udpl = UdpHeader.uh_length;

    DnsHeader.tid = rand() % 40000 + 12345;
    DnsHeader.flags = 0x0001;
    DnsHeader.queries = 0x0100;
    DnsHeader.answers = 0x0000;
    DnsHeader.auth = 0x0000;
    DnsHeader.additional = 0x0000;

    QueryHeader.type = 0x0100;
    QueryHeader.class = 0x0100;

    memcpy( (void*)buffer, (void*)&IpHeader, sizeof(IpHeader) );
    IpHeader.checksum = CheckSum( (unsigned short *) buffer, sizeof(IpHeader) );
    memcpy( (void*)buffer, (void*)&IpHeader, sizeof(IpHeader) );

    memcpy( udp_packet, (void*)&UsdHeader, sizeof(UsdHeader) );

    memcpy( udp_packet+sizeof(UsdHeader), &UdpHeader, sizeof(UdpHeader) );

    memcpy( udp_packet+sizeof(UsdHeader)+sizeof(UdpHeader), &DnsHeader, sizeof(DnsHeader) );

    PaddingQuery( udp_packet+sizeof(UsdHeader)+sizeof(UdpHeader)+sizeof(DnsHeader), domain_name );

    memcpy( udp_packet+sizeof(UsdHeader)+sizeof(UdpHeader)+sizeof(DnsHeader)+strlen(domain_name)+1, ((char*)&QueryHeader)+sizeof(char *), sizeof(QueryHeader)-sizeof(char*) );

    UdpHeader.uh_checksum = CheckSum( (unsigned short *)udp_packet, udp_with_usd_len );
    memcpy( udp_packet+sizeof(UsdHeader), &UdpHeader, sizeof(UdpHeader) );

    memcpy( buffer+sizeof(IpHeader), udp_packet+sizeof(UsdHeader), udp_with_usd_len - sizeof(USD_HEADER) );

    free( udp_packet );
}

void one_pkt_info_show(int outcount, int srcip, int sport, int dstip, int dport, char *domain)
{
    struct in_addr saddr,daddr;
    char sip[64] = {0};
    char dip[64] = {0};    

    memset(&saddr, 0, sizeof(saddr));
    memset(&daddr, 0, sizeof(daddr));

    printf("send dns pkts------------ %d -------------------\n", outcount );

    saddr.s_addr = srcip;
    daddr.s_addr = dstip;
    strncpy(sip, inet_ntoa(saddr), 16);
    strncpy(dip, inet_ntoa(daddr), 16);    
    printf("%s[%d] ==> %s[%d] %s\n\n", sip, sport, dip, dport, domain);    
}

int parse_query_file(FILE *fp, struct send_conf *sndcfg, char *domain_name, int size)
{
    char *p;
    char *token;
    char *saveptr;
    char readline[4096] = {0};

read_again:                                 
    if (fgets(readline, sizeof(readline), fp) != NULL) {
        p = readline;
        while(*p == ' ' || *p == '\t') p++;
        if (*p == '#') {
            goto read_again;
        }

        if ((token = strtok_r(p, " ", &saveptr)) != NULL) {
            strncpy(domain_name, token, size);
            p = NULL;
        }
    } else {
        rewind(fp);
        goto read_again;
    }

}

void Flood(struct send_conf *sndcfg)
{
    int ret;
    int sock;
    int flag = 1;
    char domain_name[1024];
    int packet_buff_len = 2048;
    int total_packet_len;

// sizeof(char *) means the length of "name" field in the query header.
// 2 means, 0x00 and the length of host, 0x03www0x06google0x03com0x00

    char *buffer = (char *)malloc(packet_buff_len);
    if( NULL == buffer )
    {
        fprintf( stderr, "malloc memory for packet error.\n" );
        return;
    }

    struct sockaddr_in  sa;
    memset( &sa, 0, sizeof(struct sockaddr_in) );
    sa.sin_family = AF_INET;
    sa.sin_port = htons(sndcfg->targetport);
    sa.sin_addr.s_addr = htonl(sndcfg->targetip);

    if( (sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP))  < 0 )
    {
        fprintf( stderr, "create socket error: %s\n", strerror(errno) );
        free(buffer);
        return;
    }

    if( setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (int *)&flag, sizeof(flag)) < 0 )
    {
        fprintf( stderr, "setsockopt error: %s\n", strerror(errno) );
        free(buffer);
        return;
    }

    fp_query = fopen(sndcfg->query_file, "r");
    if (fp_query == NULL) {
        fprintf(stderr, "can not open file: %s\n", sndcfg->query_file);
        return;
    }

    int number = 0;
    if( sleeptime == 0 )
    {
        while( 1 )
        {
            memset( (void *)buffer, 0, sizeof(buffer) );
            memset(domain_name, 0, sizeof(domain_name));
            parse_query_file(fp_query, sndcfg, domain_name, sizeof(domain_name));

            total_packet_len = sizeof(IP_HEADER) + sizeof(UDP_HEADER) + sizeof(DNS_HEADER) + sizeof(QUERY_HEADER) + strlen(domain_name) + 2 - sizeof(char *);
            Init( buffer, total_packet_len, sndcfg, domain_name);

            ret = sendto( sock, buffer, total_packet_len, 0, (struct sockaddr *)&sa, sizeof(struct sockaddr_in) );
            if (ret == -1) {
                fprintf(stderr, "sento error: %s\n", strerror(errno));
                continue;
            }
            outcount ++;
            if (debug_flag) {
                one_pkt_info_show(outcount, IpHeader.sourceIP, ntohs(UdpHeader.uh_sport),
                                  IpHeader.destIP, ntohs(UdpHeader.uh_dport), query_domain);
            }
            if (max_pkts != 0 && outcount >= max_pkts) {
                sig_proc(0);
                exit(0);
            }
        }
    }

    else
    {
        while( 1 )
        {

            memset( (void *)buffer, 0, sizeof(buffer) );
            memset(domain_name, 0, sizeof(domain_name));
            parse_query_file(fp_query, sndcfg, domain_name, sizeof(domain_name));

            total_packet_len = sizeof(IP_HEADER) + sizeof(UDP_HEADER) + sizeof(DNS_HEADER) + sizeof(QUERY_HEADER) + strlen(domain_name) + 2 - sizeof(char *);
            Init( buffer, total_packet_len, sndcfg, domain_name);

            ret = sendto( sock, buffer, total_packet_len, 0, (struct sockaddr *)&sa, sizeof(struct sockaddr_in) );
            if (ret == -1) {
                fprintf(stderr, "sento error: %s\n", strerror(errno));
                continue;
            }

            outcount ++;
            number ++;

            if (debug_flag) {
                one_pkt_info_show(outcount, IpHeader.sourceIP, ntohs(UdpHeader.uh_sport),
                                  IpHeader.destIP, ntohs(UdpHeader.uh_dport), query_domain);
            }

            if (max_pkts != 0 && outcount >= max_pkts) {            
                sig_proc(0);
                exit(0);
            }

            if( number == pkt_then_sleep )
            {
                MySleep( sleeptime );
                number = 0;
            }
        }
    }

    free( buffer );
    return;
}

void sig_proc(int signum)
{
    int end_time = 0;
    char *lang_env;

    end_time=time(NULL);

    lang_env = getenv("LANG");
    if (!lang_env) {
        printf("getenv LANG not Found\n");
        return;
    }

    if (!strncmp(lang_env, "zh_CN.UTF-8", strlen("zh_CN.UTF-8"))) {
        printf("\n ********** 统计信息( %d ) *************\n", signum);
        printf("   总发包数:          %llu\n",outcount);
        printf("   运行时间:         %llu\n",end_time - starttime);
        printf("   平均每秒发包数:   %llu\n",outcount/(end_time - starttime));
        printf(" **************************************\n");
    } else {
        printf("\n ******* statistics( %d ) *************\n", signum);
        printf("   packets sent:          %llu\n",outcount);
        printf("   seconds active:        %llu\n",end_time - starttime);
        printf("   average packet/second: %llu\n",outcount/(end_time - starttime));
        printf(" **************************************\n");        
    }

    if (fp_query) {
        fclose(fp_query);
    }

    exit(1);
}

int usage(void)
{
    char *lang_env;

    lang_env = getenv("LANG");
    if (!lang_env) {
        printf("getenv LANG not Found\n");
        return -1;
    }

    if (!strncmp(lang_env, "zh_CN.UTF-8", strlen("zh_CN.UTF-8"))) {
        fprintf(stderr,"\n%s @config_file <pkt_then_sleep> <sleep_time> <max_pkts> [debug] \n",  "senddns");
        fprintf(stderr, "DNS发包模拟程序\n");
        fprintf(stderr, "参数说明: \n"
                "\t @config_file:      配置文件\n"
                "\t <pkt_then_sleep>:  每次发送的包数后休眠\n"
                "\t <sleep_time>:      休眠时间(微秒)\n"
                "\t <max_pkts>:        发送总包数(0代表无穷大,可通过信号打断退出)\n"
                "\t [debug]:           调试信息输出开关\n"
            );
    } else {
        fprintf(stderr,"\n%s @config_file <pkt_then_sleep> <sleep_time> <max_pkts> [debug] \n",  "senddns");        
        fprintf(stderr, "DNS send packets monitor\n");
        fprintf(stderr, "args note: \n"
                "\t @config_file:      config file\n"                
                "\t <pkt_then_sleep>:  send packets number before sleep interval\n"
                "\t <sleep_time>:      sleep time(microseconds)\n"
                "\t <max_pkts>:        send total packets(0 is enough big, can be signal interrupt then exit)\n"
                "\t [debug]:           debug switch\n"
            );
    }
}

void set_sig( )
{
    signal(SIGHUP,&sig_proc);
    signal(SIGINT,&sig_proc);
    signal(SIGQUIT,&sig_proc);
    signal(SIGILL,&sig_proc);
    signal(SIGABRT,&sig_proc);
    signal(SIGFPE,&sig_proc);
    signal(SIGSEGV,&sig_proc);
    signal(SIGPIPE,&sig_proc);
    signal(SIGALRM,&sig_proc);
    signal(SIGTERM,&sig_proc);
    signal(SIGUSR1,&sig_proc);
    signal(SIGUSR2,&sig_proc);
    signal(SIGCHLD,&sig_proc);
    signal(SIGCONT,&sig_proc);
    signal(SIGTSTP,&sig_proc);
    signal(SIGTTIN,&sig_proc);
    signal(SIGTTOU,&sig_proc);
}


int parse_conf_file(char *conf_name)
{
    int ret;
    int i;
    FILE *fp = NULL;
    char *p = NULL;
    char readline[4096] = {0};
    char *saveptr = NULL;
    char *token;
    int ip;
    int port;
    int threadnum;
    int len;

    conf_name += 1; /* skip @  */
    fp = fopen(conf_name, "r");
    if (fp == NULL) {
        fprintf(stderr, "can not open %s file: %s\n", conf_name, strerror(errno));
        return -1;
    }

    while (fgets(readline, sizeof(readline), fp) != NULL) {
        p = readline;
        while (*p == ' ' || *p == '\t' ) p++;
        if (*p == '#') continue;

        if (!strncmp(p, "--threadnum", strlen("--threadnum"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            threadnum = atoi(p);
            if (threadnum <= 0 || threadnum > 32) {
                fprintf(stderr, "--threadnum must be range in [1~32]: %s\n", p);
                return -1;
            }
            send_config.threadnum = threadnum;
        } else if (!strncmp(p, "--start_sip", strlen("--start_sip"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            ip = inet_addr(p);
            if (ip == INADDR_NONE) {
                fprintf(stderr, "--start_sip format error: %s\n", p);
                return -1;
            }
            send_config.start_sip = ntohl(ip);

        } else if (!strncmp(p, "--end_sip", strlen("--end_sip"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            ip = inet_addr(p);
            if (ip == INADDR_NONE) {
                fprintf(stderr, "--end_sip format error: %s\n", p);
                return -1;
            }
            send_config.end_sip = ntohl(ip);

        } else if (!strncmp(p, "--exclude_sip", strlen("--exclude_sip"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            i = 0;
            send_config.exclude_sip_num = 0;
            while ((token = strtok_r(p, " ", &saveptr)) != NULL) {
                ip = inet_addr(token);
                if (ip == INADDR_NONE) {
                    fprintf(stderr, "--exclude_sip format error: %s\n", p);
                    return -1;
                }
                send_config.exclude_sip_num++;
                send_config.exclude_sip_list[i] = ntohl(ip);
                i++;
                p = NULL;                
            }
        } else if (!strncmp(p, "--start_sport", strlen("--start_sport"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            port = atoi(p);
            if (port <= 1024) {
                fprintf(stderr, "--start_sport must be big than 1024: %s\n", p);
                return -1;
            }
            send_config.start_sport = atoi(p);

        } else if (!strncmp(p, "--end_sport", strlen("--end_sport"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            port = atoi(p);
            if (port > 65535) {
                fprintf(stderr, "--end_sport must be less than 65536: %s\n", p);
                return -1;
            }
            send_config.end_sport = atoi(p);

        } else if (!strncmp(p, "--targetip", strlen("--targetip"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            ip = inet_addr(p);
            if (ip == INADDR_NONE) {
                fprintf(stderr, "--targetip format error: %s\n", p);
                return -1;
            }
            send_config.targetip = ntohl(ip);

        } else if (!strncmp(p, "--targetport", strlen("--targetport"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            send_config.targetport = atoi(p);

        } else if (!strncmp(p, "--queryfile", strlen("--queryfile"))) {
            p = strchr(p, ' ');
            while (*p == ' ' || *p == '\t' ) p++;
            len = strlen(p);
            if (p[len-1] == '\n') {
                p[len-1] = '\0';
            }
            ret = access(p, F_OK);
            if (ret != 0) {
                fprintf(stderr, "can not access file: %s, ERR: %s\n", p, strerror(errno));
                return -1;
            }
            strncpy(send_config.query_file, p, sizeof(send_config.query_file));
        } 

        memset(readline, 0, sizeof(readline));

    }

    fclose(fp);

    return 0;
}


int main(int argc,char *argv[])
{
    int i;
    int ret;
    char    dst_ip[20] = { 0 };

    if( argc != 5 && argc != 6 )
    {
        usage();
        return -1;
    }

    if (argc == 6 && !strcmp(argv[5], "debug")) {
        debug_flag = 1;
    }

    if (argv[1][0] != '@') {
        usage();
        return -1;
    }

    ret = parse_conf_file(argv[1]);
    if (ret != 0) {
        fprintf(stderr, "parse config file error: %d\n", ret);
        return ret;
    }

    pkt_then_sleep = atoi(argv[2]);
    if( pkt_then_sleep == 0 )
    {
        printf( "pkt_then_sleep error.\n" );
        return -1;
    }

    sleeptime = atoi(argv[3]);
    max_pkts = atoi(argv[4]);     
    starttime = time(NULL);
    while(time(NULL) == starttime) usleep(1000);

    srand((unsigned) time(NULL));

    set_sig( );
    Flood(&send_config);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值