Standard library · Network

net.vpn

One call that registers every proxy protocol with net.tunnel, so a v2ray style JSON config runs both sides, with a ready to use runner.

import net.vpn

This package joins net.tunnel to every protocol package: socks, http, trojan, vless, vmess and shadowsocks, with the v2ray stream settings of net.transport (tcp, tls, ws, httpupgrade, and TLS hello fragmenting). One call to Register and a v2ray style JSON config runs, both the inbounds and the outbounds.

  • Register or RegisterWith installs the makers. After that tunnel.CreateInbound, tunnel.CreateOutbound and tunnel.BuildDialer understand every protocol above.
  • StartAll starts every inbound of a config and RunConfig is a whole program: load, check, start, wait for Ctrl-C.
  • Local by default. An inbound listens on 127.0.0.1 unless its listen field says otherwise. Write "listen": "0.0.0.0" for a server that other machines connect to.
  • With use_doh the names of servers are resolved over DNS over HTTPS, and routing rules with IP ranges can match domain targets, with answers cached.
  • Trojan inbounds start their own server; their bind address follows the trojan package.
net-vpn-guide-app.salam
import net.socks
import net.tcp
import net.tunnel
import net.vpn

mut echo_srv := tcp.Server {}

func echo_once():
    c := tcp.Accept(echo_srv)
    s := tunnel.WrapTcp(c)
    data := s.Read(100)
    s.Write("echo:" + data)
    s.Close()
end

func main:
    echo_srv = tcp.Bind(0)
    _t := spawn(echo_once)
    vpn.Register()
    cfg := tunnel.ParseConfig(`{"inbounds":[{"tag":"in","port":0,"protocol":"mixed"}],"outbounds":[{"tag":"direct","protocol":"freedom"}]}`)
    stats := tunnel.NewStats()
    listeners := vpn.StartAll(cfg, stats)
    println "listening:", vpn.Ok(listeners[0])
    s := tunnel.DialTcp("127.0.0.1", listeners[0].port, 3000)
    r := socks.ClientHandshake(s, socks.Client { version = 5 }, socks.CmdConnect, "127.0.0.1", tcp.Port(echo_srv))
    println "socks handshake:", r.ok
    s.Write("hello")
    println s.Read(100)
    s.Close()
    vpn.Stop(listeners[0])
    tcp.CloseServer(echo_srv)
end
Outputlistening: true socks handshake: true echo:hello

Types

Options

struct Options
Settings for Register: fragmenting the TLS hello and DNS over HTTPS.
NameTypeDescription
fragmentbool = falseSplit the TLS hello of outgoing connections into small pieces.
fragment_minint = 4Smallest piece in bytes.
fragment_maxint = 12Largest piece in bytes.
fragment_delay_msint = 5Pause between pieces.
fragment_modestr = "tcp"What fragmenting splits: "tcp", "tls" or "both".
fragment_snibool = falseAlso cut inside the server name.
fragment_writesint = 1How many of the first handshake writes are fragmented.
read_timeout_msint = 0Idle read timeout of outgoing connections. 0 waits forever.
write_timeout_msint = 0Idle write timeout of outgoing connections. 0 waits forever.
use_dohbool = falseResolve server names through the resolver below.
resolverdoh.ResolverThe DNS over HTTPS resolver.
net-vpn-Register.salam
import net.tunnel
import net.vpn

func main:
    vpn.RegisterWith(vpn.Options { fragment = true, fragment_min = 2, fragment_max = 8 })
    each proto in ["vless", "vmess", "trojan", "socks", "http", "mixed"]:
        ib := tunnel.CreateInbound(tunnel.InboundConfig { protocol = proto, settings = `{"clients":[{"id":"0b3a8c6e-1f3d-4d7e-9a50-3f8e6a1c2b44","password":"secret"}],"method":"aes-128-gcm","password":"secret"}` })
        println "inbound", proto, ib.Name()
    end
    each proto in ["vless", "vmess", "trojan", "shadowsocks", "ss", "socks", "http", "freedom"]:
        ob := tunnel.CreateOutbound(tunnel.OutboundConfig { protocol = proto, settings = `{"address":"vpn.example.com","port":443}` })
        println "outbound", proto, ob.Name()
    end

    cfg := tunnel.ParseConfig(`{"inbounds":[{"tag":"in","port":0,"protocol":"mixed"}],"outbounds":[{"tag":"direct","protocol":"freedom"},{"tag":"out","protocol":"socks","settings":{"address":"127.0.0.1","port":1080}}]}`)
    dialer := vpn.BuildDialer(cfg)
    println dialer.Name()

    vpn.Register()
    println tunnel.CreateInbound(tunnel.InboundConfig { protocol = "vless" }).Name()
end
Outputinbound vless vless inbound vmess vmess inbound trojan trojan inbound socks socks5 inbound http http inbound mixed mixed outbound vless vless outbound vmess vmess outbound trojan trojan outbound shadowsocks shadowsocks outbound ss shadowsocks outbound socks socks5 outbound http http outbound freedom direct router vless

DohResolver

struct DohResolver
Adapts a net.doh resolver to the router and the direct dialer.
NameTypeDescription
resolverdoh.ResolverThe DNS over HTTPS resolver.
ipv6bool = trueAlso ask for AAAA records.

Lookup

func Lookup(host: str): tunnel.LookupResult
Returns the A and AAAA answers of a name.

TransportDialer

struct TransportDialer
Opens a plain transport connection to the target.
NameTypeDescription
settingstransport.SettingsNetwork, TLS and fragment settings.
net-vpn-Settings.salam
import net.transport
import net.tunnel
import net.vpn

func main:
    raw := `{"network":"ws","security":"tls","tlsSettings":{"serverName":"cdn.example.com"},"wsSettings":{"path":"/chat","headers":{"Host":"front.example.com"}}}`
    s := vpn.StreamSettings(raw)
    println s.network, s.tls, s.sni, s.path, s.host

    node := tunnel.Node { protocol = "vless", host = "vpn.example.com", port = 443, network = "ws", tls = true, sni = "vpn.example.com", path = "/ws" }
    n := vpn.NodeSettings(node)
    println n.network, n.tls, n.sni, n.path

    each proto in ["vless", "vmess", "shadowsocks", "trojan", "socks", "http", "wireguard"]:
        println proto, vpn.DialerFromNode(tunnel.Node { protocol = proto, host = "vpn.example.com", port = 443 }).Name()
    end

    t := vpn.ToTunnelAddr(transport.NewAddr("example.com", 443))
    println t.host, t.port
    back := vpn.ToTransportAddr(tunnel.NewAddr("example.org", 80))
    println back.host, back.port
end
Outputws true cdn.example.com /chat front.example.com ws true vpn.example.com /ws vless vless vmess vmess shadowsocks shadowsocks trojan trojan socks socks5 http http wireguard block example.com 443 example.org 80

Dial

func Dial(target: tunnel.Addr): dyn tunnel.Stream
Connects and returns the stream.

Name

func Name(): str
Returns transport.

The example for this item is shown with the ones above: net-vpn-Settings.salam

VlessDialer

struct VlessDialer
A dialer for a VLESS server.
NameTypeDescription
nodetunnel.NodeThe server.

The example for this item is shown with the ones above: net-vpn-Settings.salam

Dial

func Dial(target: tunnel.Addr): dyn tunnel.Stream
Connects through the server to the target.

Name

func Name(): str
Returns vless.

The example for this item is shown with the ones above: net-vpn-Settings.salam

VmessDialer

struct VmessDialer
A dialer for a VMess server.
NameTypeDescription
nodetunnel.NodeThe server.

The example for this item is shown with the ones above: net-vpn-Settings.salam

Dial

func Dial(target: tunnel.Addr): dyn tunnel.Stream
Connects through the server to the target.

Name

func Name(): str
Returns vmess.

The example for this item is shown with the ones above: net-vpn-Settings.salam

SsDialer

struct SsDialer
A dialer for a Shadowsocks server.
NameTypeDescription
nodetunnel.NodeThe server.

The example for this item is shown with the ones above: net-vpn-Settings.salam

Dial

func Dial(target: tunnel.Addr): dyn tunnel.Stream
Connects through the server to the target.

Name

func Name(): str
Returns shadowsocks.

The example for this item is shown with the ones above: net-vpn-Settings.salam

OutMaker

struct OutMaker
Builds the dialer of an outbound of one protocol from a config.
NameTypeDescription
protostr = ""The protocol name.

The example for this item is shown with the ones above: net-vpn-Register.salam

Protocol

func Protocol(): str
Returns the protocol name.

The example for this item is shown with the ones above: net-vpn-Register.salam

Make

func Make(cfg: tunnel.OutboundConfig): dyn tunnel.Dialer
Builds the dialer.

The example for this item is shown with the ones above: net-vpn-Register.salam

VlessInbound

struct VlessInbound
Accepts VLESS clients.
NameTypeDescription
usersVectorThe allowed users.

The example for this item is shown with the ones above: net-vpn-Register.salam

Name

func Name(): str
Returns vless.

The example for this item is shown with the ones above: net-vpn-Register.salam

Handshake

func Handshake(s: dyn tunnel.Stream): tunnel.Session
Reads the request and checks the user.

Reply

func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)
Closes the stream when the target could not be reached.

VmessInbound

struct VmessInbound
Accepts VMess clients.
NameTypeDescription
usersVectorThe allowed users.
replayvmess.ReplayFilterRemembers recent requests so they cannot be replayed.

The example for this item is shown with the ones above: net-vpn-Register.salam

Name

func Name(): str
Returns vmess.

The example for this item is shown with the ones above: net-vpn-Register.salam

Handshake

func Handshake(s: dyn tunnel.Stream): tunnel.Session
Reads the request and checks the user.

Reply

func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)
Closes the stream when the target could not be reached.

SsInbound

struct SsInbound
Accepts Shadowsocks clients.
NameTypeDescription
servershadowsocks.ServerThe Shadowsocks server settings.

The example for this item is shown with the ones above: net-vpn-Register.salam

Name

func Name(): str
Returns shadowsocks.

The example for this item is shown with the ones above: net-vpn-Register.salam

Handshake

func Handshake(s: dyn tunnel.Stream): tunnel.Session
Reads the request.

Reply

func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)
Closes the stream when the target could not be reached.

InMaker

struct InMaker
Builds the inbound protocol of one name from a config.
NameTypeDescription
protostr = ""The protocol name.

The example for this item is shown with the ones above: net-vpn-Register.salam

Protocol

func Protocol(): str
Returns the protocol name.

The example for this item is shown with the ones above: net-vpn-Register.salam

Make

func Make(cfg: tunnel.InboundConfig): dyn tunnel.InboundProtocol
Builds the inbound protocol from its settings.

The example for this item is shown with the ones above: net-vpn-Register.salam

TransportPending

struct TransportPending
An accepted connection waiting for its TLS or WebSocket upgrade.
NameTypeDescription
rawtransport.ConnThe raw connection.
settingstransport.SettingsHow to upgrade it.
upgradedbool = falseTrue when the connection was accepted through transport.Accept (gRPC and Reality), so the upgrade has already been done.
net-vpn-App.salam
import net.socks
import net.tcp
import net.tunnel
import net.vpn

mut echo_srv := tcp.Server {}

func echo_once():
    c := tcp.Accept(echo_srv)
    s := tunnel.WrapTcp(c)
    data := s.Read(100)
    s.Write("echo:" + data)
    s.Close()
end

func main:
    echo_srv = tcp.Bind(0)
    _t := spawn(echo_once)
    vpn.Register()
    cfg := tunnel.ParseConfig(`{"inbounds":[{"tag":"in","port":0,"protocol":"mixed"}],"outbounds":[{"tag":"direct","protocol":"freedom"}]}`)
    stats := tunnel.NewStats()
    listeners := vpn.StartAll(cfg, stats)
    println "listening:", vpn.Ok(listeners[0])
    s := tunnel.DialTcp("127.0.0.1", listeners[0].port, 3000)
    r := socks.ClientHandshake(s, socks.Client { version = 5 }, socks.CmdConnect, "127.0.0.1", tcp.Port(echo_srv))
    println "socks handshake:", r.ok
    s.Write("hello")
    println s.Read(100)
    s.Close()
    vpn.Stop(listeners[0])
    tcp.CloseServer(echo_srv)
end
Outputlistening: true socks handshake: true echo:hello

Valid

func Valid(): bool
True when the accept worked.

The example for this item is shown with the ones above: net-vpn-App.salam

Open

func Open(): dyn tunnel.Stream
Runs the upgrade and returns the stream.

The example for this item is shown with the ones above: net-vpn-App.salam

Abort

func Abort()
Drops the connection.

The example for this item is shown with the ones above: net-vpn-App.salam

Remote

func Remote(): str
The address of the client.

The example for this item is shown with the ones above: net-vpn-App.salam

TransportAcceptor

struct TransportAcceptor
Accepts connections for a transport listener.
NameTypeDescription
listenertransport.ListenerThe listener.
settingstransport.SettingsNetwork and TLS settings.

The example for this item is shown with the ones above: net-vpn-App.salam

Accept

func Accept(): dyn tunnel.Pending
Waits for the next connection.

The example for this item is shown with the ones above: net-vpn-App.salam

Port

func Port(): int
The port in use.

The example for this item is shown with the ones above: net-vpn-App.salam

Ok

func Ok(): bool
False when listening or loading the certificate failed.

The example for this item is shown with the ones above: net-vpn-App.salam

Close

func Close()
Stops listening.

The example for this item is shown with the ones above: net-vpn-App.salam

Listener

struct Listener
A running inbound.
NameTypeDescription
servertunnel.AcceptServerThe accept server.
has_serverbool = falseFalse for a trojan inbound, which has its own server.
trojantrojan.ServerThe trojan server, when the protocol is trojan.
portint = 0The port in use.
tagstr = ""The inbound tag.

The example for this item is shown with the ones above: net-vpn-App.salam

Constants and variables

PENDING_PER_SOURCE

const PENDING_PER_SOURCE: i32 = 32
How many connections of one address Start lets sit in a handshake at once on each inbound it opens: 32. A client that opens a connection and says nothing is dropped after the handshake time limit.

Functions

StreamSettings

func StreamSettings(raw: str): transport.Settings
Reads a v2ray streamSettings object: network (tcp, ws, httpupgrade, grpc), security (none, tls, reality), tlsSettings, realitySettings (client: serverName, publicKey, shortId, spiderX, fingerprint; server: privateKey, dest, serverNames, shortIds), wsSettings, httpupgradeSettings, grpcSettings (serviceName, multiMode), timeouts (read, write in milliseconds) and fragment (mode, sni, writes, min, max, delay).

The example for this item is shown with the ones above: net-vpn-Settings.salam

NodeSettings

func NodeSettings(n: tunnel.Node): transport.Settings
The transport settings for the node of a share link, including the Reality keys and the gRPC service name, with the fragment and timeout options of Register.

The example for this item is shown with the ones above: net-vpn-Settings.salam

DialerFromNode

func DialerFromNode(n: tunnel.Node): dyn tunnel.Dialer
Builds the dialer of a node for vless, vmess, trojan, shadowsocks, socks or http. Other protocols give a dialer that refuses.

The example for this item is shown with the ones above: net-vpn-Settings.salam

ToTunnelAddr

func ToTunnelAddr(a: transport.Addr): tunnel.Addr
Converts a transport address to a tunnel address.

The example for this item is shown with the ones above: net-vpn-Settings.salam

ToTransportAddr

func ToTransportAddr(a: tunnel.Addr): transport.Addr
Converts a tunnel address to a transport address.

The example for this item is shown with the ones above: net-vpn-Settings.salam

RegisterWith

func RegisterWith(o: Options)
Registers every protocol with the given options.

The example for this item is shown with the ones above: net-vpn-Register.salam

Register

func Register()
Registers outbounds and inbounds for socks, http, trojan, vless, vmess and shadowsocks, so a JSON config runs both sides.

The example for this item is shown with the ones above: net-vpn-Register.salam

BuildDialer

func BuildDialer(c: tunnel.Config): tunnel.RouterDialer
Builds the router and dialers of a config, and gives the router the DNS over HTTPS resolver when it is on.

The example for this item is shown with the ones above: net-vpn-Register.salam

InboundPolicy

func InboundPolicy(ib: tunnel.InboundConfig): tunnel.DestPolicy
Builds the destination policy of an inbound from its settings: allowPrivate (honoured only on a loopback listener), allowCidr, denyCidr, allowDomain, denyDomain.

Start

func Start(ib: tunnel.InboundConfig, dialer: dyn tunnel.Dialer, stats: tunnel.Stats): Listener
Starts one inbound. It listens on the address of the config, 127.0.0.1 by default. Write 0.0.0.0 to open it to the network.

The example for this item is shown with the ones above: net-vpn-App.salam

StartRouted

func StartRouted(ib: tunnel.InboundConfig, rd: tunnel.RouterDialer, stats: tunnel.Stats): Listener
Like Start for a router dialer: names that the router sends direct are resolved once, checked against the inbound policy and dialed at the checked address.

StartAll

func StartAll(c: tunnel.Config, stats: tunnel.Stats): Vector<Listener>
Starts every inbound of a config.

The example for this item is shown with the ones above: net-vpn-App.salam

Ok

func Ok(l: Listener): bool
True while the inbound listens.

The example for this item is shown with the ones above: net-vpn-App.salam

Stop

func Stop(l: Listener)
Stops an inbound.

The example for this item is shown with the ones above: net-vpn-App.salam

Summary

func Summary(st: tunnel.Stats): str
One line of traffic numbers.

The example for this item is shown with the ones above: net-vpn-App.salam

Wait

func Wait(st: tunnel.Stats, every: int, limit: int)
Waits for Ctrl-C or the time limit, printing the summary every few seconds.

The example for this item is shown with the ones above: net-vpn-App.salam

RunConfig

func RunConfig(path: str, every: int, limit: int): int
Loads a config file, checks it, starts everything and waits. Returns the exit code.

The example for this item is shown with the ones above: net-vpn-App.salam