Skip to content

Latest commit

 

History

History
612 lines (396 loc) · 12.4 KB

API.md

File metadata and controls

612 lines (396 loc) · 12.4 KB

neosocksd API Reference

Version: dev

RESTful API

  1. The RESTful API server runs HTTP/1.1.
  2. The content length limit for a single request is 4 MiB.

/healthy

  • Method: Any
  • Status: HTTP 200

Check server liveness.

/stats

  • Method: GET, POST
  • Query:
    • nobanner: omit the banner, default to 0.
    • server: show server statistics, default to 1.
    • q: argument for ruleset.stats.
  • Status: HTTP 200
  • Response: Server statistics in text/plain.

GET: Get the stateless server statistics.

POST: Calculate server statistics since the last request.

/ruleset/invoke

  • Method: POST
  • Content: Lua script
  • Status: HTTP 200, HTTP 500

Run the POSTed script.

/ruleset/rpcall

  • Method: POST
  • Content: application/x-neosocksd-rpc
  • Status: HTTP 200, HTTP 500
  • Response: Invocation results.

Internal API reserved for await.invoke.

/ruleset/update

  • Method: POST
  • Query:
    • module: replace a loaded Lua module, like libruleset.
    • chunkname: chunk name for stack traceback, like %40libruleset.lua.
  • Content: Lua ruleset script or Lua module script
  • Status: HTTP 200, HTTP 500

Load the posted script and use it as follows:

  1. If module name is not specified, replace the ruleset.
  2. If module name is specified, replace the named Lua module.
  3. If the field _G.name refers to the named module, update it.

/ruleset/gc

  • Method: POST
  • Content: None
  • Status: HTTP 200

Trigger the garbage collector to free some memory.

Ruleset Callbacks

ruleset.resolve

Synopsis

function ruleset.resolve(domain)
    return "www.example.org:80", "http://203.0.113.1:8080", ..., "socks4a://[2001:DB8::1]:1080"
end

Description

Process a host name request. Specifically:

  • Any HTTP CONNECT
  • SOCKS5 with host name (a.k.a. "socks5h")
  • Any SOCKS4A

This callback is called from an asynchronous routine.

Params

  • domain: full qualified domain name and port, like "www.example.org:80"

Returns

  • addr: replace the request
  • addr, proxy: forward the request through another proxy
  • addr, proxyN, ..., proxy1: forward the request through proxy chain
  • nil: reject the request

The proxy addresses are specified in URI format, supported scheme:

  • socks4a://example.org:1080: SOCKS4A server. The implementation is SOCKS4 compatible when requesting IPv4 address.
  • socks5://example.org:1080: SOCKS5 server.
  • http://example.org:8080: HTTP/1.1 CONNECT server.

ruleset.route

Synopsis

function ruleset.route(addr)
    return "www.example.org:80", "http://203.0.113.1:8080", ..., "socks4a://[2001:DB8::1]:1080"
end

Description

Process an IPv4 request. Specifically:

  • SOCKS5 with IPv4 address
  • Any SOCKS4

This callback is called from an asynchronous routine.

Params

  • addr: address and port, like "203.0.113.1:80"

Returns

See ruleset.resolve

ruleset.route6

Synopsis

function ruleset.route6(addr)
    return "www.example.org:80", "http://203.0.113.1:8080", ..., "socks4a://[2001:DB8::1]:1080"
end

Description

Process an IPv6 request. Specifically:

  • SOCKS5 with IPv6 address

This callback is called from an asynchronous routine.

Params

  • addr: address and port, like "[2001:DB8::1]:80"

Returns

See ruleset.resolve

ruleset.tick

Synopsis

function ruleset.tick(now)
    -- ......
end

Description

Periodic timer callback. See neosocksd.setinterval.

This callback is NOT called from an asynchronous routine.

Params

  • now: current timestamp in seconds

Returns

Ignored

ruleset.stats

Synopsis

function ruleset.stats(dt, q)
    local w = {}
    table.insert(w, string.format("dt = %.03f, q = %q", dt, q))
    return table.concat(w, "\n")
end

Description

Generate custom information to be provided in the API /stats. See also stats.

This callback is NOT called from an asynchronous routine.

Params

  • dt: seconds elapsed since last call

Returns

Custom information in a string.

Lua API

neosocksd.config

Synopsis

_G.config = neosocksd.config()
if config.loglevel >= 6 then
    print("...")
end

Description

Returns a table of server configurations.

neosocksd.resolve

Synopsis

local addr = neosocksd.resolve("www.example.com")

Description

(Deprecated) consider using await.resolve instead.

Resolves a host name locally and blocks the whole server until resolution is finished or times out.

neosocksd.splithostport

Synopsis

local host, port = neosocksd.splithostport("example.com:80")

Description

Split address string into host and port. Raises an error on failure.

neosocksd.parse_ipv4

Synopsis

local subnet = neosocksd.parse_ipv4("169.254.0.0")
local mask = 0xFFFF0000 -- 169.254.0.0/16
local ip = neosocksd.parse_ipv4("203.0.113.1")
if ip and (ip & mask) == subnet then
    -- ......
end

Description

Parses an IPv4 address into integers. Returns nil on failure.

neosocksd.parse_ipv6

Synopsis

-- with 64-bit Lua integers
local subnet1, subnet2 = neosocksd.parse_ipv6("FE80::")
local mask1 = 0xFFC0000000000000 -- fe80::/10
local ip1, ip2 = neosocksd.parse_ipv6("2001:DB8::1")
if ip1 and (ip1 & mask1) == subnet1 then
    -- ......
end

Description

Parses an IPv6 address into integers. Returns nil on failure.

neosocksd.setinterval

Synopsis

neosocksd.setinterval(1.5)

Description

Set the interval to call ruleset.tick in seconds.

The valid interval range is [1e-3, 1e+9], use setinterval(0) to stop the timer tick.

neosocksd.async

Synopsis

local co, err = neosocksd.async(finish, func, ...)
-- works like: finish(pcall(func, ...))
-- func is yieldable, but finish is NOT

Description

Low-level API to start an asynchronous routine. Asynchronous routines are based on Lua coroutines. I.e., they run concurrently, but not in parallel. This interface is usually not called directly by user scripts. See _G.async.

neosocksd.invoke

Synopsis

-- neosocksd.invoke(code, host, proxyN, ..., proxy1)
neosocksd.invoke([[log("test rpc")]], "api.neosocksd.internal:80", "socks4a://127.0.0.1:1080")

Description

Run Lua code on another neosocksd. This function returns immediately. In case of failure, the invocation is lost.

Tip: Please refer to neosocksd.sendmsg in libruleset.lua.

neosocksd.stats

Synopsis

local t = neosocksd.stats()

Description

Return a table of raw statistics. If called during the initial loading phase, unavailable data will be set to zero.

neosocksd.now

Synopsis

local now = neosocksd.now()

Description

Formally, get the timestamp of the latest event in seconds.

  • Any ruleset callback must be invoked by an event.
  • Any asynchronous routine must be resumed by an event.

neosocksd.traceback

Synopsis

local ok, result = xpcall(f, neosocksd.traceback, ...)

Description

In supported builds, log both Lua and C traceback.

regex.compile

Synopsis

local reg = regex.compile([[\.example\.(com|org)$]])
local s, e = reg:find(host)
if s then
    -- ......
end
local m, sub1 = reg:match(host)
if m then
    -- ......
end
for m, sub1 in reg:gmatch(s) do
    -- ......
end

Description

Lua interface for POSIX Extended Regular Expressions.

time.*

Synopsis

local t0 = time.monotonic() -- CLOCK_MONOTONIC
local t1 = time.process()   -- CLOCK_PROCESS_CPUTIME_ID
local t2 = time.thread()    -- CLOCK_THREAD_CPUTIME_ID
local t3 = time.wall()      -- CLOCK_REALTIME
-- measure function time with monotonic clock
local t, ... = time.measure(f, ...)

Description

Lua interface for POSIX function clock_gettime().

zlib.compress

Synopsis

local z = zlib.compress(s)
local s1 = zlib.uncompress(z)
assert(s == s1)

Description

Data compression interface for zlib format (as declared in RFC 1950 and RFC 1951).

Tip: neosocksd.invoke and await.invoke will compress the data internally.

_G.marshal

Synopsis

local s = marshal("a", {"b", ["c"] = "d"})
log(s) -- "a",{"b",["c"]="d"}

Description

Marshal all parameters in Lua syntax.

To be symmetric, there is also _G.unmarshal(s) in libruleset.lua.

_G.async

Synopsis

async(function(...)
    -- routine0
    local t1 = async(function(...)
        -- routine1
        return "result1"
    end, ...)
    local t2 = async(function(...)
        -- routine2
        return "result2"
    end, ...)
    local ok, r1 = t1:wait()
    local ok, r2 = t2:wait()
end, ...)

Description

Start an asynchronous routine and run it until the first await.* or the end. See await.resolve for a full example.

This function is implemented in libruleset.lua.

Notice: The await.* functions should only be called in asynchronous routines.

await.execute

Synopsis

async(function()
    local ok, what, stat = await.execute("curl -sX POST http://example.com/v1/api")
    if not ok then
        -- ......
    end
end)

Description

Execute a shell command asynchronously. Returns 3 values like os.execute.

This function depends on /bin/sh.

await.invoke

Synopsis

async(function(addr)
    local begin = neosocksd.now()
    local ok, result = await.invoke([[await.idle(); return "ok"]], addr)
    if not ok then
        -- on failure, the result is string
        error("invocation failed: " .. result)
    end
    -- on success, the result is function
    ok, result = result()
    if not ok then
        error("remote error: " .. result)
    end
    assert(result == "ok")
    local rtt = neosocksd.now() - begin
    logf("ping %s: %dms", addr, math.ceil(rtt * 1e+3))
end, "127.0.1.1:9080")

Description

Low-level API to run Lua code on another neosocksd and return the result. On another neosocksd, the code runs in asynchronous routine. Therefore, you can call await.* functions in the remote code. await.invoke is likely to be less efficient than neosocksd.invoke.

Tip: Please refer to await.rpcall in libruleset.lua.

await.resolve

Synopsis

async(function()
    local addr = await.resolve("www.example.com")
    if addr then
        -- ......
    end
end)

Description

Resolves a host name asynchronously. If asynchronous name resolution is not supported, await.resolve behaves the same as neosocksd.resolve.

IPv4/IPv6 preference depends on command line argument -4/-6.

Tip: To reduce delays caused by name resolution. It's recommended to set up a local DNS cache, such as systemd-resolved or dnsmasq.

await.sleep

Synopsis

async(function()
    await.sleep(1.5)
end)

Description

Pause an asynchronous routine for at least specified interval in seconds.

The interval must be in the range [0, 1e+9].