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.
RegisterorRegisterWithinstalls the makers. After thattunnel.CreateInbound,tunnel.CreateOutboundandtunnel.BuildDialerunderstand every protocol above.StartAllstarts every inbound of a config andRunConfigis a whole program: load, check, start, wait for Ctrl-C.- Local by default. An inbound listens on
127.0.0.1unless itslistenfield says otherwise. Write"listen": "0.0.0.0"for a server that other machines connect to. - With
use_dohthe 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.
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)
endTypes
Options
struct Options| Name | Type | Description |
|---|---|---|
fragment | bool = false | Split the TLS hello of outgoing connections into small pieces. |
fragment_min | int = 4 | Smallest piece in bytes. |
fragment_max | int = 12 | Largest piece in bytes. |
fragment_delay_ms | int = 5 | Pause between pieces. |
fragment_mode | str = "tcp" | What fragmenting splits: "tcp", "tls" or "both". |
fragment_sni | bool = false | Also cut inside the server name. |
fragment_writes | int = 1 | How many of the first handshake writes are fragmented. |
read_timeout_ms | int = 0 | Idle read timeout of outgoing connections. 0 waits forever. |
write_timeout_ms | int = 0 | Idle write timeout of outgoing connections. 0 waits forever. |
use_doh | bool = false | Resolve server names through the resolver below. |
resolver | doh.Resolver | The DNS over HTTPS resolver. |
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()
endDohResolver
struct DohResolver| Name | Type | Description |
|---|---|---|
resolver | doh.Resolver | The DNS over HTTPS resolver. |
ipv6 | bool = true | Also ask for AAAA records. |
Lookup
func Lookup(host: str): tunnel.LookupResultTransportDialer
struct TransportDialer| Name | Type | Description |
|---|---|---|
settings | transport.Settings | Network, TLS and fragment settings. |
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
endDial
func Dial(target: tunnel.Addr): dyn tunnel.StreamName
func Name(): strThe example for this item is shown with the ones above: net-vpn-Settings.salam
VlessDialer
struct VlessDialer| Name | Type | Description |
|---|---|---|
node | tunnel.Node | The server. |
The example for this item is shown with the ones above: net-vpn-Settings.salam
Dial
func Dial(target: tunnel.Addr): dyn tunnel.StreamName
func Name(): strThe example for this item is shown with the ones above: net-vpn-Settings.salam
VmessDialer
struct VmessDialer| Name | Type | Description |
|---|---|---|
node | tunnel.Node | The server. |
The example for this item is shown with the ones above: net-vpn-Settings.salam
Dial
func Dial(target: tunnel.Addr): dyn tunnel.StreamName
func Name(): strThe example for this item is shown with the ones above: net-vpn-Settings.salam
SsDialer
struct SsDialer| Name | Type | Description |
|---|---|---|
node | tunnel.Node | The server. |
The example for this item is shown with the ones above: net-vpn-Settings.salam
Dial
func Dial(target: tunnel.Addr): dyn tunnel.StreamName
func Name(): strThe example for this item is shown with the ones above: net-vpn-Settings.salam
OutMaker
struct OutMaker| Name | Type | Description |
|---|---|---|
proto | str = "" | The protocol name. |
The example for this item is shown with the ones above: net-vpn-Register.salam
Protocol
func Protocol(): strThe example for this item is shown with the ones above: net-vpn-Register.salam
Make
func Make(cfg: tunnel.OutboundConfig): dyn tunnel.DialerThe example for this item is shown with the ones above: net-vpn-Register.salam
VlessInbound
struct VlessInbound| Name | Type | Description |
|---|---|---|
users | Vector | The allowed users. |
The example for this item is shown with the ones above: net-vpn-Register.salam
Name
func Name(): strThe example for this item is shown with the ones above: net-vpn-Register.salam
Handshake
func Handshake(s: dyn tunnel.Stream): tunnel.SessionReply
func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)VmessInbound
struct VmessInbound| Name | Type | Description |
|---|---|---|
users | Vector | The allowed users. |
replay | vmess.ReplayFilter | Remembers 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(): strThe example for this item is shown with the ones above: net-vpn-Register.salam
Handshake
func Handshake(s: dyn tunnel.Stream): tunnel.SessionReply
func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)SsInbound
struct SsInbound| Name | Type | Description |
|---|---|---|
server | shadowsocks.Server | The Shadowsocks server settings. |
The example for this item is shown with the ones above: net-vpn-Register.salam
Name
func Name(): strThe example for this item is shown with the ones above: net-vpn-Register.salam
Handshake
func Handshake(s: dyn tunnel.Stream): tunnel.SessionReply
func Reply(_s: dyn tunnel.Stream, sess: tunnel.Session, ok: bool)InMaker
struct InMaker| Name | Type | Description |
|---|---|---|
proto | str = "" | The protocol name. |
The example for this item is shown with the ones above: net-vpn-Register.salam
Protocol
func Protocol(): strThe example for this item is shown with the ones above: net-vpn-Register.salam
Make
func Make(cfg: tunnel.InboundConfig): dyn tunnel.InboundProtocolThe example for this item is shown with the ones above: net-vpn-Register.salam
TransportPending
struct TransportPending| Name | Type | Description |
|---|---|---|
raw | transport.Conn | The raw connection. |
settings | transport.Settings | How to upgrade it. |
upgraded | bool = false | True when the connection was accepted through transport.Accept (gRPC and Reality), so the upgrade has already been done. |
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)
endValid
func Valid(): boolThe example for this item is shown with the ones above: net-vpn-App.salam
Open
func Open(): dyn tunnel.StreamThe example for this item is shown with the ones above: net-vpn-App.salam
Abort
func Abort()The example for this item is shown with the ones above: net-vpn-App.salam
Remote
func Remote(): strThe example for this item is shown with the ones above: net-vpn-App.salam
TransportAcceptor
struct TransportAcceptor| Name | Type | Description |
|---|---|---|
listener | transport.Listener | The listener. |
settings | transport.Settings | Network and TLS settings. |
The example for this item is shown with the ones above: net-vpn-App.salam
Accept
func Accept(): dyn tunnel.PendingThe example for this item is shown with the ones above: net-vpn-App.salam
Port
func Port(): intThe example for this item is shown with the ones above: net-vpn-App.salam
Ok
func Ok(): boolThe example for this item is shown with the ones above: net-vpn-App.salam
Close
func Close()The example for this item is shown with the ones above: net-vpn-App.salam
Listener
struct Listener| Name | Type | Description |
|---|---|---|
server | tunnel.AcceptServer | The accept server. |
has_server | bool = false | False for a trojan inbound, which has its own server. |
trojan | trojan.Server | The trojan server, when the protocol is trojan. |
port | int = 0 | The port in use. |
tag | str = "" | 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 = 32Start 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.SettingsThe example for this item is shown with the ones above: net-vpn-Settings.salam
NodeSettings
func NodeSettings(n: tunnel.Node): transport.SettingsRegister.The example for this item is shown with the ones above: net-vpn-Settings.salam
DialerFromNode
func DialerFromNode(n: tunnel.Node): dyn tunnel.DialerThe example for this item is shown with the ones above: net-vpn-Settings.salam
ToTunnelAddr
func ToTunnelAddr(a: transport.Addr): tunnel.AddrThe example for this item is shown with the ones above: net-vpn-Settings.salam
ToTransportAddr
func ToTransportAddr(a: tunnel.Addr): transport.AddrThe example for this item is shown with the ones above: net-vpn-Settings.salam
RegisterWith
func RegisterWith(o: Options)The example for this item is shown with the ones above: net-vpn-Register.salam
Register
func Register()The example for this item is shown with the ones above: net-vpn-Register.salam
BuildDialer
func BuildDialer(c: tunnel.Config): tunnel.RouterDialerThe example for this item is shown with the ones above: net-vpn-Register.salam
InboundPolicy
func InboundPolicy(ib: tunnel.InboundConfig): tunnel.DestPolicyallowPrivate (honoured only on a loopback listener), allowCidr, denyCidr, allowDomain, denyDomain.Start
func Start(ib: tunnel.InboundConfig, dialer: dyn tunnel.Dialer, stats: tunnel.Stats): ListenerThe 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): ListenerStart 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>The example for this item is shown with the ones above: net-vpn-App.salam
Ok
func Ok(l: Listener): boolThe example for this item is shown with the ones above: net-vpn-App.salam
Stop
func Stop(l: Listener)The example for this item is shown with the ones above: net-vpn-App.salam
Summary
func Summary(st: tunnel.Stats): strThe example for this item is shown with the ones above: net-vpn-App.salam
Wait
func Wait(st: tunnel.Stats, every: int, limit: int)The example for this item is shown with the ones above: net-vpn-App.salam
RunConfig
func RunConfig(path: str, every: int, limit: int): intThe example for this item is shown with the ones above: net-vpn-App.salam