Jump to content

Roy

Banned
  • Posts

    2,853
  • Joined

  • Last visited

  • Days Won

    383

Posts posted by Roy

  1. On 4/18/2020 at 8:55 AM, Kim said:

     

    @Infra you are my spirit animal.

    Fun fact: Did you know i created that tree when I was completely drunk?

     

    @Roy❤️

    we need to game more my boy

     

     

    Agreed. I've just been really busy and stressed recently. Oddly and sadly, playing games increases those stress levels most of the time lol. So I've just been trying to relax and code small things that doesn't require too much brain power for a couple of days.

     

    Also, I remember that time when you came to me like "LOOK WHAT I MADE" while drunk and it was the happy tree rofl!

  2. RTV (Exclude AFKs)

    Hey everyone, I just wanted to share a small modification I made to the base Rock The Vote plugin provided by AlliedMods.

     

    Description
    A simple modification to AlliedMod's default Rock The Vote plugin. This plugin excludes AFK players based off of the AFK Manager plugin located here. It uses forwards provided by the AFK Manager plugin.

     

    Requirements
    Running The Plugin On The Game Server

    • SourceMod >= 1.10.0
    • MetaMod
    • AFK Manager plugin found here.

     

    Compiling The Plugin

    • SourceMod >= 1.10.0
    • Afk_manager.inc file should be in the scripting/include/ directory. This file can be found here.

     

    Credits

    • AlliedMods - Created the base Rock The Vote plugin.
    • Rothgar, Asherkin, and Psychonic - Created/Helped Create the AFK Manager plugin.
    • @Roy - Added modification 

     

    GitHub Link

     

    Thank you!

  3. As stated in the original post, I made this fairly quickly. This will likely be going on our TF2 and CS:S servers.

     

    The code appears to work in CS:S and TF2 based off of the testing I've done in both games. All the features work from what I tested. I'm sure there are ways this code can be improved. With that said, if any GFL Developers want to try to implement join awards to this such as Store credits, that'd be awesome! Though, this would require setting up a Discord bot, setting up a web-backend with a REST API (more than likely), and more. I might try to take on that project in the future, I'm already busy with Anycast development and a lot more.

     

    Thanks!

  4. Discord On Connect

    Hey everyone, I just wanted to post a plugin I made this morning quickly.

     

    Description
    A quick plugin I wrote for SourceMod. When a client joins the game, it will open an MOTD window with a Discord invite link or anything else you want. Comes with many features. Supports menus, cookies, and more.

     

    ConVars

    • sm_doc_enabled => Enables plugin (Default: 1).
    • sm_doc_title => MOTD window's title. (Default: "Join our Discord server and get free rewards!").
    • sm_doc_link => Discord invite link. (Default: "https://discord.gg/MnPD6BG").
    • sm_doc_menu => Show a menu stating to join the server on connect? (Default: 1).
    • sm_doc_notify => Notify the client that we invited them to our Discord server when `sm_doc_menu` is set to 0. (Default: 1).
    • sm_doc_prevent_multiple => Prevent more than one invite per user. (Default: 1).
    • sm_doc_goto => Go to another URL after opening Discord link two seconds later (silently). (Default: 1).
    • sm_doc_goto_url => URL to go to if 'sm_doc_goto' is set to 1. (Default: "https://GFLClan.com/").
    • sm_doc_hook => Hook to use when presenting menu. 1 = Hook->player_initial_spawn. 2 = OnClientPostAdminCheck. (Default: 2).
    • sm_doc_wait_time => Wait time when using '2' as `sm_doc_hook`. (Default: 10.0).

     

    Credits

    • Christian Deacon - @Roy

     

    GitHub Link

     

    Thanks!

  5. Can this include GFL CS:S ZE? If so, can this include the best 'fun' moments as well?

     

    If so, this moment on GFL CS:S ZE's server back years ago was hilarious and probably one of my favorite highlights in my opinion:

     

     

    Sadly I wasn't there for it. I'm sure not everybody would find that fun, but personally I liked the atmosphere.

     

    I miss CS:S ZE back then :( 

  6. 23 hours ago, _Rocket_ said:

    I think it would be super interesting. I've always liked C. I mean I do also enjoy the tools that come with higher level languages, and the objects of C++. But sometimes it just gets overly complicated. Something about writing C code is so fun to me.

     

    I know you like networking a lot, so I wanna ask. How different is it to write networking code in C compared to other languages?

     

    I ask because I have a software dev mindset with C. The speed of the language is appealing. How practical is using C for networking? Is the speed of the language helpful?

    I haven't messed with networking too much in other languages besides PHP and GoLang (once). I think other higher-level languages may make it easier though, but you wouldn't have as much control and it wouldn't be as fast as well. I think the performance advantage and being able to use hooks such as XDP/TC are the biggest appeals to me for C.

     

    I plan to get into learning more higher-level languages in the future though and I'll test out the networking side of them. I'll report back to you once I do :) I already have a bit of experience with Java, C++, GoLang, and a few others thankfully.

     

    Thanks!

  7. Thank you for the appreciation everyone :) It means a lot!

     

    3 minutes ago, yuptodat said:

    Nice! Sounds like a headache to deal with. I wish you further luck. :)

    It was indeed a huge headache, but things appear to be stable for now!

     

    The next thing I'm hoping that happens is the hosting provider's DC is able to remove the ACL rules preventing us from spoofing traffic out as the Anycast network. I need these ACL rules removed so we can use the TC BPF program I made that'll send outgoing IPIP packets back to the clients directly instead of back through the Anycast POP servers/IPIP tunnel. This would result in less load on the POP servers, less overage fees, eliminates a single-point-of-failure, and more!

     

    Thank you!

  8. Update

    The new machine went down last night after an hour or two of running. I sent a ticket to our hosting provider at the time and requested IPMI/KVM access. Afterwards, I went to bed since I was exhausted.

     

    This morning, they provided me credentials to the IPMI/KVM. After inspecting some logs within the IPMI portal itself, I discovered this was most likely a motherboard issue with the new machine according to one of the events triggered at the same time the machine went down. I told our hosting provider about this and they stated while the motherboard they had in the new machine is supposed to handle the load from the Intel i9-9900K, they had other clients have the same issue that we had along with the same event triggering in the IPMI console. The hosting provider had other machines available with the Intel i9-9900K, but I needed to install the OS myself through the KVM along with setup another machine again. For the last few hours, I've been doing this and got everything setup properly. This new (new) machine comes with a motherboard that is proven stable with the Intel i9-9900K.

     

    I've moved the Rust Modded and CS:S Dust2 files over to the new machine, updated the Anycast network config, and the servers are running fine right now. I will continue to monitor the server. Thankfully I have full IPMI/KVM access which is nice :)

     

    We have also been refunded for the lost time and granted an additional day of service for the above from our hosting provider.

     

    @Xy will finish moving the other servers when he has time.

     

    I just wanted to apologize for the inconvenience and thank you for your understanding with all of this. I'm trying my best to get us up and running as quick as possible.

  9. The new machine is setup and we're working to move servers over.

     

    CS:S 24/7 Dust2 is already moved. @Xy will be moving the rest of the servers tonight/tomorrow morning. The network is prepared for the move.

     

    One thing I want to mention is this new hosting provider has not removed ACL rules to allow us to spoof out as our Anycast network. Therefore, I cannot load the TC BPF program I made onto it. However, they're working with the DC to remove the ACLs for our network. I upgraded the server's kernel and installed the TC BPF program anyways so once they do remove it, I can just load the program quickly.

     

    In the case they can't remove the ACLs, we will have to find a new provider most likely. There are plenty of options out there, though. We're going to see how this goes first. I don't think the Anycast network was the issue with the performance on the NYC machines anyways. I believe this was due to the NIC or hops at the data centers.

     

    In the meantime, I've upgraded our Chicago POP to two cores so it can handle the traffic from the game server machine(s).

     

    Thank you.

  10. 2 hours ago, MR.CORONA said:

    image.thumb.png.683c6757b98043efd28799c9f8ab05cf.png

    @Roy thank you for replying, I've scanned my pc for virus using malwarebytes and it it detected no threat. Also my router had it's firewall settings to low, Is my router's firewall doing the port scans?, should I try to disable it?  

     

    No problem :) I'm unsure if it is or not without looking at logs on the router itself.

     

    I have replied to the NFO ticket stating you took the necessary actions and they will be unblocking your IP soon.


    If you get blocked again, I'll give you some additional troubleshooting steps. I wouldn't be worried about it until that point.

     

    Thank you!

  11. Hey everyone,

     

    I just wanted to let everyone know our GS2990wx machine had a sudden hard drive failure. @Xy and I are working to get the server files off of the machine.

     

    I also ordered a new machine that includes the Intel i9-9900K, 64 GBs of RAM, and 1 TB NVMe for $139.99/m. This machine will be setup soon and we will be moving our servers from GS2990wx to this machine. The DC hasn't setup the machine for us yet, but they told us it should be setup soon. I also believe the recent performance issues should be resolved when moving to this new machine. The new machine will be located in Chicago, IL.

     

    Servers that were on this machine included Rust Modded #1 and #2, CS:S 24/7 Dust2, GMod nZombies, and a few TF2 servers.

     

    Once I have an update, I will let you all know.

     

    I apologize for the inconvenience and thank you for understanding.

  12. General Rules

    • Be respectful to players and admins.
    • No advertising.
    • No racism.
    • No spamming the chat or voice chat.
    • No delaying rounds.
    • No scripting or hacking (including BHop scripts).
    • Avoiding Mutes/Gags is punishable. 

     

    Server Features

    • 24/7 Dust2.
    • No Awps/Autos.
    • Quick defuse.
    • 30 seconds C4 timer.
    • GameME (stats).
    • $16000 each spawn.
    • Hosted in New York City, NY.

     

    Admin(s)

     

    Useful Links

    • Apply for Member here.
    • Player reports here.
    • Mute/Ban appeals here.
    • Admin applications here.

     

    Please feel free to add the servers to your favorites! The IP is 92.119.148.87:27015.

     

    Thank you!

  13. 4 minutes ago, Leks said:

    hi i got question what would i use this for :pogchamp:

    If you want to generate packet data to measure performance, this would help, specifically for IPIP traffic. Technically, this can be used as a DoS tool as well, especially if you have the --interval option set to 0 which doesn't wait in-between sending packets. Though, when I rewrite the UDP Sender program, that'll be a lot better for that. I was able to push 600 mbps from one of our machines using this, but that isn't why I made the program. I'm currently seeing how much data and packets our NICs can handle and want to see if that's one of our primary bottlenecks.

     

    Thanks.

  14. Hey everyone,

     

    I just wanted to share some code I've been working on the past couple of days. I made a C program that generates a random amount of packet data based off of the program's arguments (--min and --max). The program encapsulates the packet inside of an outer IP header with the IPIP protocol. Therefore, the endpoint (destination/NAT servers) needs to have an IPIP tunnel. This is similar to my UDP Sender program, but uses AF_PACKET sockets instead, has more in-depth command line options, and uses IPIP. I plan to rewrite my UDP Sender program and make it similar to this program, but it wouldn't use IPIP obviously. That said, this program comes with statistics (e.g. average mbps sent/received, packet loss, packet count, and latency). As of right now, the program puts a timestamp inside of the packet data and parses it when the data is sent back to get the timing of the packet (e.g. the ping). Unfortunately, I wasn't sure of how to do this otherwise unless if I sent the packet, waited for the packet's reply, parsed the packet (e.g. got the timing), and so on which would have been slower in my opinion.

     

    Here's the main program's code:

     

    SendPackets.c

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <linux/if.h>
    #include <arpa/inet.h>
    #include <inttypes.h>
    #include <signal.h>
    #include <pthread.h>
    #include <sys/sysinfo.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    #include <string.h>
    #include <sys/time.h>
    #include <time.h>
    #include <math.h>
    #include <getopt.h>
    
    #include "csum.h"
    
    #define MAX_PCKT_LENGTH 0xFFFF  // 65535
    
    static uint8_t cont = 1;
    static uint8_t contR = 1;
    static uint8_t gwMAC[ETH_ALEN];
    static uint64_t sentCount;
    static uint64_t recvCount;
    static uint64_t totalPing;
    static uint64_t minPing;
    static uint64_t maxPing;
    static uint64_t sentDataTotal;
    static uint64_t recvDataTotal;
    static int fanoutid;
    
    struct info
    {
        char *sIP;
        uint16_t sPort;
        char *dIP;
        char *nIP;
        uint16_t nPort;
        char *interface;
        uint64_t interval;
        uint16_t min;
        uint16_t max;
        int output;
        uint16_t rthreads;
        uint16_t sthreads;
        int help;
    } stuff;
    
    static struct option longopts[] =
    {
        {"src", required_argument, NULL, 's'},
        {"sport", required_argument, NULL, 1},
        {"dst", required_argument, NULL, 'd'},
        {"nat", required_argument, NULL, 'n'},
        {"nport", required_argument, NULL, 2},
        {"dev", required_argument, NULL, 'i'},
        {"interval", required_argument, NULL, 3},
        {"min", required_argument, NULL, 4},
        {"max", required_argument, NULL, 5},
        {"rthreads", required_argument, NULL, 6},
        {"sthreads", required_argument, NULL, 7},
        {"output", no_argument, &stuff.output, 'o'},
        {"help", no_argument, &stuff.help, 'h'},
        {NULL, 0, NULL, 0}
    };
    
    void signHdl(int tmp)
    {
        cont = 0;
    }
    
    void GetGatewayMAC()
    {
        // Command to run.
        char cmd[] = "ip neigh | grep \"$(ip -4 route list 0/0 | cut -d' ' -f3) \" | cut -d' ' -f5 | tr '[a-f]' '[A-F]'";
    
        // Execute command.
        FILE *fp =  popen(cmd, "r");
    
        // Check if command is valid.
        if (fp != NULL)
        {
            // Initialize line char.
            char line[18];
    
            // Get output from command.
            if (fgets(line, sizeof(line), fp) != NULL)
            {
                // Parse output and put it into gwMAC.
                sscanf(line, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &gwMAC[0], &gwMAC[1], &gwMAC[2], &gwMAC[3], &gwMAC[4], &gwMAC[5]);
            }
            
            // Close command.
            pclose(fp);
        }
    }
    
    uint16_t randNum(uint16_t min, uint16_t max)
    {
        return (rand() % (max - min + 1)) + min;
    }
    
    
    void *threadSendHdl(void *data)
    {
        int sockfd;
        struct sockaddr_ll din;
    
        din.sll_family = PF_PACKET;
        din.sll_ifindex = if_nametoindex(stuff.interface);
        din.sll_protocol = htons(ETH_P_IP);
    
        if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) < 1)
        {
            perror("socket");
    
            pthread_exit(NULL);
        }
    
        struct ifreq ifr;
        
        strcpy(ifr.ifr_name, stuff.interface);
    
        if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0)
        {
            perror("ioctl");
        }
    
        memcpy(din.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
        din.sll_halen = ETH_ALEN;
    
        if (bind(sockfd, (struct sockaddr *)&din, sizeof(din)) < 0)
        {
            perror("bind");
        }
        
        while (cont)
        {
            uint16_t pcktLen = randNum(stuff.min, stuff.max);
    
            unsigned char buffer[MAX_PCKT_LENGTH];
            memset(buffer, 0, MAX_PCKT_LENGTH);
    
            struct ethhdr *eth = (struct ethhdr *)buffer;
            eth->h_proto = htons(ETH_P_IP);
            memcpy(eth->h_source, din.sll_addr, ETH_ALEN);
            memcpy(eth->h_dest, gwMAC, ETH_ALEN);
    
            struct iphdr *oIP = (struct iphdr *) (buffer + sizeof(struct ethhdr));
            oIP->ihl = 5;
            oIP->version = 4;
            oIP->protocol = IPPROTO_IPIP;
            oIP->frag_off = 0;
            oIP->tos = 0x00;
            oIP->ttl = 64;
            oIP->id = 0;
            oIP->saddr = inet_addr(stuff.sIP);
            oIP->daddr = inet_addr(stuff.dIP);
            oIP->tot_len = htons(sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + pcktLen);
    
            struct iphdr *iIP = (struct iphdr *) (buffer + sizeof(struct ethhdr) + sizeof(struct iphdr));
            iIP->ihl = 5;
            iIP->version = 4;
            iIP->protocol = IPPROTO_UDP;
            iIP->frag_off = 0;
            iIP->tos = 0x00;
            iIP->ttl = 64;
            iIP->id = 0;
            iIP->saddr = inet_addr(stuff.sIP);
            iIP->daddr = inet_addr(stuff.nIP);
            iIP->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + pcktLen);
    
            struct udphdr *udp = (struct udphdr *) (buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr));
            udp->source = htons(stuff.sPort);
            udp->dest = htons(stuff.nPort);
            udp->len = htons(sizeof(struct udphdr) + pcktLen);
    
            oIP->check = 0;
            oIP->check = ip_fast_csum(oIP, oIP->ihl);
            iIP->check = 0;
            iIP->check = ip_fast_csum(iIP, iIP->ihl);
    
            struct timeval tv;
            gettimeofday(&tv, NULL);
    
            unsigned char *header = (unsigned char *)(buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr));
            *header = 'l';
    
            uint64_t *curTime = (uint64_t *)(buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + 1);
            *curTime = 1000000 + tv.tv_sec + tv.tv_usec;
    
            unsigned char *pcktData = (unsigned char *) (buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + 1 + sizeof(uint64_t));
    
            for (uint16_t i = 0; i < (pcktLen - sizeof(uint64_t) - 1); i++)
            {
                *pcktData = rand() % 255;
                *pcktData++;
            }
    
            udp->check = 0;
            udp->check = csum_tcpudp_magic(iIP->saddr, iIP->daddr, sizeof(struct udphdr) + pcktLen, IPPROTO_UDP, csum_partial(udp, sizeof(struct udphdr) + pcktLen, 0));
    
            uint16_t sent;
    
            if ((sent = write(sockfd, buffer, ntohs(oIP->tot_len) + sizeof(struct ethhdr))) < 1)
            {
                perror("sent");
            }
    
            sentDataTotal += sent;
            sentCount++;
    
            if (stuff.interval > 0)
            {
                usleep(stuff.interval);
            }
    
            //fprintf(stdout, "Sent %" PRIu16 " bytes of data to IPIP tunnel\n", sent);
        }
    
        close(sockfd);
    
        pthread_exit(NULL);
    }
    
    void *threadRecvHdl(void *data)
    {
        int sockfd;
        struct sockaddr_ll din;
        struct sockaddr_ll rin;
        socklen_t rinLen = sizeof(rin);
    
        din.sll_family = PF_PACKET;
        din.sll_ifindex = if_nametoindex(stuff.interface);
        din.sll_protocol = htons(ETH_P_IP);
    
        if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 1)
        {
            perror("socket");
    
            pthread_exit(NULL);
        }
    
        struct ifreq ifr;
        
        strcpy(ifr.ifr_name, stuff.interface);
    
        if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0)
        {
            perror("ioctl");
        }
    
        memcpy(din.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
        din.sll_halen = ETH_ALEN;
    
        if (bind(sockfd, (struct sockaddr *)&din, sizeof(din)) < 0)
        {
            perror("bind");
        }
    
        int fanoutarg;
    
        fanoutarg = (fanoutid | (PACKET_FANOUT_HASH << 16));
    
        if (setsockopt(sockfd, SOL_PACKET, PACKET_FANOUT, &fanoutarg, sizeof(fanoutarg)) < 0)
        {
            perror("setsockopt");
    
            pthread_exit(NULL);
        }
        
        while (contR)
        {
            unsigned char buffer[MAX_PCKT_LENGTH];
            memset(buffer, 0, MAX_PCKT_LENGTH);
    
            uint16_t recv;
    
            if ((recv = recvfrom(sockfd, &buffer, MAX_PCKT_LENGTH, 0, (struct sockaddr *)&rin, &rinLen)) < 1)
            {
                perror("recv");
    
                continue;
            }
    
            struct iphdr *oIP = (struct iphdr *) (buffer + sizeof(struct ethhdr));
            
            if (oIP->protocol == IPPROTO_IPIP && oIP->daddr == inet_addr(stuff.sIP))
            {
                struct iphdr *iIP = (struct iphdr *) (buffer + sizeof(struct ethhdr) + sizeof(struct iphdr));
    
                if (iIP->daddr == inet_addr(stuff.sIP))
                {
                    unsigned char *header = (unsigned char *)(buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr));
    
                    if (*header != 'l')
                    {
                        continue;
                    }
    
                    struct timeval tv;
                    gettimeofday(&tv, NULL);
    
                    uint64_t nowTime = 1000000 + tv.tv_sec + tv.tv_usec;
    
                    uint64_t *pcktTime = (uint64_t *)(buffer + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + 1);
    
                    uint64_t ping = nowTime - *pcktTime;
    
                    ping /= 1000;
    
                    if (ping > 100000)
                    {
                        continue;
                    }
    
                    if (stuff.output)
                    {
                        fprintf(stdout, "%" PRIu64 "ms\n", ping);
                    }
    
                    if (ping > maxPing)
                    {
                        maxPing = ping;
                    }
    
                    if (ping < minPing || recvCount < 1)
                    {
                        minPing = ping;
                    }
    
                    totalPing += ping;
    
                    recvDataTotal += recv;
                    recvCount++;
                    
                }
            }
        }
    
        close(sockfd);
    
        pthread_exit(NULL);    
    }
    
    int parse_command_line(int argc, char *argv[])
    {
        uint8_t pass = 0;
    
        int c;
    
        while ((c = getopt_long(argc, argv, "s:d:n:i:oh", longopts, NULL)) != -1)
        {
            switch (c)
            {
                case 's':
                    stuff.sIP = optarg;
    
                    break;
    
                case 1:
                    stuff.sPort = atoi(optarg);
    
                    break;
    
                case 'd':
                    stuff.dIP = optarg;
    
                    break;
    
                case 'n':
                    stuff.nIP = optarg;
    
                    break;
    
                case 2:
                    stuff.nPort = atoi(optarg);
    
                    break;
    
                case 'i':
                    stuff.interface = optarg;
    
                    break;
    
                case 3:
                    stuff.interval = strtoll(optarg, NULL, 10);
    
                    break;
    
                case 4:
                    stuff.min = atoi(optarg);
    
                    break;
    
                case 5:
                    stuff.max = atoi(optarg);
    
                    break;
    
                case 6:
                    stuff.rthreads = atoi(optarg);
    
                    break;
    
                case 7:
                    stuff.sthreads = atoi(optarg);
    
                    break;
    
                case 'o':
                    stuff.output = 1;
    
                    break;
    
                case 'h':
                    stuff.help = 1;
    
                    break;
    
                case '?':
                    pass = -1;
    
                    break;
            }
        }
    
        return pass;
    }
    
    int main(int argc, char *argv[])
    {
        // Set optional defaults.
        stuff.interval = 1000000;
        stuff.max = 1200;
        stuff.min = 500;
        stuff.rthreads = get_nprocs_conf();
        stuff.sthreads = get_nprocs_conf();
    
        if (parse_command_line(argc, argv) != 0)
        {
            exit(EXIT_FAILURE);
        }
    
        if (stuff.help)
        {
            fprintf(stderr, "%s Arguments:\n"
            "-s, --src => Source IP.\n"
            "--sport => Source Port.\n"
            "-d, --dst => Destination IP\n"
            "-n, --nat => NAT IP.\n"
            "--nport => NAT Port.\n"
            "-i, --dev => Network Device Name.\n"
            "--interval => Interval between sent packets.\n"
            "--min => Minimum packet length in bytes.\n"
            "--max => Maximum packet length in bytes.\n"
            "--rthreads => Amount of receiving threads/sockets to spawn.\n"
            "--sthreads => Amount of sending threads/sockets to spawn.\n", argv[0]);
    
            exit(EXIT_SUCCESS);
        }
    
        if (stuff.sIP == NULL)
        {
            fprintf(stderr, "Missing --src option for source IP.\n");
    
            exit(EXIT_FAILURE);
        }
    
        if (stuff.sPort == 0)
        {
            fprintf(stderr, "Missing --sport option for source port or invalid (0).\n");
    
            exit(EXIT_FAILURE);
        }
    
        if (stuff.dIP == NULL)
        {
            fprintf(stderr, "Missing --dst option for destination IP.\n");
    
            exit(EXIT_FAILURE);
        }
    
        if (stuff.nIP == NULL)
        {
            fprintf(stderr, "Missing --nat option for NAT IP.\n");
    
            exit(EXIT_FAILURE);
        }
    
        if (stuff.nPort == 0)
        {
            fprintf(stderr, "Missing --nport option for NAT port or invalid (0).\n");
    
            exit(EXIT_FAILURE);
        }
    
        if (stuff.interface == NULL)
        {
            fprintf(stderr, "Missing --dev option for network device/interface.\n");
    
            exit(EXIT_FAILURE);
        }
    
        time_t startTime = time(NULL);
    
        fanoutid = getpid() & 0xFFFF;
    
        for (uint16_t i = 0; i < stuff.sthreads; i++)
        {
            pthread_t pid;
    
            if (pthread_create(&pid, NULL, threadSendHdl, (void *)&stuff) != 0)
            {
                fprintf(stderr, "Error creating sending thread #%d\n", i);
            }
        }
    
        for (uint16_t i = 0; i < stuff.rthreads; i++)
        {
            pthread_t pid;
    
            if (pthread_create(&pid, NULL, threadRecvHdl, (void *)&stuff) != 0)
            {
                fprintf(stderr, "Error creating receiving thread #%d\n", i);
            }
        }
    
        signal(SIGINT, signHdl);
        signal(SIGABRT, signHdl);
    
        GetGatewayMAC();
    
        while(cont)
        {
            sleep(1);
        }
    
        time_t endTime = time(NULL);
    
        fprintf(stdout, "Cleaning up\n");
    
        sleep(1);
    
        contR = 0;
    
        sleep(1);
    
        time_t totalTime = endTime - startTime;
        uint64_t avgPing = totalPing / recvCount;
    
        uint64_t avgSent = sentDataTotal / totalTime;
        uint64_t avgRecv = recvDataTotal / totalTime;
    
        double pcktLoss = (double) ((double)(sentCount - recvCount) / sentCount);
        pcktLoss *= 100.0;
    
        avgSent /= 125000;
        avgRecv /= 125000;
    
        fprintf(stdout, "%" PRIu64 " packets sent and %" PRIu64 " packets received. %" PRIu64 " packets lost. Average ping was %" PRIu64 ". Max ping was %" PRIu64 " and min ping was %" PRIu64 ".\n", sentCount, recvCount, (sentCount - recvCount), avgPing, maxPing, minPing);
        fprintf(stdout, "Total time -> %lu. Average sent => %" PRIu64 " mbps. Average received => %" PRIu64 " mbps. \n", totalTime, avgSent, avgRecv);
        fprintf(stdout, "Packet Loss => %.2f\%%\n", pcktLoss);
    
        exit(EXIT_SUCCESS);
    }

     

    Here's the output from ./SendPackets -h for a description of the arguments:

     

    root@test02:/home/dev/OutTest# ./SendPackets -h
    ./SendPackets Arguments:
    -s, --src => Source IP.
    --sport => Source Port.
    -d, --dst => Destination IP
    -n, --nat => NAT IP.
    --nport => NAT Port.
    -i, --dev => Network Device Name.
    --interval => Interval between sent packets.
    --min => Minimum packet length in bytes.
    --max => Maximum packet length in bytes.
    --rthreads => Amount of receiving threads/sockets to spawn.
    --sthreads => Amount of sending threads/sockets to spawn.

     

    Here's an example (with real statistics from my local network):

     

    root@test02:/home/dev/OutTest# ./SendPackets --src 10.50.0.3 --sport 27000 --dst 10.50.0.4 -n 10.2.0.5 --nport 27015 -i ens18 --interval 0 --rthreads 4 --sthreads 1
    Cleaning up
    1899149 packets sent and 1855387 packets received. 43762 packets lost. Average ping was 0. Max ping was 31 and min ping was 0.
    Total time -> 77. Average sent => 180 mbps. Average received => 176 mbps.
    Packet Loss => 2.30%
    

     

    Here's another program I made that attaches to the IPIP tunnel and sends back replies:

     

    AckPackets.c

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <linux/if.h>
    #include <arpa/inet.h>
    #include <inttypes.h>
    #include <signal.h>
    #include <pthread.h>
    #include <sys/sysinfo.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    #include <string.h>
    #include <sys/time.h>
    
    #include "csum.h"
    
    #define MAX_PCKT_LENGTH 0xFFFF  // 65535
    
    static uint8_t cont = 1;
    static uint8_t gwMAC[ETH_ALEN];
    static int fanoutid;
    
    struct info
    {
        char *interface;
    };
    
    void signHdl(int tmp)
    {
        cont = 0;
    }
    
    void GetGatewayMAC()
    {
        // Command to run.
        char cmd[] = "ip neigh | grep \"$(ip -4 route list 0/0 | cut -d' ' -f3) \" | cut -d' ' -f5 | tr '[a-f]' '[A-F]'";
    
        // Execute command.
        FILE *fp =  popen(cmd, "r");
    
        // Check if command is valid.
        if (fp != NULL)
        {
            // Initialize line char.
            char line[18];
    
            // Get output from command.
            if (fgets(line, sizeof(line), fp) != NULL)
            {
                // Parse output and put it into gwMAC.
                sscanf(line, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &gwMAC[0], &gwMAC[1], &gwMAC[2], &gwMAC[3], &gwMAC[4], &gwMAC[5]);
            }
            
            // Close command.
            pclose(fp);
        }
    }
    
    void *threadRecvHdl(void *data)
    {
        struct info *stuff = (struct info *) data;
    
        int sockfd, sendSockfd;
        struct sockaddr_ll sin, din;
    
        if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
        {
            perror("RecvSocket");
    
            pthread_exit(NULL);
        }
    
        struct ifreq ifr;
        strcpy(ifr.ifr_name, stuff->interface);
    
        if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0)
        {
            perror("ioctl");
    
            pthread_exit(NULL);
        }
    
        sin.sll_family = PF_PACKET;
        sin.sll_ifindex = if_nametoindex(stuff->interface);
        sin.sll_protocol = htons(ETH_P_IP);
        memcpy(sin.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
        sin.sll_halen = ETH_ALEN;
        socklen_t sinLen = sizeof(sin);
    
        if(bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) != 0)
        {
            perror("bind");
    
            pthread_exit(NULL);
        }
    
        int fanoutarg;
        fanoutarg = (fanoutid | (PACKET_FANOUT_HASH << 16));
    
        if (setsockopt(sockfd, SOL_PACKET, PACKET_FANOUT, &fanoutarg, sizeof(fanoutarg)) < 0)
        {
            perror("setsockopt");
    
            pthread_exit(NULL);
        }
    
        if ((sendSockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) < 0)
        {
            perror("SendSocket");
    
            pthread_exit(NULL);
        }
    
        din.sll_family = PF_PACKET;
        din.sll_ifindex = sin.sll_ifindex;
        din.sll_protocol = htons(ETH_P_IP);
        memcpy(din.sll_addr, sin.sll_addr, ETH_ALEN);
        din.sll_halen = ETH_ALEN;
    
        if (bind(sendSockfd, (struct sockaddr *)&din, sizeof(din)) < 0)
        {
            perror("bind");
    
            pthread_exit(NULL);
        }
    
        while(cont)
        {
            unsigned char buffer[MAX_PCKT_LENGTH];
    
            uint16_t recv;
    
            if ((recv = recvfrom(sockfd, &buffer, MAX_PCKT_LENGTH, 0, (struct sockaddr *)&sin, &sinLen)) < 1)
            {
                perror("recvfrom");
    
                continue;
            }
    
            struct iphdr *ip = (struct iphdr *)(buffer);
            struct udphdr *udp = (struct udphdr *)(buffer + sizeof(struct iphdr));
            uint32_t old = ip->saddr;
            ip->saddr = ip->daddr;
            ip->daddr = old;
            ip->check = 0;
            ip->check = ip_fast_csum(ip, ip->ihl);
    
            udp->check = 0;
            udp->check = csum_tcpudp_magic(ip->saddr, ip->daddr, (recv - sizeof(struct iphdr)), IPPROTO_UDP, csum_partial(udp, (recv - sizeof(struct iphdr)), 0));
    
            uint16_t sent;
    
            if ((sent = write(sendSockfd, buffer, recv)) < 1)
            {
                perror("sent");
    
                continue;
            }
    
            //fprintf(stdout, "Sent %d packet to host.\n", sent);
        }
    
        close(sockfd);
        close(sendSockfd);
    
        pthread_exit(NULL);    
    }
    
    int main(int argc, char *argv[])
    {
        if (argc < 2)
        {
            fprintf(stderr, "Usage: %s <Interface>\n", argv[0]);
    
            exit(1);
        }
    
        fanoutid = getpid() & 0xFFFF;
    
        struct info stuff;
        stuff.interface = argv[1];
    
        for (uint8_t i = 0; i < get_nprocs_conf(); i++)
        {
            pthread_t pid;
    
            if (pthread_create(&pid, NULL, threadRecvHdl, (void *)&stuff) != 0)
            {
                fprintf(stderr, "Error creating receiving thread #%d\n", i);
            }
        }
    
        signal(SIGINT, signHdl);
        signal(SIGABRT, signHdl);
    
        GetGatewayMAC();
    
        while(cont)
        {
            sleep(1);
        }
    
        fprintf(stdout, "Cleaning up\n");
    
        sleep(2);
    
        exit(0);
    }

     

    Usage for this program is ./AckPackets <Interface Name> (e.g. ./AckPackets ens18).

     

    Here's an example of setting up the namespace, IPIP tunnel, and running the AckPackets program:

     

    ip netns add ns01
    ip tunnel add ipip01 mode ipip remote xxx.xxx.xxx.xxx # Replace xxx.xxx.xxx.xxx with remote IP.
    ip link set ipip01 netns ns01
    ip netns exec ns01 ip link set lo up
    ip netns exec ns01 ip addr add 10.2.0.5/32 dev ipip01
    ip netns exec ns01 ip link set ipip01 up
    ip netns exec ns01 ip route add default dev ipip01
    ip netns exec ns01 ./AckPackets ipip01
    ...

     

    The code doesn't include much documentation or comments at the moment. Once I rewrite my UDP Sender program, I'll be adding many documents and comments to it and I'll release it to GitHub.

     

    To build these files, I used GCC like the following:

     

    gcc -g SendPackets.c -o SendPackets -lpthread -lm # SendPackets.c program.
    gcc -g AckPackets.c -o AckPackets -lpthread # AckPackets.c program.

     

    If you have any questions, please let me know!

     

    Thank you.

×
×
  • Create New...