Skip to main content

Ouija

Python relay/proxy server and library to build reliable encrypted TCP/UDP tunnels with entropy control for TCP traffic

pypi version

Features

  • Easy to install, configure and use

  • TCP/UDP tunneling

  • Pluggable traffic ciphers

  • Pluggable traffic entropy control

Hides TCP traffic in encrypted TCP/UDP tunnel between relay and proxy servers

TCP/UDP tunneling

Requirements

  • Python 3.11

  • pbjson 1.18.0

  • cryptography 41.0.2

  • numpy 1.25.2

Install

python3.11 -m venv .env
source .env/bin/activate
pip install ouija

Usage

Generate cipher_key/token secrets:

ouija_secret

Run relay/proxy server:

ouija <config.json>

tcp-relay.json - TCP relay server - HTTP/HTTPS proxy server interface with TCP connectors:

{
  "protocol": "TCP",
  "mode": "RELAY",
  "debug": true,
  "monitor": true,
  "relay_host": "127.0.0.1",
  "relay_port": 9000,
  "proxy_host": "127.0.0.1",
  "proxy_port": 50000,
  "cipher_key": "bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI=",
  "entropy_rate": 5,
  "token": "395f249c-343a-4f92-9129-68c6d83b5f55",
  "serving_timeout": 20.0,
  "tcp_buffer": 1024,
  "tcp_timeout": 1.0,
  "message_timeout": 5.0
}

tcp-proxy.json - TCP-relayed proxy server:

{
  "protocol": "TCP",
  "mode": "PROXY",
  "debug": true,
  "monitor": true,
  "proxy_host": "0.0.0.0",
  "proxy_port": 50000,
  "cipher_key": "bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI=",
  "entropy_rate": 5,
  "token": "395f249c-343a-4f92-9129-68c6d83b5f55",
  "serving_timeout": 20.0,
  "tcp_buffer": 1024,
  "tcp_timeout": 1.0,
  "message_timeout": 5.0
}

udp-relay.json - UDP relay server - HTTP/HTTPS proxy server interface with UDP connectors:

{
  "protocol": "UDP",
  "mode": "RELAY",
  "debug": true,
  "monitor": true,
  "relay_host": "127.0.0.1",
  "relay_port": 9000,
  "proxy_host": "127.0.0.1",
  "proxy_port": 50000,
  "cipher_key": "bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI=",
  "entropy_rate": 5,
  "token": "395f249c-343a-4f92-9129-68c6d83b5f55",
  "serving_timeout": 20.0,
  "tcp_buffer": 1024,
  "tcp_timeout": 1.0,
  "udp_min_payload": 512,
  "udp_max_payload": 1024,
  "udp_timeout": 2.0,
  "udp_retries": 5,
  "udp_capacity": 10000,
  "udp_resend_sleep": 0.25
}

udp-proxy.json - UDP-relayed proxy server:

{
  "protocol": "UDP",
  "mode": "PROXY",
  "debug": true,
  "monitor": true,
  "proxy_host": "0.0.0.0",
  "proxy_port": 50000,
  "cipher_key": "bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI=",
  "entropy_rate": 5,
  "token": "395f249c-343a-4f92-9129-68c6d83b5f55",
  "serving_timeout": 20.0,
  "tcp_buffer": 1024,
  "tcp_timeout": 1.0,
  "udp_min_payload": 512,
  "udp_max_payload": 1024,
  "udp_timeout": 2.0,
  "udp_retries": 5,
  "udp_capacity": 10000,
  "udp_resend_sleep": 0.25
}

Relay and proxy setup configuration with supervisord - ouija-config

Cipher and entropy

  • cipher_key - FernetCipher key - use ouija_secret to generate key

  • entropy_rate - SimpleEntropy rate, when rate=N every Nth byte will be generated and payload size will increase, rate=5 means 20% traffic overhead

Protocols

  • Stream - TCP

  • Datagram - UDP

Entities

  • Cipher - cipher implementation - FernetCipher out of the box

  • Entropy - entropy control implementation - SimpleEntropy out of the box

  • Tuning - relay/proxy and connector/link interaction settings

  • Relay - HTTPS proxy server interface

  • Connector - relay connector, which communicates with proxy link

  • Proxy - proxy server, which gets requests from relay and sends back responses from remote servers

  • Link - proxy link with relay connector

Tuning - TCP

  • cipher - cipher instance, if None then no encryption will be applied

  • entropy - entropy instance, if None then no entropy control will be applied

  • token - your secret token - UUID4 or anything else - use ouija_secret to generate token

  • serving_timeout - timeout for serve/resend workers, 2X for handlers, seconds

  • tcp_buffer - TCP buffer size, bytes

  • tcp_timeout - TCP awaiting timeout, seconds

  • message_timeout - TCP service message timeout, seconds

Tuning - UDP

  • cipher - cipher instance, if None then no encryption will be applied

  • entropy - entropy instance, if None then no entropy control will be applied

  • token - your secret token - UUID4 or anything else - use ouija_secret to generate token

  • serving_timeout - timeout for serve/resend workers, 2X for handlers, seconds

  • tcp_buffer - TCP buffer size, bytes

  • tcp_timeout - TCP awaiting timeout, seconds

  • udp_min_payload - UDP min payload size, bytes

  • udp_max_payload - UDP max payload size, bytes

  • udp_timeout - UDP awaiting timeout, seconds

  • udp_retries - UDP max retry count per interaction

  • udp_capacity - UDP send/receive buffer capacity - max packet count

  • udp_resend_sleep - UDP resend sleep between retries, seconds

Library usage

stream-relay.py - TCP relay server - HTTP/HTTPS proxy server interface with TCP connectors:

import asyncio
import logging

from ouija import StreamRelay as Relay, StreamTuning as Tuning, Telemetry, SimpleEntropy, FernetCipher


async def main() -> None:
    tuning = Tuning(
        cipher=FernetCipher(key='bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI='),
        entropy=SimpleEntropy(rate=5),
        token='395f249c-343a-4f92-9129-68c6d83b5f55',
        serving_timeout=20.0,
        tcp_buffer=1024,
        tcp_timeout=1.0,
        message_timeout=5.0,
    )
    relay = Relay(
        telemetry=Telemetry(),
        tuning=tuning,
        relay_host='127.0.0.1',
        relay_port=9000,
        proxy_host='127.0.0.1',
        proxy_port=50000,
    )
    asyncio.create_task(relay.debug())
    await relay.serve()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.run_forever()

stream-proxy.py - TCP-relayed proxy server:

import asyncio
import logging

from ouija import StreamProxy as Proxy, Telemetry, StreamTuning as Tuning, SimpleEntropy, FernetCipher


async def main() -> None:
    tuning = Tuning(
        cipher=FernetCipher(key='bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI='),
        entropy=SimpleEntropy(rate=5),
        token='395f249c-343a-4f92-9129-68c6d83b5f55',
        serving_timeout=20.0,
        tcp_buffer=1024,
        tcp_timeout=1.0,
        message_timeout=5.0,
    )
    proxy = Proxy(
        telemetry=Telemetry(),
        tuning=tuning,
        proxy_host='0.0.0.0',
        proxy_port=50000,
    )
    asyncio.create_task(proxy.debug())
    await proxy.serve()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.run_forever()

datagram-relay.py - UDP relay server - HTTPS proxy server interface with UDP connectors:

import asyncio
import logging

from ouija import DatagramRelay as Relay, DatagramTuning as Tuning, Telemetry, SimpleEntropy, FernetCipher


async def main() -> None:
    tuning = Tuning(
        cipher=FernetCipher(key='bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI='),
        entropy=SimpleEntropy(rate=5),
        token='395f249c-343a-4f92-9129-68c6d83b5f55',
        serving_timeout=20.0,
        tcp_buffer=1024,
        tcp_timeout=1.0,
        udp_min_payload=512,
        udp_max_payload=1024,
        udp_timeout=2.0,
        udp_retries=5,
        udp_capacity=10000,
        udp_resend_sleep=0.25,
    )
    relay = Relay(
        telemetry=Telemetry(),
        tuning=tuning,
        relay_host='127.0.0.1',
        relay_port=9000,
        proxy_host='127.0.0.1',
        proxy_port=50000,
    )
    asyncio.create_task(relay.debug())
    await relay.serve()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.run_forever()

datagram-proxy.py - UDP-relayed proxy server:

import asyncio
import logging

from ouija import DatagramProxy as Proxy, Telemetry, DatagramTuning as Tuning, SimpleEntropy, FernetCipher


async def main() -> None:
    tuning = Tuning(
        cipher=FernetCipher(key='bdDmN4VexpDvTrs6gw8xTzaFvIBobFg1Cx2McFB1RmI='),
        entropy=SimpleEntropy(rate=5),
        token='395f249c-343a-4f92-9129-68c6d83b5f55',
        serving_timeout=20.0,
        tcp_buffer=1024,
        tcp_timeout=1.0,
        udp_min_payload=512,
        udp_max_payload=1024,
        udp_timeout=2.0,
        udp_retries=5,
        udp_capacity=10000,
        udp_resend_sleep=0.25,
    )
    proxy = Proxy(
        telemetry=Telemetry(),
        tuning=tuning,
        proxy_host='0.0.0.0',
        proxy_port=50000,
    )
    asyncio.create_task(proxy.debug())
    await proxy.serve()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.run_forever()

Tests

pytest --cov-report html:htmlcov --cov=ouija tests/

Metadata

Release files for ouija 1.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ouija 1.3.1
File Size Uploaded
ouija-1.3.1.tar.gz 22.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ouija 1.3.1
File Interpreter ABI Platform
ouija-1.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 41.5 kB

Release files / ouija-1.3.1.tar.gz

Download URL ouija-1.3.1.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8277b6724364377a4bafd108c3c92953ce4a3c21fcee1595460515f81d395324
BLAKE2b-256 checksum
How to use checksums
467300c4798ec9623919dd61e1a7bffc32ca3b03faabdde8d48a5552928d7952
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.4

Release files / ouija-1.3.1-py3-none-any.whl

Download URL ouija-1.3.1-py3-none-any.whl
Size 18.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ac8d9c87700f581d4867131137da0cd4f6553f53fd1946364d36e1d018b917c1
BLAKE2b-256 checksum
How to use checksums
2358f59c78bff705b071cfb659bb0b268d9ac1ddedbbb6695142d37386c12c72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.4

Release history Release notifications | RSS feed

This release

1.3.1 This release

2 release files

1.3.0

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page