├── README.md ├── dockergen ├── README.md ├── dockergen.conf └── update-netns.sh.tmpl ├── images ├── gflsev3 │ ├── Dockerfile │ ├── README.md │ └── entrypoint.sh ├── gflsev4 │ ├── Dockerfile │ ├── README.md │ └── entrypoint.sh ├── gflsev5 │ ├── Dockerfile │ ├── README.md │ └── entrypoint.sh └── gmod64 │ ├── Dockerfile │ ├── README.md │ └── entrypoint.sh └── misc ├── compressor_updater ├── README.md └── update.sh └── gttoffload_notify ├── README.md └── ddosnotify.sh /README.md: -------------------------------------------------------------------------------- 1 | # Anycast Endpoint Setup 2 | ## Description 3 | This repository will store all needed Docker images, Docker Gen configuration files, and more to complete our Anycast endpoint setup for Compressor (soon to be BiFrost). -------------------------------------------------------------------------------- /dockergen/README.md: -------------------------------------------------------------------------------- 1 | # Docker Gen Configuration 2 | ## Description 3 | This directory includes our Docker Gen configuration. 4 | 5 | ## Installation 6 | Firstly, install Docker Gen. A guide on this can be found [here](https://gitlab.com/-/snippets/1836688). 7 | 8 | Secondly, copy `dockergen.conf` and `update-netns.sh.tmpl` to `/etc/netns-dockergen/`. 9 | 10 | Lastly, start/restart the Docker Gen service via `systemctl restart netns-dockergen`. 11 | 12 | ## Notes 13 | If you're using Pterodactyl, make sure to create variables `ANYCAST_ADDR` and `INTERNAL_IP`. The `ANYCAST_ADDR` should be set to the public IP address from the Anycast network associated with the container/game server (e.g. 92.119.148.4). The `INTERNAL_IP` variable should be set to the IPIP tunnel's IP (`internal_ip` in Compressor's configuration) for the specific container/game server (e.g. `172.20.0.2`). The internal IP should be a part of a private IP range (LAN). 14 | 15 | ## Credits 16 | * [Dreae](https://github.com/Dreae) - Created base configuration. 17 | * [Christian Deacon](https://www.linkedin.com/in/christian-deacon-902042186/) - Modified configuration to suit GFL's needs. -------------------------------------------------------------------------------- /dockergen/dockergen.conf: -------------------------------------------------------------------------------- 1 | [[config]] 2 | watch = true 3 | notifycmd = "/bin/bash /tmp/update-netns.sh" 4 | template = "/etc/netns-dockergen/update-netns.sh.tmpl" 5 | dest = "/tmp/update-netns.sh" -------------------------------------------------------------------------------- /dockergen/update-netns.sh.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | {{ $containerLen := len . }} 4 | {{ if gt $containerLen 0 }} 5 | {{ range $key, $value := . }} 6 | id="{{ .ID }}" 7 | 8 | {{ if .Env.ANYCAST_ADDR }} 9 | serverUpdating="0" 10 | {{ if .Env.SERVERUPDATE }} 11 | {{ if or (eq .Env.SERVERUPDATE "1") (eq .Env.SERVERUPDATE "2") }} 12 | serverUpdating="1" 13 | {{ end }} 14 | {{ end }} 15 | 16 | {{ $addrLen := len .Env.ANYCAST_ADDR }} 17 | {{ if gt $addrLen 0 }} 18 | 19 | # Check if the server is updating. 20 | if [ "$serverUpdating" -eq "0" ]; then 21 | pid=`docker inspect $id | jq '.[0].State.Pid'` 22 | mkdir -p /var/run/netns 23 | rm -f /var/run/netns/$id 24 | ln -s /proc/$pid/ns/net /var/run/netns/$id 25 | 26 | remoteIp="{{ .Env.ANYCAST_ADDR }}" 27 | internalIp="{{ .Env.INTERNAL_IP }}" 28 | tunnelName="tf-${id:0:10}" 29 | 30 | # Attempt to create the IPIP tunnel every second until it is created. 31 | val=0 32 | try=0 33 | 34 | while [[ "$val" == 0 ]]; do 35 | ip tunnel del $tunnelName 36 | ip tunnel add $tunnelName mode ipip remote $remoteIp 37 | ip link set $tunnelName promisc on 38 | ip link set $tunnelName netns $id 39 | ip netns exec $id ip link set $tunnelName up 40 | ip netns exec $id ip addr add $internalIp/32 dev $tunnelName 41 | result=$? 42 | 43 | if [ $result -eq 0 ]; then 44 | val=1 45 | fi 46 | 47 | if [[ "$try" > 5 ]]; then 48 | val=1 49 | fi 50 | 51 | try=try+1 52 | 53 | sleep 1 54 | done 55 | 56 | ip netns exec $id ip route del default 57 | ip netns exec $id ip route add default dev $tunnelName 58 | fi 59 | {{ end }} 60 | {{ end }} 61 | {{ end }} 62 | 63 | {{ else }} 64 | 65 | ip netns | while read line; do 66 | docker inspect $line 67 | if [ $? -ne 0 ]; then 68 | tunnelName="tf-${line:0:10}" 69 | ip netns del $line 70 | ip tunnel del $tunnelName 71 | fi 72 | done 73 | {{ end }} -------------------------------------------------------------------------------- /images/gflsev3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | # Install Dependencies 5 | RUN dpkg --add-architecture i386 \ 6 | && apt-get update \ 7 | && apt-get upgrade -y \ 8 | && apt-get install -y tar curl gcc g++ lib32gcc1 lib32tinfo5 lib32z1 lib32stdc++6 libtinfo5:i386 libncurses5:i386 libcurl3-gnutls:i386 gdb lsof iproute2 iptables \ 9 | && useradd -m -d /home/container container \ 10 | && mkdir -p /tmp/dumps && chmod -R 777 /tmp/ \ 11 | && chown root:root /tmp/dumps 12 | 13 | 14 | USER container 15 | ENV HOME /home/container 16 | WORKDIR /home/container 17 | 18 | COPY ./entrypoint.sh /entrypoint.sh 19 | CMD ["/bin/bash", "/entrypoint.sh"] 20 | -------------------------------------------------------------------------------- /images/gflsev3/README.md: -------------------------------------------------------------------------------- 1 | # GFL Source Engine V3 2 | ## Description 3 | A Docker image GFL is using for its servers hosted on its Anycast network. 4 | 5 | ## Notes 6 | If using Pterodactyl, make sure to add a variable with the name `SERVERUPDATE`. If set to `1` or `2`, the IPIP tunnel will not attach allowing the server to bind to the Docker veth interface and all inbound traffic would go into the machine directly instead of through the tunnel (Anycast network). 7 | 8 | If set to `1`, the server will update. If set to `2`, the server will update and also validate its installation. 9 | 10 | You may also set a `MOUNT_DEST` which can be used after changes performed in [this](https://gflclan.com/forums/topic/48643-pterodactyl-mount-multiple-volumes-to-container/) thread. 11 | 12 | ## Building 13 | You may build this image executing the following command as root (or using `sudo`): 14 | 15 | ``` 16 | docker build -t gflsev3:latest . 17 | ``` 18 | 19 | ## Available On Docker Hub 20 | This image is available on Docker Hub. You may download it with: 21 | 22 | ``` 23 | docker pull gamemann/gflsev3 24 | ``` -------------------------------------------------------------------------------- /images/gflsev3/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 3 3 | 4 | # Set Ulimit 5 | ulimit -c unlimited 6 | echo "Set: ulimit -c unlimited" 7 | 8 | # Set the default working directory. 9 | workingDir=/home/container 10 | 11 | # Check if the MOUNT_DEST variable exists. If so, set it to that. 12 | if [ ! -z "$MOUNT_DEST" ]; then 13 | workingDir=$MOUNT_DEST 14 | fi 15 | 16 | echo "Changing working directory to ${workingDir}" 17 | 18 | cd $workingDir 19 | 20 | # Update or validate server. 21 | if [ "$SERVERUPDATE" = "1" ]; then 22 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} +quit 23 | elif [ "$SERVERUPDATE" = "2" ]; then 24 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} validate +quit 25 | fi 26 | 27 | # Replace Startup Variables 28 | MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` 29 | echo ":${workingDir}$ ${MODIFIED_STARTUP}" 30 | 31 | # Run the Server 32 | ${MODIFIED_STARTUP} 33 | 34 | if [ $? -ne 0 ]; then 35 | echo "PTDL_CONTAINER_ERR: There was an error while attempting to run the start command." 36 | exit 1 37 | fi -------------------------------------------------------------------------------- /images/gflsev4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | # Install Dependencies 5 | RUN dpkg --add-architecture i386 \ 6 | && apt-get update \ 7 | && apt-get upgrade -y \ 8 | && apt-get install -y tar curl gcc g++ lib32gcc1 lib32tinfo5 lib32z1 lib32stdc++6 libtinfo5:i386 libncurses5:i386 libcurl3-gnutls:i386 gdb lsof iproute2 iptables \ 9 | && useradd -m -d /home/container container \ 10 | && mkdir -p /tmp/dumps && chmod -R 777 /tmp/ \ 11 | && chown root:root /tmp/dumps 12 | 13 | 14 | USER container 15 | ENV HOME /home/container 16 | WORKDIR /home/container 17 | 18 | COPY ./entrypoint.sh /entrypoint.sh 19 | CMD ["/bin/bash", "/entrypoint.sh"] 20 | -------------------------------------------------------------------------------- /images/gflsev4/README.md: -------------------------------------------------------------------------------- 1 | # GFL Source Engine V4 2 | ## Description 3 | A Docker image GFL is using for its servers hosted on its Anycast network. 4 | 5 | ## Notes 6 | If using Pterodactyl, make sure to add a variable with the name `SERVERUPDATE`. If set to `1` or `2`, the IPIP tunnel will not attach allowing the server to bind to the Docker veth interface and all inbound traffic would go into the machine directly instead of through the tunnel (Anycast network). 7 | 8 | If set to `1`, the server will update. If set to `2`, the server will update and also validate its installation. 9 | 10 | You may also set a `MOUNT_DEST` which can be used after changes performed in [this](https://gflclan.com/forums/topic/48643-pterodactyl-mount-multiple-volumes-to-container/) thread. 11 | 12 | ## Building 13 | You may build this image executing the following command as root (or using `sudo`): 14 | 15 | ``` 16 | docker build -t gflsev4:latest . 17 | ``` -------------------------------------------------------------------------------- /images/gflsev4/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 7 3 | 4 | # Set Ulimit 5 | ulimit -c unlimited 6 | echo "Set: ulimit -c unlimited" 7 | 8 | # Set the default working directory. 9 | workingDir=/home/container 10 | 11 | # Check if the MOUNT_DEST variable exists. If so, set it to that. 12 | if [ ! -z "$MOUNT_DEST" ]; then 13 | workingDir=$MOUNT_DEST 14 | fi 15 | 16 | echo "Changing working directory to ${workingDir}" 17 | 18 | cd $workingDir 19 | 20 | # Update or validate server. 21 | if [ "$SERVERUPDATE" = "2" ]; then 22 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} validate +quit 23 | elif [ "$SERVERUPDATE" = "1" ]; then 24 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} +quit 25 | fi 26 | 27 | # Replace Startup Variables 28 | MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` 29 | echo ":${workingDir}$ ${MODIFIED_STARTUP}" 30 | 31 | # Run the Server 32 | ${MODIFIED_STARTUP} 33 | 34 | if [ $? -ne 0 ]; then 35 | echo "PTDL_CONTAINER_ERR: There was an error while attempting to run the start command." 36 | exit 1 37 | fi -------------------------------------------------------------------------------- /images/gflsev5/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | # Install Dependencies 5 | RUN dpkg --add-architecture i386 \ 6 | && apt-get update \ 7 | && apt-get upgrade -y \ 8 | && apt-get install -y tar curl gcc g++ lib32gcc1 lib32tinfo5 lib32z1 lib32stdc++6 libtinfo5:i386 libncurses5:i386 libcurl3-gnutls:i386 gdb lsof iproute2 iptables \ 9 | && useradd -m -d /home/container container \ 10 | && mkdir -p /tmp/dumps && chmod -R 777 /tmp/ \ 11 | && chown root:root /tmp/dumps 12 | 13 | 14 | USER container 15 | ENV HOME /home/container 16 | WORKDIR /home/container 17 | 18 | COPY ./entrypoint.sh /entrypoint.sh 19 | CMD ["/bin/bash", "/entrypoint.sh"] 20 | -------------------------------------------------------------------------------- /images/gflsev5/README.md: -------------------------------------------------------------------------------- 1 | # GFL Source Engine V5 2 | ## Description 3 | A Docker image GFL is using for its servers hosted on its Anycast network. 4 | 5 | ## Notes 6 | If using Pterodactyl, make sure to add a variable with the name `SERVERUPDATE`. If set to `1` or `2`, the IPIP tunnel will not attach allowing the server to bind to the Docker veth interface and all inbound traffic would go into the machine directly instead of through the tunnel (Anycast network). 7 | 8 | If set to `1`, the server will update. If set to `2`, the server will update and also validate its installation. 9 | 10 | You may also set a `MOUNT_DEST` which can be used after changes performed in [this](https://gflclan.com/forums/topic/48643-pterodactyl-mount-multiple-volumes-to-container/) thread. 11 | 12 | ## Differences Between V4 and V5? 13 | In this image, we wait until a device with the internal IP is available. This hopefully will result in less times where the container shuts down because the server cannot bind to the internal IP. 14 | 15 | ## Building 16 | You may build this image executing the following command as root (or using `sudo`): 17 | 18 | ``` 19 | docker build -t gflsev4:latest . 20 | ``` -------------------------------------------------------------------------------- /images/gflsev5/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if internal IP exists within container. 4 | val=0 5 | 6 | while [[ "$val" == 0 ]]; do 7 | cmds=$(ip a | grep $INTERNAL_IP) 8 | result=$? 9 | 10 | if [ $result -eq 0 ]; then 11 | val=1 12 | fi 13 | 14 | sleep 1 15 | done 16 | 17 | # Set Ulimit 18 | ulimit -c unlimited 19 | echo "Set: ulimit -c unlimited" 20 | 21 | # Set the default working directory. 22 | workingDir=/home/container 23 | 24 | # Check if the MOUNT_DEST variable exists. If so, set it to that. 25 | if [ ! -z "$MOUNT_DEST" ]; then 26 | workingDir=$MOUNT_DEST 27 | fi 28 | 29 | echo "Changing working directory to ${workingDir}" 30 | 31 | cd $workingDir 32 | 33 | # Update or validate server. 34 | if [ "$SERVERUPDATE" = "2" ]; then 35 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} validate +quit 36 | elif [ "$SERVERUPDATE" = "1" ]; then 37 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update ${CSRCDS_APPID} +quit 38 | fi 39 | 40 | # Replace Startup Variables 41 | MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` 42 | echo ":${workingDir}$ ${MODIFIED_STARTUP}" 43 | 44 | # Run the Server 45 | ${MODIFIED_STARTUP} 46 | 47 | if [ $? -ne 0 ]; then 48 | echo "PTDL_CONTAINER_ERR: There was an error while attempting to run the start command." 49 | exit 1 50 | fi -------------------------------------------------------------------------------- /images/gmod64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | LABEL author="Xy" maintainer="contact@xytime.xyz" 4 | 5 | ENV DEBIAN_FRONTEND noninteractive 6 | RUN dpkg --add-architecture i386 \ 7 | && apt-get update \ 8 | && apt-get upgrade -y \ 9 | && apt-get install -y tar curl gcc g++ lib32gcc1 libgcc1 libcurl4-gnutls-dev:i386 libssl1.1:i386 libcurl4:i386 libtinfo5:i386 lib32z1 lib32stdc++6 libncurses5:i386 libcurl3-gnutls:i386 iproute2 gdb libsdl1.2debian libfontconfig telnet net-tools netcat git \ 10 | && useradd -m -d /home/container container 11 | 12 | USER container 13 | ENV HOME /home/container 14 | WORKDIR /home/container 15 | 16 | COPY ./entrypoint.sh /entrypoint.sh 17 | CMD ["/bin/bash", "/entrypoint.sh"] 18 | -------------------------------------------------------------------------------- /images/gmod64/README.md: -------------------------------------------------------------------------------- 1 | Using this image with pterodactyl is easy: 2 | 3 | 1) Swap out the default container image for your GMOD server. You can build the image yourself or you can use quay.io/xytime/gmod64 4 | 2) Add 64-Bit Linux versions of any binary modules you're using to lua/bin. 5 | 3) Change the binary invoked by the startup line from srcds_run to srcds_run_x64 6 | -------------------------------------------------------------------------------- /images/gmod64/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 5 3 | 4 | # Allow for the creation of coredumps 5 | ulimit -c unlimited 6 | 7 | cd /home/container 8 | 9 | # Update or validate server. 10 | if [ "$SERVERUPDATE" = "1" ]; then 11 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update 4020 -beta x86-64 +quit 12 | elif [ "$SERVERUPDATE" = "2" ]; then 13 | ./steamcmd/steamcmd.sh +login anonymous +force_install_dir /home/container +app_update 4020 validate -beta x86-64 +quit 14 | fi 15 | 16 | # Replace Startup Variables 17 | MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` 18 | echo ":/home/container$ ${MODIFIED_STARTUP}" 19 | 20 | # Run the Server 21 | ${MODIFIED_STARTUP} 22 | 23 | if [ $? -ne 0 ]; then 24 | echo "PTDL_CONTAINER_ERR: There was an error while attempting to run the start command." 25 | exit 1 26 | fi 27 | -------------------------------------------------------------------------------- /misc/compressor_updater/README.md: -------------------------------------------------------------------------------- 1 | # Compressor Updater 2 | ## Description 3 | A small Bash script I made to update Compressor's config automatically. This also includes the functionality to check the status of Compressor on all servers specified, restart Compressor, and run custom commands. 4 | 5 | ## Config 6 | You must add an entry to the Bash array for each server. An example would be like the following: 7 | 8 | ```bash 9 | declare -a PoPs=( 10 | "user1@127.0.0.1" 11 | "user2@server2.local" 12 | ) 13 | ``` 14 | 15 | ## Usage 16 | The script takes one required argument which is the action and a second optional argument for custom commands. 17 | 18 | ### Updating Config 19 | Make sure you have a `compressor.conf` file in the same directory as the script and run: 20 | 21 | ``` 22 | ./update UPDATE 23 | ``` 24 | 25 | This will replace the `/etc/compressor/compressor.conf` file on the servers listed inside the Bash array with the local `compressor.conf` file and restart the Compressor service. 26 | 27 | ### Checking Status 28 | If you want to check the status of the Compressor service on all servers, run: 29 | 30 | ``` 31 | ./update STATUS 32 | ``` 33 | 34 | ### Restarting Compressor 35 | If you want to restart Compressor on all servers without updating the config, run: 36 | 37 | ``` 38 | ./update RESTART 39 | ``` 40 | 41 | ### Custom Commands 42 | If you want to run a custom command such as `uname -r` on all servers, use `CUSTOM` at the first argument followed by the custom command in single quotes for the second argument. Here's an example: 43 | 44 | ``` 45 | ./update CUSTOM 'uname -r' 46 | ``` 47 | 48 | ## Credits 49 | * [Christian Deacon](https://github.com/gamemann) -------------------------------------------------------------------------------- /misc/compressor_updater/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define all the PoP servers. 4 | declare -a PoPs=( 5 | #"user@host" 6 | #"me@127.0.0.1" 7 | ) 8 | 9 | # Loop through each PoP. 10 | for i in "${PoPs[@]}" 11 | do 12 | if [ "$1" = "UPDATE" ]; then 13 | echo "Updating $i..." 14 | 15 | # Copy compressor config to remote PoP. 16 | scp compressor.conf $i:/tmp/compressor.conf.temp 17 | 18 | # Move the file to appropriate location. 19 | ssh -t $i 'sudo mv /tmp/compressor.conf.temp /etc/compressor/compressor.conf' 20 | 21 | # Clear the RAM cache before restarting so there's a less chance it'll cause Compressor to die. 22 | ssh -t $i 'sudo su -c "sync; echo 3 > /proc/sys/vm/drop_caches"' 23 | 24 | # Restart Compressor. 25 | ssh -t $i 'sudo systemctl restart compressor --no-pager' 26 | 27 | # Grab the status. 28 | ssh -t $i 'sudo systemctl status compressor --no-pager' 29 | 30 | echo "Done updating..." 31 | 32 | elif [ "$1" = "UPDATENORESTART" ]; then 33 | echo "Updating $i without Compressor restart..." 34 | 35 | # Copy compressor config to remote PoP. 36 | scp compressor.conf $i:/tmp/compressor.conf.temp 37 | 38 | # Move the file to appropriate location. 39 | ssh -t $i 'sudo mv /tmp/compressor.conf.temp /etc/compressor/compressor.conf' 40 | 41 | echo "Done updating..." 42 | elif [ "$1" = "CLEARCACHE" ]; then 43 | echo "Clearing $i RAM cache..." 44 | 45 | # Clear the RAM cache. 46 | ssh -t $i 'sudo su -c "sync; echo 3 > /proc/sys/vm/drop_caches"' 47 | 48 | # Done clearing cache. 49 | 50 | elif [ "$1" = "STATUS" ]; then 51 | echo "Status for $i" 52 | 53 | # Grab the status. 54 | ssh -t $i 'sudo systemctl status compressor --no-pager' 55 | elif [ "$1" = "RESTART" ]; then 56 | echo "Restarting compressor for $i" 57 | 58 | # Clear the RAM cache so there's a less chance of Compressor dying. 59 | ssh -t $i 'sudo su -c "sync; echo 3 > /proc/sys/vm/drop_caches"' 60 | 61 | # Restart Compressor. 62 | ssh -t $i 'sudo systemctl restart compressor --no-pager' 63 | 64 | # Grab the status. 65 | ssh -t $i 'sudo systemctl status compressor --no-pager' 66 | 67 | echo "Done restarting..." 68 | 69 | elif [ "$1" = "CUSTOM" ]; then 70 | echo "Running custom command" 71 | 72 | # Running custom command. 73 | ssh -t $i $2 74 | fi 75 | done 76 | -------------------------------------------------------------------------------- /misc/gttoffload_notify/README.md: -------------------------------------------------------------------------------- 1 | # GTT Offload Notify 2 | ## Description 3 | A temporary bash script I made for our GSK POP to notify us on when GSK pushes policies to GTT to offload single `/32` IPs on our network. This happens when GSK detects a (D)DoS attack. It then sends a cURL POST request to a Discord Web Hook I made in GFL's internal Discord server to notify us for when an attack occurs. 4 | 5 | This is somewhat unreliable, but a solution that works for right now. You will need to edit the bash file and modify the webhook URL along with the group ID (note - `%26` represents the `&` character in the message contents for a role mention). -------------------------------------------------------------------------------- /misc/gttoffload_notify/ddosnotify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Listening for route changes indicating attacks..." 4 | 5 | # Initialize starting variables. 6 | timestamps=() 7 | i=1 8 | 9 | # Make an infinite loop (but we sleep every 60 seconds or so to avoid high CPU consumption). 10 | while [ "$i" -ne 0 ]; do 11 | # Verbose. 12 | echo "Scanning..." 13 | 14 | # Get contents of BGP routes from BIRD. 15 | contents=$(birdc show route) 16 | 17 | # Loop through each new line. 18 | while IFS= read -r; do 19 | # Try to find a match on the IP with a /32 prefix since GTT offloads are only for single IPs (/32) at the moment. 20 | ip=$(echo "$REPLY" | grep -P -o "([0-9]{1,3}\.)+([0-9]{1,3})(?=/32)") 21 | 22 | # Check size of $ip variable (if it's above 1, it matched). 23 | if [[ ${#ip} > 1 ]]; then 24 | # Get timestamp. 25 | ts=$(echo "$REPLY" | grep -P -o "[0-9]{2}:[0-9]{2}") 26 | 27 | # Check if timestamp is a part of $timestamps array. 28 | if [[ ! " ${timestamps[@]} " =~ " $ip-$ts " ]]; then 29 | # Logging. 30 | echo "Detected attack against $ip with $ts as the timestamp. Adding timestamp to array and going forward." 31 | 32 | # Add timestamp to timestamps array. 33 | timestamps+=("$ip-$ts") 34 | 35 | # Construct cURL request. 36 | msg="<@%26xxxxxxxxxxxxx> Attack detected on $ip. GTT offload is enabled on this IP for an hour on GSK's behalf." 37 | 38 | curl -s -d "content=$msg" -X POST https://discordapp.com/api/webhooks/xxxxxxxxxxxx/yyyyyyyyyyyyyyyyyyyyyyyyyy 39 | fi 40 | fi 41 | done <<< "$contents" 42 | 43 | sleep 60 44 | done --------------------------------------------------------------------------------