Giter Club home page Giter Club logo

anti_vpn's Introduction

anti_vpn

Minetest mod to block connections from known VPN egress IPs

Usage

  1. Register for a "free tier" API KEY at https://vpnapi.io/. This entitles you to make 1000 lookups "per day". Read their terms and conditions.

  2. Install this mod into your world.

  3. Add the following to your minetest.conf file:

    anti_vpn.provider.vpnapi.apikey = YOUR_PRIVATE_API_KEY_HERE.
    anti_vpn.provider.vpnapi.url = https://vpnapi.io
    anti_vpn.kick_text = Any extra text you want appended to the kick message.
    

    Also add anti_vpn to secure.http_mods.

  4. Restart your Minetest server.

Theory of Operation

The anti_vpn mod registers three callbacks:

  1. on_prejoinplayer - Called before a player even authenticates. Is passed their username and IP address.
  2. on_playerjoin - Called after the player is logged in and about to spawn in the world.
  3. after - used to running periodic functions.

When a player prejoins, the mod instantly checks the VPN lookup cache. If the IP address belongs to a known VPN, the prejoin is rejected. If the IP address is unknown to the cache, then a background lookup (external http request) is initiated, and the prejoin is allowed to proceed.

When a player joins, the same lookup is performed, and if the player's IP address is a VPN endpoint, then the player is kicked.

When the HTTP request is finished, the cache is updated, but no players are instantly kicked. The HTTP response can arrive before, during or after a player has logged in, and its easier to just catch these players during the periodic worker (via minetest.after()).

The periodic callback checks the IP address for each connected player, and kicks any that map to a VPN.

Chat Commands

Chat commands require the staff privilege (not registered with this mod).

  • /anti_vpn add IPV4_ADDRESS

    Queues a lookup for the given IP address.

  • /anti_vpn cleanup

    Initiate a background "cleanup" of the cached data. Currently, this refetches all IP address lookups that were missing a 'country' or 'asn' (from an earlier version of this mod).

  • /anti_vpn flush

    Forcably flushes data to mod_storage, and if enabled, raw JSON text files. Normally the mod will flush data after each lookup. This command was added to aide in development/debugging.

  • /anti_vpn ip VERB LIST...

    Apply action 'VERB' to the LIST of objects (space separated IP addresses or player names). If the list contains a name of a connected player, their IP address is used. Any other items in the LIST are ignored.

    VERBS:

    • add - Queue a remote lookup of each IP address from the list.

    • del or delete or rm - Remove cached results for each IP address in the list. Note that the next time a player from this IP address connects, the IP address will be automatically queued for a remote lookup.

    • allow - Allow connections from IP addresses in the list (ignore results of the remote lookup).

    • deny - Block connections from IP addresses in the list (ignore results of the remote lookup).

    Note: The only purpose for accepting player names with the ip command is to obtain their IP addresses. Blocking by player name is not implemented with the ip command.

  • /anti_vpn mode [NEW_MODE]

    Reports the current operating mode, or sets it to a new value:

    • off - Mod is effectively disabled. No join/prejoin/async checks are performed, no HTTP requests are send.

    • dryrun - Mod performs all normal behavior, except that players are not actually blocked of kicked. Useful for testing the mode before "going live".

    • enforce - Mod performs all normal behavior, and will actively block or kick players who are connecting/connected from banned IPs.

  • /anti_vpn stats

    Report some generic stats via chat. If you have any better ideas, please send a pull request.

    Ex: anti_vpn stats: total: 101, blocked: 4 (3.9604%)

Misc

  1. Check logs by looking for the string anti_vpn:

    $ grep -a anti_vpn ~/.minetest/debug.log

  2. A cache of IPs is in ${WORLD}/mod_storage/anti_vpn (JSON format).

Manual testing.

  1. Edit the local testdata_player_ip table near the top of api.lua. Add a test username and an IP that you would like the anti_vpn mod to think that they are coming from, even though the real network will use the real IP address. Ex:

    local testdata_player_ip = {
      vpn_user = '185.253.162.14',
      lan_user = '10.0.0.1',
      non_vpn_user = '67.84.231.116',
    }
    
  2. To avoid consuming calls via your APIKEY, and you test during development by using a small (included) python web server that pretends to be "vpnapi.io".

    1. Create a directory called testdata and populate it with a few manual lookups. Ex:

      $ mkdir testdata
      $ export APIKEY=xxxxxxxxxxxx
      $ for IP in 1.1.1.1 8.8.8.8 185.253.162.14; do \
          wget -q -O testdata/${IP}.json \
            https://vpnapi.io/api/${IP}?key=${APIKEY}; \
        done
      
    2. Edit minetest.conf:

      1. Add anti_vpn.provider.vpnapi.url = http://localhost:48888.
      2. Add anti_vpn.debug.json = true.
      3. Add anti_vpn to secure.http_mods.
    3. Run the python script. It runs in the foreground.

    4. Edit anti_vpn/api.lua and add some fake user/IP mappings to testdata_player_ip (see above).

    5. Start a minetest server.

    6. Connect to the minetest server and conduct your testing.

    7. Examine JSON dump of anti_vpn's data (requires anti_vpn.debug.json = true):

      # Dump raw data:
      $ jq < ${WORLD_DIR}/anti_vpn_ip_data.json
      $ jq < ${WORLD_DIR}/anti_vpn_players.json
      
      # List all IPs that were detected as a VPN endpoint:
      $ jq -r 'keys[] as $k | .[$k] | select(.blocked) | $k' < \
        ${WORLD_DIR}/anti_vpn_ip_data.json
      
      # List all IPs that were manually entered:
      $ jq -r 'keys[] as $k | .[$k] | select(.provider == "manual") | {ip: $k, blocked: .blocked}' < \
        ${WORLD_DIR}/anti_vpn_ip_data.json
      

anti_vpn's People

Contributors

dennisjenkins75 avatar

Watchers

 avatar Buckaroo Banzai avatar

anti_vpn's Issues

Add mechanism to change the operating mode of this mod.

Add a chat command /anti_vpn mode $MODE to allow changing the "mode":

  • enforce - Players connecting from detected VPNs are kicked.
  • dryrun - Mod operates as fully as possible, but without warning or kicking players.
  • off - Mode is disabled. No remote lookups are done.

Mode should be changeable on the fly, and the mode should be persistent (store flag in mod_storage).

Add ability to override block/allow on a per-player basis

Add ability to specify rules that apply to a player, that can override a VPN lookup:

  • Allow-list a player, and ignore any IP address info.
  • Deny-list a player, and ignore any IP address info.
  • Lock a player to a subset of ASNs.
    • If the player connects from an IP that is not in the per-player ASN allow list, then reject/kick the connection.
  • (hyper-specific to EdenLost as of 2023-01) Lock a password-less player.
    • See https://github.com/EdenLostMinetest/password_auditor
    • I had to (temp) ban ~11k accounts for having no or weak passwords. I'd like to unban them. However, I need to prevent a certain VPN user who as a partial list of these accounts from abusing them. This is my plan:
    • If the player logs in with a blank password, and they are NOT connecting from the per-player ASN allow list, then kick them.
    • If they login with no password from an allowed ASN, then prompt them to change their password (via a different mod).
    • Write a tool to compute the player/ASN list from historic server logs (2022-01-04 through 2022-09-04), and automate the /xunban actions.

Suggested chat command forms:

/anti_vpn player allow Player1 Player2 ...
/anti_vpn player deny PlayerX PlayerY ...
/anti_vpn player lock Player ASN1 ASN2 ...
/anti_vpn player unlock Player1 Player2 ...

Add chat command for overriding VPN lookup results

The VPNAPI provider is sometimes wrong. Although we can still /xban an IP address, I'd rather this mod provide a mechanism for overriding a VPN determination.

There is an existing chat command /anti_vpn add $IP that simply asks the backend to queue a lookup of an IP. Plan is to replace this command with a new one: /anti_vpn ip $VERB $IP_LIST. IP_LIST is s space-separated list of IPV4 addresses. VERB is one of:

  • add - Queue a remote lookup of all IPs in the list.
  • del - Remove the IPs from our cache.
  • allow - Declare that the IPs are "allowed to connect" (eg, not VPNs). They are added to the cache if not already there.
  • deny - Declare that the IPs should be blocked from connecting. They are added to the cache if not already there.

HTTP2 errors after random amount of uptime

I've also observed this with the geoip mod. After some (random?) amount of time, minetest will 100% fail to fetch any URLs from the http server for these mods (geoip, anti_vpn), returning an error that looks like:

2023-01-01 09:59:14: WARNING[CurlFetch]: https://vpnapi.io/api/90.210.243.11?key=REDACTED not found (Error in the HTTP2 framing layer) (response code 0)
2023-01-01 09:59:14: ERROR[Server]: [anti_vpn] HTTP request failed: {
        succeeded = false,
        code = 0,
        completed = true,
        timeout = false,
        data = ""
}

I attempted to reproduce the issue with https://github.com/EdenLostMinetest/http_api_test, but it won't repro in a stand-alone mod. After thinking about it some more, and reviewing the logs again, I thought of something. When the HTTP requests are perfectly serialized, they work fine. But if a new one starts in parallel with an existing one, then they sometimes fail.

anti_vpn is capable of firing off multiple, simultaneous, requests. I should modify i so that it keeps a "queue", and only ever attempts to perform ONE lookup at a time. Furthermore, it can rate-limit itself if done this way.

Need to gate requests to external HTTP lookups.

Player who are rapidly logging in from the same IP address will cause multiple requests for the same lookup to be "in flight" at the same time. This mod should add pending requests to a table, and only issue a new request if there is not already one for the same IP. once the HTTP response is received, the entry can be removed from that table.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.