mirror of https://github.com/v2ray/v2ray-core
				
				
				
			prototype of vpndialer
							parent
							
								
									61b6b6fff5
								
							
						
					
					
						commit
						c5aa4acb35
					
				|  | @ -0,0 +1,52 @@ | |||
| package vpndialer | ||||
| 
 | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
| 
 | ||||
| // Reference imports to suppress errors if they are not otherwise used.
 | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
| 
 | ||||
| // This is a compile-time assertion to ensure that this generated file
 | ||||
| // is compatible with the proto package it is being compiled against.
 | ||||
| // A compilation error at this line likely means your copy of the
 | ||||
| // proto package needs to be updated.
 | ||||
| const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
 | ||||
| 
 | ||||
| type Config struct { | ||||
| 	Address string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (m *Config) Reset()                    { *m = Config{} } | ||||
| func (m *Config) String() string            { return proto.CompactTextString(m) } | ||||
| func (*Config) ProtoMessage()               {} | ||||
| func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } | ||||
| 
 | ||||
| func (m *Config) GetAddress() string { | ||||
| 	if m != nil { | ||||
| 		return m.Address | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	proto.RegisterType((*Config)(nil), "v2ray.core.app.vpndialer.Config") | ||||
| } | ||||
| 
 | ||||
| func init() { proto.RegisterFile("v2ray.com/core/app/vpndialer/config.proto", fileDescriptor0) } | ||||
| 
 | ||||
| var fileDescriptor0 = []byte{ | ||||
| 	// 150 bytes of a gzipped FileDescriptorProto
 | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2c, 0x33, 0x2a, 0x4a, | ||||
| 	0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x28, 0xd0, 0x2f, | ||||
| 	0x2b, 0xc8, 0x4b, 0xc9, 0x4c, 0xcc, 0x49, 0x2d, 0xd2, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, | ||||
| 	0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x80, 0x29, 0x2d, 0x4a, 0xd5, 0x4b, 0x2c, 0x28, 0xd0, | ||||
| 	0x83, 0x2b, 0x53, 0x52, 0xe2, 0x62, 0x73, 0x06, 0xab, 0x14, 0x92, 0xe0, 0x62, 0x4f, 0x4c, 0x49, | ||||
| 	0x29, 0x4a, 0x2d, 0x2e, 0x96, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0x71, 0x9d, 0xdc, 0xb8, | ||||
| 	0x64, 0x92, 0xf3, 0x73, 0xf5, 0x70, 0x99, 0x11, 0xc0, 0x18, 0xc5, 0x09, 0xe7, 0xac, 0x62, 0x92, | ||||
| 	0x08, 0x33, 0x0a, 0x4a, 0xac, 0xd4, 0x73, 0x06, 0xa9, 0x73, 0x2c, 0x28, 0xd0, 0x0b, 0x2b, 0xc8, | ||||
| 	0x73, 0x01, 0x4b, 0x25, 0xb1, 0x81, 0x1d, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x97, 0xfc, | ||||
| 	0x09, 0x70, 0xb9, 0x00, 0x00, 0x00, | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| syntax = "proto3"; | ||||
| 
 | ||||
| package v2ray.core.app.vpndialer; | ||||
| option csharp_namespace = "V2Ray.Core.App.VpnDialer"; | ||||
| option go_package = "vpndialer"; | ||||
| option java_package = "com.v2ray.core.app.vpndialer"; | ||||
| option java_multiple_files = true; | ||||
| 
 | ||||
| message Config { | ||||
|   string address = 1; | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| package unix | ||||
| 
 | ||||
| import "v2ray.com/core/common/errors" | ||||
| 
 | ||||
| func newError(values ...interface{}) *errors.Error { | ||||
| 	return errors.New(values...).Path("App", "VPNDialer", "Unix") | ||||
| } | ||||
|  | @ -0,0 +1,218 @@ | |||
| package unix | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"v2ray.com/core/app/vpndialer" | ||||
| 	"v2ray.com/core/common" | ||||
| 	v2net "v2ray.com/core/common/net" | ||||
| 	"v2ray.com/core/common/serial" | ||||
| 	"v2ray.com/core/transport/internet" | ||||
| ) | ||||
| 
 | ||||
| //go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg unix -path App,VPNDialer,Unix
 | ||||
| 
 | ||||
| type status int | ||||
| 
 | ||||
| const ( | ||||
| 	statusNew status = iota | ||||
| 	statusOK | ||||
| 	statusFail | ||||
| ) | ||||
| 
 | ||||
| type fdStatus struct { | ||||
| 	status   status | ||||
| 	fd       int | ||||
| 	callback chan<- error | ||||
| } | ||||
| 
 | ||||
| type protector struct { | ||||
| 	sync.Mutex | ||||
| 	address string | ||||
| 	conn    *net.UnixConn | ||||
| 	status  chan fdStatus | ||||
| } | ||||
| 
 | ||||
| func readFrom(conn *net.UnixConn, schan chan<- fdStatus) { | ||||
| 	var payload [6]byte | ||||
| 	for { | ||||
| 		_, err := conn.Read(payload[:]) | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		fd := serial.BytesToInt(payload[1:5]) | ||||
| 		s := status(payload[5]) | ||||
| 		schan <- fdStatus{ | ||||
| 			fd:     fd, | ||||
| 			status: s, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (m *protector) dial() (*net.UnixConn, error) { | ||||
| 	m.Lock() | ||||
| 	defer m.Unlock() | ||||
| 
 | ||||
| 	if m.conn != nil { | ||||
| 		return m.conn, nil | ||||
| 	} | ||||
| 
 | ||||
| 	conn, err := net.DialUnix("unix", nil, &net.UnixAddr{ | ||||
| 		Name: m.address, | ||||
| 		Net:  "unix", | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	m.conn = conn | ||||
| 	m.status = make(chan fdStatus, 32) | ||||
| 	go readFrom(conn, m.status) | ||||
| 	go m.monitor(conn) | ||||
| 	return conn, nil | ||||
| } | ||||
| 
 | ||||
| func (m *protector) close() { | ||||
| 	m.Lock() | ||||
| 	defer m.Unlock() | ||||
| 	if m.conn == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	m.conn.Close() | ||||
| 	m.conn = nil | ||||
| } | ||||
| 
 | ||||
| func (m *protector) monitor(c *net.UnixConn) { | ||||
| 	pendingFd := make(map[int]chan<- error, 32) | ||||
| 	for s := range m.status { | ||||
| 		switch s.status { | ||||
| 		case statusNew: | ||||
| 			pendingFd[s.fd] = s.callback | ||||
| 		case statusOK: | ||||
| 			if c, f := pendingFd[s.fd]; f { | ||||
| 				close(c) | ||||
| 				delete(pendingFd, s.fd) | ||||
| 			} | ||||
| 		case statusFail: | ||||
| 			if c, f := pendingFd[s.fd]; f { | ||||
| 				c <- newError("failed to protect fd") | ||||
| 				close(c) | ||||
| 				delete(pendingFd, s.fd) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (m *protector) protect(fd int) error { | ||||
| 	conn, err := m.dial() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var payload [6]byte | ||||
| 	serial.IntToBytes(fd, payload[1:1]) | ||||
| 	payload[5] = byte(statusNew) | ||||
| 	if _, err := conn.Write(payload[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	wait := make(chan error) | ||||
| 	m.status <- fdStatus{ | ||||
| 		status:   statusNew, | ||||
| 		fd:       fd, | ||||
| 		callback: wait, | ||||
| 	} | ||||
| 	return <-wait | ||||
| } | ||||
| 
 | ||||
| type App struct { | ||||
| 	protector *protector | ||||
| 	dialer    *Dialer | ||||
| } | ||||
| 
 | ||||
| func NewApp(ctx context.Context, config *vpndialer.Config) (*App, error) { | ||||
| 	a := &App{ | ||||
| 		dialer: &Dialer{}, | ||||
| 		protector: &protector{ | ||||
| 			address: config.Address, | ||||
| 		}, | ||||
| 	} | ||||
| 	a.dialer.protect = a.protector.protect | ||||
| 	return a, nil | ||||
| } | ||||
| 
 | ||||
| func (*App) Interface() interface{} { | ||||
| 	return (*App)(nil) | ||||
| } | ||||
| 
 | ||||
| func (a *App) Start() error { | ||||
| 	internet.UseAlternativeSystemDialer(a.dialer) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (a *App) Close() { | ||||
| 	internet.UseAlternativeSystemDialer(nil) | ||||
| } | ||||
| 
 | ||||
| type Dialer struct { | ||||
| 	protect func(fd int) error | ||||
| } | ||||
| 
 | ||||
| func socket(dest v2net.Destination) (int, error) { | ||||
| 	switch dest.Network { | ||||
| 	case v2net.Network_TCP: | ||||
| 		return unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, unix.IPPROTO_TCP) | ||||
| 	case v2net.Network_UDP: | ||||
| 		return unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP) | ||||
| 	default: | ||||
| 		return 0, newError("unknown network ", dest.Network) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getIP(addr v2net.Address) (net.IP, error) { | ||||
| 	if addr.Family().Either(v2net.AddressFamilyIPv4, v2net.AddressFamilyIPv6) { | ||||
| 		return addr.IP(), nil | ||||
| 	} | ||||
| 	ips, err := net.LookupIP(addr.Domain()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return ips[0], nil | ||||
| } | ||||
| 
 | ||||
| func (d *Dialer) Dial(ctx context.Context, source v2net.Address, dest v2net.Destination) (net.Conn, error) { | ||||
| 	fd, err := socket(dest) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := d.protect(fd); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	ip, err := getIP(dest.Address) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	addr := &unix.SockaddrInet6{ | ||||
| 		Port:   int(dest.Port), | ||||
| 		ZoneId: 0, | ||||
| 	} | ||||
| 	copy(addr.Addr[:], ip.To16()) | ||||
| 
 | ||||
| 	if err := unix.Connect(fd, addr); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	file := os.NewFile(uintptr(fd), "Socket") | ||||
| 	return net.FileConn(file) | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	common.Must(common.RegisterConfig((*vpndialer.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { | ||||
| 		return NewApp(ctx, config.(*vpndialer.Config)) | ||||
| 	})) | ||||
| } | ||||
|  | @ -0,0 +1 @@ | |||
| package vpndialer | ||||
|  | @ -60,6 +60,13 @@ func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) { | |||
| 	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil | ||||
| } | ||||
| 
 | ||||
| type StreamMode int | ||||
| 
 | ||||
| const ( | ||||
| 	ModeStream StreamMode = iota | ||||
| 	ModePacket | ||||
| ) | ||||
| 
 | ||||
| type AuthenticationReader struct { | ||||
| 	auth       Authenticator | ||||
| 	buffer     *buf.Buffer | ||||
|  |  | |||
|  | @ -20,6 +20,13 @@ func BytesToUint32(value []byte) uint32 { | |||
| 		uint32(value[3]) | ||||
| } | ||||
| 
 | ||||
| func BytesToInt(value []byte) int { | ||||
| 	return int(value[0])<<24 | | ||||
| 		int(value[1])<<16 | | ||||
| 		int(value[2])<<8 | | ||||
| 		int(value[3]) | ||||
| } | ||||
| 
 | ||||
| // BytesToInt64 deserializes a byte array to an int64 in big endian order. The byte array must have at least 8 elements.
 | ||||
| func BytesToInt64(value []byte) int64 { | ||||
| 	return int64(value[0])<<56 | | ||||
|  |  | |||
|  | @ -63,9 +63,12 @@ func (v *SimpleSystemDialer) Dial(ctx context.Context, src v2net.Address, dest v | |||
| // UseAlternativeSystemDialer replaces the current system dialer with a given one.
 | ||||
| // Caller must ensure there is no race condition.
 | ||||
| func UseAlternativeSystemDialer(dialer SystemDialer) { | ||||
| 	if dialer == nil { | ||||
| 		effectiveSystemDialer = &DefaultSystemDialer{} | ||||
| 	} | ||||
| 	effectiveSystemDialer = dialer | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	effectiveSystemDialer = &DefaultSystemDialer{} | ||||
| 	UseAlternativeSystemDialer(nil) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Darien Raymond
						Darien Raymond