prototype of vpndialer

pull/298/merge
Darien Raymond 8 years ago
parent 61b6b6fff5
commit c5aa4acb35
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169

@ -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 return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
} }
type StreamMode int
const (
ModeStream StreamMode = iota
ModePacket
)
type AuthenticationReader struct { type AuthenticationReader struct {
auth Authenticator auth Authenticator
buffer *buf.Buffer buffer *buf.Buffer

@ -20,6 +20,13 @@ func BytesToUint32(value []byte) uint32 {
uint32(value[3]) 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. // 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 { func BytesToInt64(value []byte) int64 {
return int64(value[0])<<56 | 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. // UseAlternativeSystemDialer replaces the current system dialer with a given one.
// Caller must ensure there is no race condition. // Caller must ensure there is no race condition.
func UseAlternativeSystemDialer(dialer SystemDialer) { func UseAlternativeSystemDialer(dialer SystemDialer) {
if dialer == nil {
effectiveSystemDialer = &DefaultSystemDialer{}
}
effectiveSystemDialer = dialer effectiveSystemDialer = dialer
} }
func init() { func init() {
effectiveSystemDialer = &DefaultSystemDialer{} UseAlternativeSystemDialer(nil)
} }

Loading…
Cancel
Save