1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 09:50:43 +00:00

prototype of vpndialer

This commit is contained in:
Darien Raymond 2017-04-30 23:37:30 +02:00
parent 61b6b6fff5
commit c5aa4acb35
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
8 changed files with 307 additions and 1 deletions

View File

@ -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,
}

View File

@ -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;
}

View File

@ -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")
}

218
app/vpndialer/unix/unix.go Normal file
View File

@ -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))
}))
}

View File

@ -0,0 +1 @@
package vpndialer

View File

@ -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

View File

@ -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 |

View File

@ -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)
}