Merge branch 'master' of https://github.com/alterware/master-server
This commit is contained in:
commit
6048d9f1c2
93
.github/workflows/build.yml
vendored
93
.github/workflows/build.yml
vendored
@ -3,10 +3,12 @@ name: Build
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "*"
|
- "**"
|
||||||
|
tags:
|
||||||
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "*"
|
- "**"
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@ -58,7 +60,11 @@ jobs:
|
|||||||
uses: ammaraskar/msvc-problem-matcher@master
|
uses: ammaraskar/msvc-problem-matcher@master
|
||||||
|
|
||||||
- name: Build ${{matrix.arch}} ${{matrix.configuration}} binaries
|
- name: Build ${{matrix.arch}} ${{matrix.configuration}} binaries
|
||||||
|
<<<<<<< HEAD
|
||||||
run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=${{matrix.platform}} build/master-server.sln
|
run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=${{matrix.platform}} build/master-server.sln
|
||||||
|
=======
|
||||||
|
run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=${{matrix.platform}} build/alterware-master.sln
|
||||||
|
>>>>>>> 27c2b2b75b56e54dcfbec690dd086946a45587d7
|
||||||
|
|
||||||
- name: Upload ${{matrix.arch}} ${{matrix.configuration}} binaries
|
- name: Upload ${{matrix.arch}} ${{matrix.configuration}} binaries
|
||||||
uses: actions/upload-artifact@main
|
uses: actions/upload-artifact@main
|
||||||
@ -162,17 +168,28 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: macos-${{matrix.arch}}-${{matrix.configuration}}
|
name: macos-${{matrix.arch}}-${{matrix.configuration}}
|
||||||
path: |
|
path: |
|
||||||
|
<<<<<<< HEAD
|
||||||
build/bin/${{matrix.arch}}/${{matrix.configuration}}/master-server
|
build/bin/${{matrix.arch}}/${{matrix.configuration}}/master-server
|
||||||
|
=======
|
||||||
|
build/bin/${{matrix.arch}}/${{matrix.configuration}}/alterware-master
|
||||||
|
>>>>>>> 27c2b2b75b56e54dcfbec690dd086946a45587d7
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy artifacts
|
name: Deploy artifacts
|
||||||
needs: [build-win, build-linux, build-macos]
|
needs: [build-win, build-linux, build-macos]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
<<<<<<< HEAD
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
- name: Setup main environment
|
- name: Setup main environment
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
run: echo "MASTER_SERVER_PATH=${{ secrets.MASTER_SERVER_SSH_PATH }}" >> $GITHUB_ENV
|
run: echo "MASTER_SERVER_PATH=${{ secrets.MASTER_SERVER_SSH_PATH }}" >> $GITHUB_ENV
|
||||||
|
=======
|
||||||
|
if: github.ref_type == 'tag'
|
||||||
|
steps:
|
||||||
|
- name: Setup main environment
|
||||||
|
run: echo "ALTERWARE_MASTER_SERVER_PATH=${{ secrets.ALTERWARE_MASTER_SERVER_SSH_PATH }}" >> $GITHUB_ENV
|
||||||
|
>>>>>>> 27c2b2b75b56e54dcfbec690dd086946a45587d7
|
||||||
|
|
||||||
- name: Download Release binaries
|
- name: Download Release binaries
|
||||||
uses: actions/download-artifact@main
|
uses: actions/download-artifact@main
|
||||||
@ -182,6 +199,7 @@ jobs:
|
|||||||
- name: Install SSH key
|
- name: Install SSH key
|
||||||
uses: shimataro/ssh-key-action@v2.7.0
|
uses: shimataro/ssh-key-action@v2.7.0
|
||||||
with:
|
with:
|
||||||
|
<<<<<<< HEAD
|
||||||
key: ${{ secrets.MASTER_SERVER_SSH_PRIVATE_KEY }}
|
key: ${{ secrets.MASTER_SERVER_SSH_PRIVATE_KEY }}
|
||||||
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
||||||
|
|
||||||
@ -193,3 +211,74 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish changes
|
- name: Publish changes
|
||||||
run: ssh ${{ secrets.MASTER_SERVER_SSH_USER }}@${{ secrets.MASTER_SERVER_SSH_ADDRESS }} ${{ secrets.SSH_SERVER_PUBLISH_COMMAND }}
|
run: ssh ${{ secrets.MASTER_SERVER_SSH_USER }}@${{ secrets.MASTER_SERVER_SSH_ADDRESS }} ${{ secrets.SSH_SERVER_PUBLISH_COMMAND }}
|
||||||
|
=======
|
||||||
|
key: ${{ secrets.ALTERWARE_MASTER_SERVER_SSH_PRIVATE_KEY }}
|
||||||
|
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
||||||
|
|
||||||
|
- name: Add known hosts
|
||||||
|
run: ssh-keyscan -H ${{ secrets.ALTERWARE_MASTER_SERVER_SSH_ADDRESS }} >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Upload release binary
|
||||||
|
run: rsync -avz alterware-master ${{ secrets.ALTERWARE_MASTER_SERVER_SSH_USER }}@${{ secrets.ALTERWARE_MASTER_SERVER_SSH_ADDRESS }}:${{ env.ALTERWARE_MASTER_SERVER_PATH }}/
|
||||||
|
|
||||||
|
- name: Publish changes
|
||||||
|
run: ssh ${{ secrets.ALTERWARE_MASTER_SERVER_SSH_USER }}@${{ secrets.ALTERWARE_MASTER_SERVER_SSH_ADDRESS }} ${{ secrets.ALTERWARE_SSH_SERVER_PUBLISH_COMMAND }}
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Create Docker Image
|
||||||
|
needs: [build-win, build-linux, build-macos]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref_type == 'tag'
|
||||||
|
steps:
|
||||||
|
- name: Check out files
|
||||||
|
uses: actions/checkout@main
|
||||||
|
with:
|
||||||
|
sparse-checkout: |
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
|
sparse-checkout-cone-mode: false
|
||||||
|
|
||||||
|
- name: Download Release binaries
|
||||||
|
uses: actions/download-artifact@main
|
||||||
|
|
||||||
|
- name: Compress Binaries
|
||||||
|
run: |
|
||||||
|
for dir in */; do
|
||||||
|
if [[ $dir == *"windows"* ]]; then
|
||||||
|
cd "$dir" && zip -r "../${dir%/}.zip" . && cd ..
|
||||||
|
else
|
||||||
|
tar -czvf "${dir%/}.tar.gz" -C "$dir" .
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.2.0
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v3.1.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USER }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- id: meta
|
||||||
|
uses: docker/metadata-action@v5.5.1
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
alterware/master-server
|
||||||
|
tags: |
|
||||||
|
${{ github.ref_name }}
|
||||||
|
latest
|
||||||
|
|
||||||
|
- name: Build and Push Docker Image
|
||||||
|
id: build-and-push
|
||||||
|
uses: docker/build-push-action@v5.1.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
>>>>>>> 27c2b2b75b56e54dcfbec690dd086946a45587d7
|
||||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -19,4 +19,8 @@
|
|||||||
[submodule "deps/curl"]
|
[submodule "deps/curl"]
|
||||||
path = deps/curl
|
path = deps/curl
|
||||||
url = https://github.com/curl/curl.git
|
url = https://github.com/curl/curl.git
|
||||||
branch = curl-8_7_1
|
<<<<<<< HEAD
|
||||||
|
branch = curl-8_7_1
|
||||||
|
=======
|
||||||
|
branch = curl-8_7_1
|
||||||
|
>>>>>>> 27c2b2b75b56e54dcfbec690dd086946a45587d7
|
||||||
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y libc++-dev libcurl4-gnutls-dev
|
||||||
|
|
||||||
|
COPY --chmod=755 ./linux-x64-release/alterware-master /usr/local/bin/
|
||||||
|
|
||||||
|
RUN groupadd alterware-master && useradd -r -g alterware-master alterware-master
|
||||||
|
USER alterware-master
|
||||||
|
|
||||||
|
EXPOSE 20810/udp
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/alterware-master"]
|
@ -4,6 +4,13 @@
|
|||||||
# Master Server
|
# Master Server
|
||||||
This is the master server our clients use. It is based on the DP Master Server (ID Tech) protocol
|
This is the master server our clients use. It is based on the DP Master Server (ID Tech) protocol
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Run using [Docker][docker-link]
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 20810:20810/udp alterware/master-server:latest
|
||||||
|
```
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
- Install [Premake5][premake5-link] and add it to your system PATH
|
- Install [Premake5][premake5-link] and add it to your system PATH
|
||||||
- Clone this repository using [Git][git-link]
|
- Clone this repository using [Git][git-link]
|
||||||
@ -18,6 +25,7 @@ Requirements for Unix systems:
|
|||||||
- Customization: Modifications to the Premake5.lua script may be required
|
- Customization: Modifications to the Premake5.lua script may be required
|
||||||
- Platform support: Details regarding supported platforms are available in [build.yml][build-link]
|
- Platform support: Details regarding supported platforms are available in [build.yml][build-link]
|
||||||
|
|
||||||
|
[docker-link]: https://www.docker.com
|
||||||
[premake5-link]: https://premake.github.io
|
[premake5-link]: https://premake.github.io
|
||||||
[git-link]: https://git-scm.com
|
[git-link]: https://git-scm.com
|
||||||
[mold-link]: https://github.com/rui314/mold
|
[mold-link]: https://github.com/rui314/mold
|
||||||
|
@ -36,7 +36,7 @@ namespace crypto_key
|
|||||||
|
|
||||||
if (!utils::io::write_file("./private.key", key.serialize()))
|
if (!utils::io::write_file("./private.key", key.serialize()))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to write server key!");
|
console::error("Failed to write server key!");
|
||||||
}
|
}
|
||||||
|
|
||||||
console::info("Generated cryptographic key: %llX", key.get_hash());
|
console::info("Generated cryptographic key: %llX", key.get_hash());
|
||||||
|
@ -30,6 +30,7 @@ void elimination_handler::run_frame()
|
|||||||
(server.state == game_server::state::can_ping && diff > 15min))
|
(server.state == game_server::state::can_ping && diff > 15min))
|
||||||
{
|
{
|
||||||
context.remove();
|
context.remove();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.game == game_type::unknown)
|
if (server.game == game_type::unknown)
|
||||||
@ -43,6 +44,7 @@ void elimination_handler::run_frame()
|
|||||||
console::log("Removing T7 server '%s' because they are using an outdated protocol (%i)", context.get_address().to_string().data(), server.protocol);
|
console::log("Removing T7 server '%s' because they are using an outdated protocol (%i)", context.get_address().to_string().data(), server.protocol);
|
||||||
#endif
|
#endif
|
||||||
context.remove();
|
context.remove();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++server_count[server.game][context.get_address().to_string(false)];
|
++server_count[server.game][context.get_address().to_string(false)];
|
||||||
@ -50,6 +52,18 @@ void elimination_handler::run_frame()
|
|||||||
{
|
{
|
||||||
console::log("Removing server '%s' because it exceeds MAX_SERVERS_PER_GAME", context.get_address().to_string().data());
|
console::log("Removing server '%s' because it exceeds MAX_SERVERS_PER_GAME", context.get_address().to_string().data());
|
||||||
context.remove();
|
context.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = utils::string::to_lower(server.name);
|
||||||
|
for (const auto& entry : bad_names)
|
||||||
|
{
|
||||||
|
if (const auto pos = name.find(entry); pos != std::string::npos)
|
||||||
|
{
|
||||||
|
console::log("Removing server '%s' (%s) because it contains a bad name", server.name.data(), context.get_address().to_string().data());
|
||||||
|
context.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto name = utils::string::to_lower(server.name);
|
const auto name = utils::string::to_lower(server.name);
|
||||||
|
@ -1,153 +1,159 @@
|
|||||||
#include "std_include.hpp"
|
#include "std_include.hpp"
|
||||||
#include "kill_list.hpp"
|
#include "kill_list.hpp"
|
||||||
|
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
constexpr auto* kill_file = "./kill.txt";
|
constexpr auto* kill_file = "./kill.txt";
|
||||||
|
|
||||||
kill_list::kill_list_entry::kill_list_entry(std::string ip_address, std::string reason)
|
kill_list::kill_list_entry::kill_list_entry(std::string ip_address, std::string reason)
|
||||||
: ip_address_(std::move(ip_address)), reason_(std::move(reason))
|
: ip_address_(std::move(ip_address)), reason_(std::move(reason))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool kill_list::contains(const network::address& address, std::string& reason)
|
bool kill_list::contains(const network::address& address, std::string& reason)
|
||||||
{
|
{
|
||||||
auto str_address = address.to_string(false);
|
auto str_address = address.to_string(false);
|
||||||
|
|
||||||
return this->entries_container_.access<bool>([&str_address, &reason](const kill_list_entries& entries)
|
return this->entries_container_.access<bool>([&str_address, &reason](const kill_list_entries& entries)
|
||||||
{
|
{
|
||||||
if (const auto itr = entries.find(str_address); itr != entries.end())
|
if (const auto itr = entries.find(str_address); itr != entries.end())
|
||||||
{
|
{
|
||||||
reason = itr->second.reason_;
|
reason = itr->second.reason_;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_list::add_to_kill_list(const kill_list_entry& add)
|
void kill_list::add_to_kill_list(const kill_list_entry& add)
|
||||||
{
|
{
|
||||||
const auto any_change = this->entries_container_.access<bool>([&add](kill_list_entries& entries)
|
const auto any_change = this->entries_container_.access<bool>([&add](kill_list_entries& entries)
|
||||||
{
|
{
|
||||||
const auto existing_entry = entries.find(add.ip_address_);
|
const auto existing_entry = entries.find(add.ip_address_);
|
||||||
if (existing_entry == entries.end() || existing_entry->second.reason_ != add.reason_)
|
if (existing_entry == entries.end() || existing_entry->second.reason_ != add.reason_)
|
||||||
{
|
{
|
||||||
console::info("Added %s to kill list (reason: %s)", add.ip_address_.data(), add.reason_.data());
|
console::info("Added %s to kill list (reason: %s)", add.ip_address_.data(), add.reason_.data());
|
||||||
entries[add.ip_address_] = add;
|
entries[add.ip_address_] = add;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!any_change)
|
if (!any_change)
|
||||||
{
|
{
|
||||||
console::info("%s already in kill list, doing nothing", add.ip_address_.data());
|
console::info("%s already in kill list, doing nothing", add.ip_address_.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->write_to_disk();
|
this->write_to_disk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_list::remove_from_kill_list(const network::address& remove)
|
void kill_list::remove_from_kill_list(const network::address& remove)
|
||||||
{
|
{
|
||||||
this->remove_from_kill_list(remove.to_string());
|
this->remove_from_kill_list(remove.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_list::remove_from_kill_list(const std::string& remove)
|
void kill_list::remove_from_kill_list(const std::string& remove)
|
||||||
{
|
{
|
||||||
const auto any_change = this->entries_container_.access<bool>([&remove](kill_list_entries& entries)
|
const auto any_change = this->entries_container_.access<bool>([&remove](kill_list_entries& entries)
|
||||||
{
|
{
|
||||||
if (entries.erase(remove))
|
if (entries.erase(remove))
|
||||||
{
|
{
|
||||||
console::info("Removed %s from kill list", remove.data());
|
console::info("Removed %s from kill list", remove.data());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!any_change)
|
if (!any_change)
|
||||||
{
|
{
|
||||||
console::info("%s not in kill list, doing nothing", remove.data());
|
console::info("%s not in kill list, doing nothing", remove.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->write_to_disk();
|
this->write_to_disk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_list::reload_from_disk()
|
void kill_list::reload_from_disk()
|
||||||
{
|
{
|
||||||
std::string contents;
|
std::string contents;
|
||||||
if (!utils::io::read_file(kill_file, &contents))
|
if (!utils::io::read_file(kill_file, &contents))
|
||||||
{
|
{
|
||||||
console::info("Could not find %s, kill list will not be loaded.", kill_file);
|
console::info("Could not find %s, kill list will not be loaded.", kill_file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::istringstream string_stream(contents);
|
std::istringstream string_stream(contents);
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
this->entries_container_.access([&string_stream, &line](kill_list_entries& entries)
|
this->entries_container_.access([&string_stream, &line](kill_list_entries& entries)
|
||||||
{
|
{
|
||||||
entries.clear();
|
entries.clear();
|
||||||
while (std::getline(string_stream, line))
|
while (std::getline(string_stream, line))
|
||||||
{
|
{
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
{
|
{
|
||||||
// comments or ignored line
|
// comments or ignored line
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ip;
|
std::string ip;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
|
|
||||||
const auto index = line.find(' ');
|
const auto index = line.find(' ');
|
||||||
if (index != std::string::npos)
|
if (index != std::string::npos)
|
||||||
{
|
{
|
||||||
ip = line.substr(0, index);
|
ip = line.substr(0, index);
|
||||||
comment = line.substr(index + 1);
|
comment = line.substr(index + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ip = line;
|
ip = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip.empty())
|
if (ip.empty())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double line breaks from windows' \r\n
|
// Double line breaks from windows' \r\n
|
||||||
if (ip[ip.size() - 1] == '\r')
|
if (ip[ip.size() - 1] == '\r')
|
||||||
{
|
{
|
||||||
ip.pop_back();
|
ip.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.emplace(ip, kill_list_entry(ip, comment));
|
entries.emplace(ip, kill_list_entry(ip, comment));
|
||||||
}
|
}
|
||||||
|
|
||||||
console::info("Loaded %zu kill list entries from %s", entries.size(), kill_file);
|
console::info("Loaded %zu kill list entries from %s", entries.size(), kill_file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_list::write_to_disk()
|
void kill_list::write_to_disk()
|
||||||
{
|
{
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
this->entries_container_.access([&stream](const kill_list_entries& entries)
|
this->entries_container_.access([&stream](const kill_list_entries& entries)
|
||||||
{
|
{
|
||||||
for (const auto& [ip, entry] : entries)
|
for (const auto& [ip, entry] : entries)
|
||||||
{
|
{
|
||||||
stream << entry.ip_address_ << " " << entry.reason_ << "\n";
|
stream << entry.ip_address_ << " " << entry.reason_ << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::io::write_file(kill_file, stream.str(), false);
|
if (utils::io::write_file(kill_file, stream.str(), false))
|
||||||
console::info("Wrote %s to disk (%zu entries)", kill_file, entries.size());
|
{
|
||||||
});
|
console::info("Wrote %s to disk (%zu entries)", kill_file, entries.size());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
kill_list::kill_list(server& server) : service(server)
|
{
|
||||||
{
|
console::error("Failed to write %s!", kill_file);
|
||||||
this->reload_from_disk();
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
kill_list::kill_list(server& server) : service(server)
|
||||||
|
{
|
||||||
|
this->reload_from_disk();
|
||||||
|
}
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <network/address.hpp>
|
#include <network/address.hpp>
|
||||||
|
|
||||||
#include "../service.hpp"
|
#include "../service.hpp"
|
||||||
|
|
||||||
class kill_list : public service
|
class kill_list : public service
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class kill_list_entry
|
class kill_list_entry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
kill_list_entry() = default;
|
kill_list_entry() = default;
|
||||||
kill_list_entry(std::string ip_address, std::string reason);
|
kill_list_entry(std::string ip_address, std::string reason);
|
||||||
|
|
||||||
std::string ip_address_;
|
std::string ip_address_;
|
||||||
std::string reason_;
|
std::string reason_;
|
||||||
};
|
};
|
||||||
|
|
||||||
kill_list(server& server);
|
kill_list(server& server);
|
||||||
|
|
||||||
bool contains(const network::address& address, std::string& reason);
|
bool contains(const network::address& address, std::string& reason);
|
||||||
void add_to_kill_list(const kill_list_entry& add);
|
void add_to_kill_list(const kill_list_entry& add);
|
||||||
void remove_from_kill_list(const network::address& remove);
|
void remove_from_kill_list(const network::address& remove);
|
||||||
void remove_from_kill_list(const std::string& remove);
|
void remove_from_kill_list(const std::string& remove);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using kill_list_entries = std::unordered_map<std::string, kill_list_entry>;
|
using kill_list_entries = std::unordered_map<std::string, kill_list_entry>;
|
||||||
utils::concurrency::container<kill_list_entries> entries_container_;
|
utils::concurrency::container<kill_list_entries> entries_container_;
|
||||||
|
|
||||||
void reload_from_disk();
|
void reload_from_disk();
|
||||||
void write_to_disk();
|
void write_to_disk();
|
||||||
};
|
};
|
||||||
|
@ -1,65 +1,65 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "patch_kill_list_command.hpp"
|
#include "patch_kill_list_command.hpp"
|
||||||
|
|
||||||
#include "crypto_key.hpp"
|
#include "crypto_key.hpp"
|
||||||
#include "services/kill_list.hpp"
|
#include "services/kill_list.hpp"
|
||||||
|
|
||||||
#include <utils/parameters.hpp>
|
#include <utils/parameters.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
const char* patch_kill_list_command::get_command() const
|
const char* patch_kill_list_command::get_command() const
|
||||||
{
|
{
|
||||||
return "patchkill";
|
return "patchkill";
|
||||||
}
|
}
|
||||||
|
|
||||||
// patchkill timestamp signature add/remove target_ip (ban_reason)
|
// patchkill timestamp signature add/remove target_ip (ban_reason)
|
||||||
void patch_kill_list_command::handle_command([[maybe_unused]] const network::address& target, const std::string_view& data)
|
void patch_kill_list_command::handle_command([[maybe_unused]] const network::address& target, const std::string_view& data)
|
||||||
{
|
{
|
||||||
const utils::parameters params(data);
|
const utils::parameters params(data);
|
||||||
if (params.size() < 3)
|
if (params.size() < 3)
|
||||||
{
|
{
|
||||||
throw execution_exception("Invalid parameter count");
|
throw execution_exception("Invalid parameter count");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto supplied_timestamp = std::chrono::seconds(std::stoul(params[0]));
|
const auto supplied_timestamp = std::chrono::seconds(std::stoul(params[0]));
|
||||||
const auto current_timestamp = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
const auto current_timestamp = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
|
||||||
// Abs the duration so that the client can be ahead or behind
|
// Abs the duration so that the client can be ahead or behind
|
||||||
const auto time_stretch = std::chrono::abs(current_timestamp - supplied_timestamp);
|
const auto time_stretch = std::chrono::abs(current_timestamp - supplied_timestamp);
|
||||||
|
|
||||||
// not offset by more than 5 minutes in either direction
|
// not offset by more than 5 minutes in either direction
|
||||||
if (time_stretch > 5min)
|
if (time_stretch > 5min)
|
||||||
{
|
{
|
||||||
throw execution_exception(utils::string::va("Invalid timestamp supplied - expected %llu, got %llu, which is more than 5 minutes apart", current_timestamp.count(), supplied_timestamp.count()));
|
throw execution_exception(utils::string::va("Invalid timestamp supplied - expected %llu, got %llu, which is more than 5 minutes apart", current_timestamp.count(), supplied_timestamp.count()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& signature = utils::cryptography::base64::decode(params[1]);
|
const auto& signature = utils::cryptography::base64::decode(params[1]);
|
||||||
const auto should_remove = params[2] == "remove"s;
|
const auto should_remove = params[2] == "remove"s;
|
||||||
|
|
||||||
if (!should_remove && params[2] != "add"s)
|
if (!should_remove && params[2] != "add"s)
|
||||||
{
|
{
|
||||||
throw execution_exception("Invalid parameter #2: should be 'add' or 'remove'");
|
throw execution_exception("Invalid parameter #2: should be 'add' or 'remove'");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto supplied_reason = params.join(4);
|
const auto supplied_reason = params.join(4);
|
||||||
const auto& crypto_key = crypto_key::get();
|
const auto& crypto_key = crypto_key::get();
|
||||||
const auto signature_candidate = std::to_string(supplied_timestamp.count());
|
const auto signature_candidate = std::to_string(supplied_timestamp.count());
|
||||||
|
|
||||||
if (!utils::cryptography::ecc::verify_message(crypto_key, signature_candidate, signature))
|
if (!utils::cryptography::ecc::verify_message(crypto_key, signature_candidate, signature))
|
||||||
{
|
{
|
||||||
throw execution_exception("Signature verification of the kill list patch key failed");
|
throw execution_exception("Signature verification of the kill list patch key failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto kill_list_service = this->get_server().get_service<kill_list>();
|
const auto kill_list_service = this->get_server().get_service<kill_list>();
|
||||||
const auto& supplied_address = params[3];
|
const auto& supplied_address = params[3];
|
||||||
|
|
||||||
if (should_remove)
|
if (should_remove)
|
||||||
{
|
{
|
||||||
kill_list_service->remove_from_kill_list(supplied_address);
|
kill_list_service->remove_from_kill_list(supplied_address);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kill_list_service->add_to_kill_list(kill_list::kill_list_entry(supplied_address, supplied_reason));
|
kill_list_service->add_to_kill_list(kill_list::kill_list_entry(supplied_address, supplied_reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user