Browse Source

Add wireguard outbound

世界 4 years ago
parent
commit
54211e960e

+ 11 - 5
go.mod

@@ -13,7 +13,7 @@ require (
 	github.com/jhump/protoreflect v1.9.0
 	github.com/jhump/protoreflect v1.9.0
 	github.com/lucas-clemente/quic-go v0.23.0
 	github.com/lucas-clemente/quic-go v0.23.0
 	github.com/miekg/dns v1.1.43
 	github.com/miekg/dns v1.1.43
-	github.com/pelletier/go-toml v1.2.0
+	github.com/pelletier/go-toml v1.8.1
 	github.com/pires/go-proxyproto v0.6.1
 	github.com/pires/go-proxyproto v0.6.1
 	github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
 	github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
 	github.com/stretchr/testify v1.7.0
 	github.com/stretchr/testify v1.7.0
@@ -21,17 +21,21 @@ require (
 	github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848
 	github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848
 	github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
 	github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
 	go.starlark.net v0.0.0-20210901212718-87f333178d59
 	go.starlark.net v0.0.0-20210901212718-87f333178d59
-	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
-	golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
+	golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
+	golang.org/x/net v0.0.0-20211020060615-d418f374d309
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
-	golang.org/x/sys v0.0.0-20210903071746-97244b99971b
+	golang.org/x/sys v0.0.0-20211020174200-9d6173849985
+	golang.zx2c4.com/wireguard v0.0.0-20211026125340-e42c6c4bc2d0
 	google.golang.org/grpc v1.40.0
 	google.golang.org/grpc v1.40.0
 	google.golang.org/protobuf v1.27.1
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/yaml.v2 v2.4.0
 	gopkg.in/yaml.v2 v2.4.0
+	gvisor.dev/gvisor v0.0.0
 	h12.io/socks v1.0.3
 	h12.io/socks v1.0.3
 	inet.af/netaddr v0.0.0-20210903134321-85fa6c94624e
 	inet.af/netaddr v0.0.0-20210903134321-85fa6c94624e
 )
 )
 
 
+replace gvisor.dev/gvisor v0.0.0 => github.com/sagernet/gvisor v0.0.0-20211022025201-1cae8baac6b3
+
 require (
 require (
 	github.com/cheekybits/genny v1.0.0 // indirect
 	github.com/cheekybits/genny v1.0.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
@@ -41,6 +45,7 @@ require (
 	github.com/go-playground/locales v0.14.0 // indirect
 	github.com/go-playground/locales v0.14.0 // indirect
 	github.com/go-playground/universal-translator v0.18.0 // indirect
 	github.com/go-playground/universal-translator v0.18.0 // indirect
 	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
 	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
+	github.com/google/btree v1.0.1 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
 	github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
 	github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
 	github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
@@ -54,9 +59,10 @@ require (
 	go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect
 	go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect
 	golang.org/x/mod v0.4.2 // indirect
 	golang.org/x/mod v0.4.2 // indirect
 	golang.org/x/text v0.3.6 // indirect
 	golang.org/x/text v0.3.6 // indirect
+	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
 	golang.org/x/tools v0.1.1 // indirect
 	golang.org/x/tools v0.1.1 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
-	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
+	google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
 )

File diff suppressed because it is too large
+ 541 - 8
go.sum


+ 1 - 0
infra/conf/v4/v2ray.go

@@ -42,6 +42,7 @@ var (
 		"trojan":      func() interface{} { return new(TrojanClientConfig) },
 		"trojan":      func() interface{} { return new(TrojanClientConfig) },
 		"dns":         func() interface{} { return new(DNSOutboundConfig) },
 		"dns":         func() interface{} { return new(DNSOutboundConfig) },
 		"loopback":    func() interface{} { return new(LoopbackConfig) },
 		"loopback":    func() interface{} { return new(LoopbackConfig) },
+		"wireguard":   func() interface{} { return new(WireGuardClientConfig) },
 	}, "protocol", "settings")
 	}, "protocol", "settings")
 )
 )
 
 

+ 37 - 0
infra/conf/v4/wireguard.go

@@ -0,0 +1,37 @@
+package v4
+
+import (
+	"github.com/golang/protobuf/proto"
+	"github.com/v2fly/v2ray-core/v4/common/protocol"
+	"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
+	"github.com/v2fly/v2ray-core/v4/proxy/wireguard"
+)
+
+type WireGuardClientConfig struct {
+	Address        *cfgcommon.Address   `json:"address"`
+	Port           uint16               `json:"port"`
+	Network        cfgcommon.Network    `json:"network"`
+	LocalAddresses cfgcommon.StringList `json:"localAddresses"`
+	PrivateKey     string               `json:"privateKey"`
+	PeerPublicKey  string               `json:"peerPublicKey"`
+	PreSharedKey   string               `json:"preSharedKey"`
+	MTU            uint32               `json:"mtu"`
+	UserLevel      uint32               `json:"userLevel"`
+}
+
+func (v *WireGuardClientConfig) Build() (proto.Message, error) {
+	config := &wireguard.Config{
+		Server: &protocol.ServerEndpoint{
+			Address: v.Address.Build(),
+			Port:    uint32(v.Port),
+		},
+		Network:       v.Network.Build(),
+		LocalAddress:  v.LocalAddresses,
+		PrivateKey:    v.PrivateKey,
+		PeerPublicKey: v.PeerPublicKey,
+		PreSharedKey:  v.PreSharedKey,
+		Mtu:           v.MTU,
+		UserLevel:     v.UserLevel,
+	}
+	return config, nil
+}

+ 359 - 0
proxy/wireguard/client.go

@@ -0,0 +1,359 @@
+package wireguard
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/hex"
+	core "github.com/v2fly/v2ray-core/v4"
+	"github.com/v2fly/v2ray-core/v4/common"
+	"github.com/v2fly/v2ray-core/v4/common/buf"
+	"github.com/v2fly/v2ray-core/v4/common/net"
+	"github.com/v2fly/v2ray-core/v4/common/protocol"
+	"github.com/v2fly/v2ray-core/v4/common/session"
+	"github.com/v2fly/v2ray-core/v4/common/signal"
+	"github.com/v2fly/v2ray-core/v4/common/signal/done"
+	"github.com/v2fly/v2ray-core/v4/common/task"
+	"github.com/v2fly/v2ray-core/v4/features/dns"
+	"github.com/v2fly/v2ray-core/v4/features/policy"
+	"github.com/v2fly/v2ray-core/v4/features/routing"
+	"github.com/v2fly/v2ray-core/v4/proxy"
+	"github.com/v2fly/v2ray-core/v4/transport"
+	"github.com/v2fly/v2ray-core/v4/transport/internet"
+	"golang.zx2c4.com/wireguard/conn"
+	"golang.zx2c4.com/wireguard/device"
+	"golang.zx2c4.com/wireguard/tun"
+	"strings"
+	"sync"
+)
+
+func init() {
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		o := new(Outbound)
+		err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher, policyManager policy.Manager, dnsClient dns.Client) error {
+			o.ctx = ctx
+			o.dispatcher = dispatcher
+			o.dnsClient = dnsClient
+			o.init = done.New()
+			return o.Init(config.(*Config), policyManager)
+		})
+		return o, err
+	}))
+	common.Must(common.RegisterConfig((*SimplifiedConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		o := new(Outbound)
+		err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher, policyManager policy.Manager, dnsClient dns.Client) error {
+			sf := config.(*SimplifiedConfig)
+			cf := &Config{
+				Server: &protocol.ServerEndpoint{
+					Address: sf.Address,
+					Port:    sf.Port,
+				},
+				Network:       sf.Network,
+				PrivateKey:    sf.PrivateKey,
+				PeerPublicKey: sf.PeerPublicKey,
+				PreSharedKey:  sf.PreSharedKey,
+				Mtu:           sf.Mtu,
+				UserLevel:     sf.UserLevel,
+			}
+			o.ctx = ctx
+			o.dispatcher = dispatcher
+			o.dnsClient = dnsClient
+			o.init = done.New()
+			return o.Init(cf, policyManager)
+		})
+		return o, err
+	}))
+}
+
+var _ proxy.Outbound = (*Outbound)(nil)
+var _ conn.Bind = (*Outbound)(nil)
+
+type Outbound struct {
+	sync.Mutex
+
+	ctx           context.Context
+	dispatcher    routing.Dispatcher
+	sessionPolicy policy.Session
+	dnsClient     dns.Client
+
+	tun    tun.Device
+	dev    *device.Device
+	wire   *Net
+	dialer internet.Dialer
+
+	init        *done.Instance
+	destination net.Destination
+	endpoint    *conn.StdNetEndpoint
+	connection  *remoteConnection
+}
+
+func (o *Outbound) Init(config *Config, policyManager policy.Manager) error {
+	o.sessionPolicy = policyManager.ForLevel(config.UserLevel)
+	spec, err := protocol.NewServerSpecFromPB(config.Server)
+	if err != nil {
+		return err
+	}
+
+	o.destination = spec.Destination()
+	o.endpoint = &conn.StdNetEndpoint{
+		Port: int(o.destination.Port),
+	}
+
+	if o.destination.Address.Family().IsDomain() {
+		o.endpoint.IP = []byte{172, 19, 0, 3}
+	} else {
+		o.endpoint.IP = o.destination.Address.IP()
+	}
+
+	localAddress := make([]net.IP, len(config.LocalAddress))
+	if len(localAddress) == 0 {
+		return newError("empty local address")
+	}
+	for index, address := range config.LocalAddress {
+		localAddress[index] = net.ParseIP(address)
+	}
+
+	var privateKey, peerPublicKey, preSharedKey string
+	{
+		decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(config.PrivateKey))
+		bytes, err := buf.ReadAllToBytes(decoder)
+		if err != nil {
+			return newError("failed to decode private key from base64: ", config.PrivateKey).Base(err)
+		}
+		privateKey = hex.EncodeToString(bytes)
+	}
+	{
+		decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(config.PeerPublicKey))
+		bytes, err := buf.ReadAllToBytes(decoder)
+		if err != nil {
+			return newError("failed to decode peer public key from base64: ", config.PeerPublicKey).Base(err)
+		}
+		peerPublicKey = hex.EncodeToString(bytes)
+	}
+	if config.PreSharedKey != "" {
+		decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(config.PreSharedKey))
+		bytes, err := buf.ReadAllToBytes(decoder)
+		if err != nil {
+			return newError("failed to decode pre share key from base64: ", config.PreSharedKey).Base(err)
+		}
+		preSharedKey = hex.EncodeToString(bytes)
+	}
+	ipcConf := "private_key=" + privateKey
+	ipcConf += "\npublic_key=" + peerPublicKey
+	ipcConf += "\nendpoint=" + o.endpoint.DstToString()
+
+	if preSharedKey != "" {
+		ipcConf += "\npreshared_key=" + preSharedKey
+	}
+
+	var has4, has6 bool
+
+	for _, address := range localAddress {
+		if address.To4() != nil {
+			has4 = true
+		} else {
+			has6 = true
+		}
+	}
+
+	if has4 {
+		ipcConf += "\nallowed_ip=0.0.0.0/0"
+	}
+
+	if has6 {
+		ipcConf += "\nallowed_ip=::/0"
+	}
+
+	mtu := int(config.Mtu)
+	if mtu == 0 {
+		mtu = 1450
+	}
+	tun, wire, err := CreateNetTUN(localAddress, mtu)
+
+	if err != nil {
+		return newError("failed to create wireguard device").Base(err)
+	}
+
+	dev := device.NewDevice(tun, o, device.NewLogger(device.LogLevelVerbose, ""))
+	err = dev.IpcSet(ipcConf)
+	if err != nil {
+		return newError("failed to set wireguard ipc conf").Base(err)
+	}
+
+	o.tun = tun
+	o.dev = dev
+	o.wire = wire
+
+	return nil
+}
+
+func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
+	if o.dialer == nil {
+		o.dialer = dialer
+	}
+	o.init.Close()
+
+	outbound := session.OutboundFromContext(ctx)
+	if outbound == nil || !outbound.Target.IsValid() {
+		return newError("target not specified")
+	}
+	destination := outbound.Target
+
+	if destination.Address.Family().IsDomain() {
+		if c, ok := o.dnsClient.(dns.ClientWithIPOption); ok {
+			c.SetFakeDNSOption(false)
+		}
+		ips, err := o.dnsClient.LookupIP(destination.Address.Domain())
+		if err != nil {
+			return newError("failed to lookup ip addresses for domain ", destination.Address.Domain()).Base(err)
+		}
+		destination.Address = net.IPAddress(ips[0])
+	}
+
+	var conn internet.Connection
+	{
+		var err error
+
+		switch destination.Network {
+		case net.Network_TCP:
+			conn, err = o.wire.DialContextTCP(ctx, &net.TCPAddr{
+				IP:   destination.Address.IP(),
+				Port: int(destination.Port),
+			})
+		case net.Network_UDP:
+			conn, err = o.wire.DialUDP(nil, &net.UDPAddr{
+				IP:   destination.Address.IP(),
+				Port: int(destination.Port),
+			})
+		}
+
+		if err != nil {
+			return err
+		}
+	}
+
+	defer conn.Close()
+
+	ctx, cancel := context.WithCancel(ctx)
+	timer := signal.CancelAfterInactivity(ctx, cancel, o.sessionPolicy.Timeouts.ConnectionIdle)
+	ctx = policy.ContextWithBufferPolicy(ctx, o.sessionPolicy.Buffer)
+
+	uplink := func() error {
+		defer timer.SetTimeout(o.sessionPolicy.Timeouts.UplinkOnly)
+
+		if err := buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer)); err != nil {
+			return newError("failed to transport all TCP response").Base(err)
+		}
+
+		return nil
+	}
+
+	downlink := func() error {
+		defer timer.SetTimeout(o.sessionPolicy.Timeouts.DownlinkOnly)
+
+		if err := buf.Copy(buf.NewReader(conn), link.Writer, buf.UpdateActivity(timer)); err != nil {
+			return newError("failed to transport all TCP request").Base(err)
+		}
+
+		return nil
+	}
+
+	if err := task.Run(ctx, uplink, downlink); err != nil {
+		common.Interrupt(link.Reader)
+		common.Interrupt(link.Writer)
+		return newError("connection ends").Base(err)
+	}
+
+	return nil
+
+}
+
+type remoteConnection struct {
+	internet.Connection
+	done *done.Instance
+}
+
+func (r remoteConnection) Close() error {
+	if !r.done.Done() {
+		r.done.Close()
+	}
+	return r.Connection.Close()
+}
+
+func (o *Outbound) connect() (*remoteConnection, error) {
+	if o.dialer == nil {
+		<-o.init.Wait()
+	}
+
+	if c := o.connection; c != nil && !c.done.Done() {
+		return c, nil
+	}
+
+	o.Lock()
+	defer o.Unlock()
+
+	if c := o.connection; c != nil && !c.done.Done() {
+		return c, nil
+	}
+
+	conn, err := o.dialer.Dial(context.Background(), o.destination)
+	if err == nil {
+		o.connection = &remoteConnection{
+			conn,
+			done.New(),
+		}
+	}
+
+	return o.connection, err
+}
+
+func (o *Outbound) Open(uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) {
+	return []conn.ReceiveFunc{o.Receive}, 0, nil
+}
+
+func (o *Outbound) Receive(b []byte) (n int, ep conn.Endpoint, err error) {
+	var c *remoteConnection
+	c, err = o.connect()
+	if err != nil {
+		return
+	}
+	n, err = c.Read(b)
+	if err != nil {
+		common.Close(c)
+	} else {
+		ep = o.endpoint
+	}
+	return
+}
+
+func (o *Outbound) Close() error {
+	o.Lock()
+	defer o.Unlock()
+
+	c := o.connection
+	if c != nil {
+		common.Close(c)
+	}
+
+	return nil
+}
+
+func (o *Outbound) SetMark(uint32) error {
+	return nil
+}
+
+func (o *Outbound) Send(b []byte, _ conn.Endpoint) (err error) {
+	var c *remoteConnection
+	c, err = o.connect()
+	if err != nil {
+		return
+	}
+	_, err = c.Write(b)
+	if err != nil {
+		common.Close(c)
+	}
+	return err
+}
+
+func (o *Outbound) ParseEndpoint(string) (conn.Endpoint, error) {
+	return o.endpoint, nil
+}

+ 258 - 0
proxy/wireguard/codec.go

@@ -0,0 +1,258 @@
+package wireguard
+
+import (
+	"context"
+	"fmt"
+	"golang.zx2c4.com/wireguard/tun"
+	"net"
+	"os"
+
+	"gvisor.dev/gvisor/pkg/tcpip"
+	"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
+	"gvisor.dev/gvisor/pkg/tcpip/buffer"
+	"gvisor.dev/gvisor/pkg/tcpip/header"
+	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
+	"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
+	"gvisor.dev/gvisor/pkg/tcpip/stack"
+	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
+	"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
+)
+
+type netTun struct {
+	stack          *stack.Stack
+	dispatcher     stack.NetworkDispatcher
+	events         chan tun.Event
+	incomingPacket chan buffer.VectorisedView
+	mtu            int
+	hasV4, hasV6   bool
+}
+type endpoint netTun
+
+// WritePackets writes packets back into io.ReadWriter.
+func (e *endpoint) WritePackets(_ stack.RouteInfo, pkts stack.PacketBufferList, _ tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
+	n := 0
+	for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
+		if err := e.WriteRawPacket(pkt); err != nil {
+			break
+		}
+		n++
+	}
+	return n, nil
+}
+
+func (e *endpoint) WriteRawPacket(buffer *stack.PacketBuffer) tcpip.Error {
+	data := buffer.Data().ExtractVV()
+	_, err := (*netTun)(e).Write(data.ToView(), 0)
+	if err != nil {
+		return &tcpip.ErrAborted{}
+	}
+	return nil
+}
+
+type Net netTun
+
+func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
+	e.dispatcher = dispatcher
+}
+
+func (e *endpoint) IsAttached() bool {
+	return e.dispatcher != nil
+}
+
+func (e *endpoint) MTU() uint32 {
+	mtu, err := (*netTun)(e).MTU()
+	if err != nil {
+		panic(err)
+	}
+	return uint32(mtu)
+}
+
+func (*endpoint) Capabilities() stack.LinkEndpointCapabilities {
+	return stack.CapabilityNone
+}
+
+func (*endpoint) MaxHeaderLength() uint16 {
+	return 0
+}
+
+func (*endpoint) LinkAddress() tcpip.LinkAddress {
+	return ""
+}
+
+func (*endpoint) Wait() {}
+
+func (e *endpoint) WritePacket(_ stack.RouteInfo, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
+	e.incomingPacket <- buffer.NewVectorisedView(pkt.Size(), pkt.Views())
+	return nil
+}
+
+func (*endpoint) ARPHardwareType() header.ARPHardwareType {
+	return header.ARPHardwareNone
+}
+
+func (e *endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) {
+}
+
+func CreateNetTUN(localAddresses []net.IP, mtu int) (tun.Device, *Net, error) {
+	opts := stack.Options{
+		NetworkProtocols:   []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
+		TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
+		HandleLocal:        true,
+	}
+	dev := &netTun{
+		stack:          stack.New(opts),
+		events:         make(chan tun.Event, 10),
+		incomingPacket: make(chan buffer.VectorisedView),
+		mtu:            mtu,
+	}
+	tcpipErr := dev.stack.CreateNIC(1, (*endpoint)(dev))
+	if tcpipErr != nil {
+		return nil, nil, fmt.Errorf("CreateNIC: %v", tcpipErr)
+	}
+
+	for _, ip := range localAddresses {
+		if ip4 := ip.To4(); ip4 != nil {
+			protoAddr := tcpip.ProtocolAddress{
+				Protocol:          ipv4.ProtocolNumber,
+				AddressWithPrefix: tcpip.Address(ip4).WithPrefix(),
+			}
+			tcpipErr := dev.stack.AddProtocolAddress(1, protoAddr, stack.AddressProperties{})
+			if tcpipErr != nil {
+				return nil, nil, fmt.Errorf("AddProtocolAddress(%v): %v", ip4, tcpipErr)
+			}
+			dev.hasV4 = true
+		} else {
+			protoAddr := tcpip.ProtocolAddress{
+				Protocol:          ipv6.ProtocolNumber,
+				AddressWithPrefix: tcpip.Address(ip).WithPrefix(),
+			}
+			tcpipErr := dev.stack.AddProtocolAddress(1, protoAddr, stack.AddressProperties{})
+			if tcpipErr != nil {
+				return nil, nil, fmt.Errorf("AddProtocolAddress(%v): %v", ip, tcpipErr)
+			}
+			dev.hasV6 = true
+		}
+	}
+	if dev.hasV4 {
+		dev.stack.AddRoute(tcpip.Route{Destination: header.IPv4EmptySubnet, NIC: 1})
+	}
+	if dev.hasV6 {
+		dev.stack.AddRoute(tcpip.Route{Destination: header.IPv6EmptySubnet, NIC: 1})
+	}
+
+	dev.events <- tun.EventUp
+	return dev, (*Net)(dev), nil
+}
+
+func (tun *netTun) Name() (string, error) {
+	return "go", nil
+}
+
+func (tun *netTun) File() *os.File {
+	return nil
+}
+
+func (tun *netTun) Events() chan tun.Event {
+	return tun.events
+}
+
+func (tun *netTun) Read(buf []byte, offset int) (int, error) {
+	view, ok := <-tun.incomingPacket
+	if !ok {
+		return 0, os.ErrClosed
+	}
+	return view.Read(buf[offset:])
+}
+
+func (tun *netTun) Write(buf []byte, offset int) (int, error) {
+	packet := buf[offset:]
+	if len(packet) == 0 {
+		return 0, nil
+	}
+
+	pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{Data: buffer.NewVectorisedView(len(packet), []buffer.View{buffer.NewViewFromBytes(packet)})})
+	switch packet[0] >> 4 {
+	case 4:
+		tun.dispatcher.DeliverNetworkPacket("", "", ipv4.ProtocolNumber, pkb)
+	case 6:
+		tun.dispatcher.DeliverNetworkPacket("", "", ipv6.ProtocolNumber, pkb)
+	}
+
+	return len(buf), nil
+}
+
+func (tun *netTun) Flush() error {
+	return nil
+}
+
+func (tun *netTun) Close() error {
+	tun.stack.RemoveNIC(1)
+
+	if tun.events != nil {
+		close(tun.events)
+	}
+	if tun.incomingPacket != nil {
+		close(tun.incomingPacket)
+	}
+	return nil
+}
+
+func (tun *netTun) MTU() (int, error) {
+	return tun.mtu, nil
+}
+
+func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
+	if ip4 := ip.To4(); ip4 != nil {
+		return tcpip.FullAddress{
+			NIC:  1,
+			Addr: tcpip.Address(ip4),
+			Port: uint16(port),
+		}, ipv4.ProtocolNumber
+	} else {
+		return tcpip.FullAddress{
+			NIC:  1,
+			Addr: tcpip.Address(ip),
+			Port: uint16(port),
+		}, ipv6.ProtocolNumber
+	}
+}
+
+func (net *Net) DialContextTCP(ctx context.Context, addr *net.TCPAddr) (*gonet.TCPConn, error) {
+	if addr == nil {
+		panic("todo: deal with auto addr semantics for nil addr")
+	}
+	fa, pn := convertToFullAddr(addr.IP, addr.Port)
+	return gonet.DialContextTCP(ctx, net.stack, fa, pn)
+}
+
+func (net *Net) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) {
+	if addr == nil {
+		panic("todo: deal with auto addr semantics for nil addr")
+	}
+	fa, pn := convertToFullAddr(addr.IP, addr.Port)
+	return gonet.DialTCP(net.stack, fa, pn)
+}
+
+func (net *Net) ListenTCP(addr *net.TCPAddr) (*gonet.TCPListener, error) {
+	if addr == nil {
+		panic("todo: deal with auto addr semantics for nil addr")
+	}
+	fa, pn := convertToFullAddr(addr.IP, addr.Port)
+	return gonet.ListenTCP(net.stack, fa, pn)
+}
+
+func (net *Net) DialUDP(laddr, raddr *net.UDPAddr) (*gonet.UDPConn, error) {
+	var lfa, rfa *tcpip.FullAddress
+	var pn tcpip.NetworkProtocolNumber
+	if laddr != nil {
+		var addr tcpip.FullAddress
+		addr, pn = convertToFullAddr(laddr.IP, laddr.Port)
+		lfa = &addr
+	}
+	if raddr != nil {
+		var addr tcpip.FullAddress
+		addr, pn = convertToFullAddr(raddr.IP, raddr.Port)
+		rfa = &addr
+	}
+	return gonet.DialUDP(net.stack, lfa, rfa, pn)
+}

+ 390 - 0
proxy/wireguard/config.pb.go

@@ -0,0 +1,390 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.17.3
+// source: proxy/wireguard/config.proto
+
+package wireguard
+
+import (
+	net "github.com/v2fly/v2ray-core/v4/common/net"
+	protocol "github.com/v2fly/v2ray-core/v4/common/protocol"
+	_ "github.com/v2fly/v2ray-core/v4/common/protoext"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Config struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Server        *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
+	Network       net.Network              `protobuf:"varint,2,opt,name=network,proto3,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
+	LocalAddress  []string                 `protobuf:"bytes,3,rep,name=localAddress,proto3" json:"localAddress,omitempty"`
+	PrivateKey    string                   `protobuf:"bytes,4,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"`
+	PeerPublicKey string                   `protobuf:"bytes,5,opt,name=peer_public_key,json=peerPublicKey,proto3" json:"peer_public_key,omitempty"`
+	PreSharedKey  string                   `protobuf:"bytes,6,opt,name=pre_shared_key,json=preSharedKey,proto3" json:"pre_shared_key,omitempty"`
+	Mtu           uint32                   `protobuf:"varint,7,opt,name=mtu,proto3" json:"mtu,omitempty"`
+	UserLevel     uint32                   `protobuf:"varint,8,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
+}
+
+func (x *Config) Reset() {
+	*x = Config{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proxy_wireguard_config_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Config) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Config) ProtoMessage() {}
+
+func (x *Config) ProtoReflect() protoreflect.Message {
+	mi := &file_proxy_wireguard_config_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Config.ProtoReflect.Descriptor instead.
+func (*Config) Descriptor() ([]byte, []int) {
+	return file_proxy_wireguard_config_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Config) GetServer() *protocol.ServerEndpoint {
+	if x != nil {
+		return x.Server
+	}
+	return nil
+}
+
+func (x *Config) GetNetwork() net.Network {
+	if x != nil {
+		return x.Network
+	}
+	return net.Network(0)
+}
+
+func (x *Config) GetLocalAddress() []string {
+	if x != nil {
+		return x.LocalAddress
+	}
+	return nil
+}
+
+func (x *Config) GetPrivateKey() string {
+	if x != nil {
+		return x.PrivateKey
+	}
+	return ""
+}
+
+func (x *Config) GetPeerPublicKey() string {
+	if x != nil {
+		return x.PeerPublicKey
+	}
+	return ""
+}
+
+func (x *Config) GetPreSharedKey() string {
+	if x != nil {
+		return x.PreSharedKey
+	}
+	return ""
+}
+
+func (x *Config) GetMtu() uint32 {
+	if x != nil {
+		return x.Mtu
+	}
+	return 0
+}
+
+func (x *Config) GetUserLevel() uint32 {
+	if x != nil {
+		return x.UserLevel
+	}
+	return 0
+}
+
+type SimplifiedConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Address       *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+	Port          uint32          `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
+	Network       net.Network     `protobuf:"varint,3,opt,name=network,proto3,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
+	LocalAddress  []string        `protobuf:"bytes,4,rep,name=localAddress,proto3" json:"localAddress,omitempty"`
+	PrivateKey    string          `protobuf:"bytes,5,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"`
+	PeerPublicKey string          `protobuf:"bytes,6,opt,name=peer_public_key,json=peerPublicKey,proto3" json:"peer_public_key,omitempty"`
+	PreSharedKey  string          `protobuf:"bytes,7,opt,name=pre_shared_key,json=preSharedKey,proto3" json:"pre_shared_key,omitempty"`
+	Mtu           uint32          `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"`
+	UserLevel     uint32          `protobuf:"varint,9,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
+}
+
+func (x *SimplifiedConfig) Reset() {
+	*x = SimplifiedConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proxy_wireguard_config_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SimplifiedConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SimplifiedConfig) ProtoMessage() {}
+
+func (x *SimplifiedConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_proxy_wireguard_config_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SimplifiedConfig.ProtoReflect.Descriptor instead.
+func (*SimplifiedConfig) Descriptor() ([]byte, []int) {
+	return file_proxy_wireguard_config_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SimplifiedConfig) GetAddress() *net.IPOrDomain {
+	if x != nil {
+		return x.Address
+	}
+	return nil
+}
+
+func (x *SimplifiedConfig) GetPort() uint32 {
+	if x != nil {
+		return x.Port
+	}
+	return 0
+}
+
+func (x *SimplifiedConfig) GetNetwork() net.Network {
+	if x != nil {
+		return x.Network
+	}
+	return net.Network(0)
+}
+
+func (x *SimplifiedConfig) GetLocalAddress() []string {
+	if x != nil {
+		return x.LocalAddress
+	}
+	return nil
+}
+
+func (x *SimplifiedConfig) GetPrivateKey() string {
+	if x != nil {
+		return x.PrivateKey
+	}
+	return ""
+}
+
+func (x *SimplifiedConfig) GetPeerPublicKey() string {
+	if x != nil {
+		return x.PeerPublicKey
+	}
+	return ""
+}
+
+func (x *SimplifiedConfig) GetPreSharedKey() string {
+	if x != nil {
+		return x.PreSharedKey
+	}
+	return ""
+}
+
+func (x *SimplifiedConfig) GetMtu() uint32 {
+	if x != nil {
+		return x.Mtu
+	}
+	return 0
+}
+
+func (x *SimplifiedConfig) GetUserLevel() uint32 {
+	if x != nil {
+		return x.UserLevel
+	}
+	return 0
+}
+
+var File_proxy_wireguard_config_proto protoreflect.FileDescriptor
+
+var file_proxy_wireguard_config_proto_rawDesc = []byte{
+	0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72,
+	0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a,
+	0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
+	0x2e, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x63,
+	0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2f, 0x65,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+	0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x22, 0xca, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42,
+	0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a,
+	0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76,
+	0x65, 0x72, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
+	0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77,
+	0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x0c,
+	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65,
+	0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
+	0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72,
+	0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x65,
+	0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6d, 0x74,
+	0x75, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
+	0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c,
+	0x22, 0x80, 0x03, 0x0a, 0x10, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
+	0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49,
+	0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
+	0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
+	0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
+	0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,
+	0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+	0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64,
+	0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f,
+	0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61,
+	0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75,
+	0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
+	0x70, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a,
+	0x0e, 0x70, 0x72, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,
+	0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d,
+	0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65,
+	0x76, 0x65, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c,
+	0x65, 0x76, 0x65, 0x6c, 0x3a, 0x1d, 0x82, 0xb5, 0x18, 0x0a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x62,
+	0x6f, 0x75, 0x6e, 0x64, 0x82, 0xb5, 0x18, 0x0b, 0x12, 0x09, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75,
+	0x61, 0x72, 0x64, 0x42, 0x6f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
+	0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x77, 0x69, 0x72, 0x65,
+	0x67, 0x75, 0x61, 0x72, 0x64, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d,
+	0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x77, 0x69,
+	0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
+	0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x57, 0x69, 0x72, 0x65, 0x47,
+	0x75, 0x61, 0x72, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_proxy_wireguard_config_proto_rawDescOnce sync.Once
+	file_proxy_wireguard_config_proto_rawDescData = file_proxy_wireguard_config_proto_rawDesc
+)
+
+func file_proxy_wireguard_config_proto_rawDescGZIP() []byte {
+	file_proxy_wireguard_config_proto_rawDescOnce.Do(func() {
+		file_proxy_wireguard_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_wireguard_config_proto_rawDescData)
+	})
+	return file_proxy_wireguard_config_proto_rawDescData
+}
+
+var file_proxy_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_proxy_wireguard_config_proto_goTypes = []interface{}{
+	(*Config)(nil),                  // 0: v2ray.core.proxy.wireguard.Config
+	(*SimplifiedConfig)(nil),        // 1: v2ray.core.proxy.wireguard.SimplifiedConfig
+	(*protocol.ServerEndpoint)(nil), // 2: v2ray.core.common.protocol.ServerEndpoint
+	(net.Network)(0),                // 3: v2ray.core.common.net.Network
+	(*net.IPOrDomain)(nil),          // 4: v2ray.core.common.net.IPOrDomain
+}
+var file_proxy_wireguard_config_proto_depIdxs = []int32{
+	2, // 0: v2ray.core.proxy.wireguard.Config.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
+	3, // 1: v2ray.core.proxy.wireguard.Config.network:type_name -> v2ray.core.common.net.Network
+	4, // 2: v2ray.core.proxy.wireguard.SimplifiedConfig.address:type_name -> v2ray.core.common.net.IPOrDomain
+	3, // 3: v2ray.core.proxy.wireguard.SimplifiedConfig.network:type_name -> v2ray.core.common.net.Network
+	4, // [4:4] is the sub-list for method output_type
+	4, // [4:4] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_proxy_wireguard_config_proto_init() }
+func file_proxy_wireguard_config_proto_init() {
+	if File_proxy_wireguard_config_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_proxy_wireguard_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Config); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proxy_wireguard_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SimplifiedConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proxy_wireguard_config_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proxy_wireguard_config_proto_goTypes,
+		DependencyIndexes: file_proxy_wireguard_config_proto_depIdxs,
+		MessageInfos:      file_proxy_wireguard_config_proto_msgTypes,
+	}.Build()
+	File_proxy_wireguard_config_proto = out.File
+	file_proxy_wireguard_config_proto_rawDesc = nil
+	file_proxy_wireguard_config_proto_goTypes = nil
+	file_proxy_wireguard_config_proto_depIdxs = nil
+}

+ 38 - 0
proxy/wireguard/config.proto

@@ -0,0 +1,38 @@
+syntax = "proto3";
+
+package v2ray.core.proxy.wireguard;
+option csharp_namespace = "V2Ray.Core.Proxy.WireGuard";
+option go_package = "github.com/v2fly/v2ray-core/v4/proxy/wireguard";
+option java_package = "com.v2ray.core.proxy.wireguard";
+option java_multiple_files = true;
+
+import "common/protocol/server_spec.proto";
+import "common/protoext/extensions.proto";
+import "common/net/address.proto";
+import "common/net/network.proto";
+
+message Config {
+  v2ray.core.common.protocol.ServerEndpoint server = 1;
+  v2ray.core.common.net.Network network = 2;
+  repeated string localAddress = 3;
+  string private_key = 4;
+  string peer_public_key = 5;
+  string pre_shared_key = 6;
+  uint32 mtu = 7;
+  uint32 user_level = 8;
+}
+
+message SimplifiedConfig {
+  option (v2ray.core.common.protoext.message_opt).type = "outbound";
+  option (v2ray.core.common.protoext.message_opt).short_name = "wireguard";
+
+  v2ray.core.common.net.IPOrDomain address = 1;
+  uint32 port = 2;
+  v2ray.core.common.net.Network network = 3;
+  repeated string localAddress = 4;
+  string private_key = 5;
+  string peer_public_key = 6;
+  string pre_shared_key = 7;
+  uint32 mtu = 8;
+  uint32 user_level = 9;
+}

+ 9 - 0
proxy/wireguard/errors.generated.go

@@ -0,0 +1,9 @@
+package wireguard
+
+import "github.com/v2fly/v2ray-core/v4/common/errors"
+
+type errPathObjHolder struct{}
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).WithPathObj(errPathObjHolder{})
+}

+ 4 - 0
proxy/wireguard/wireguard.go

@@ -0,0 +1,4 @@
+package wireguard
+
+//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
+

Some files were not shown because too many files changed in this diff