mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-21 09:36:34 -05:00
support udp redirection
This commit is contained in:
parent
956b47f6ae
commit
210a32dc12
@ -90,7 +90,7 @@ func (this *DokodemoDoor) Start() error {
|
||||
|
||||
func (this *DokodemoDoor) ListenUDP() error {
|
||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, this.handleUDPPackets)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, udp.ListenOption{Callback: this.handleUDPPackets})
|
||||
if err != nil {
|
||||
log.Error("Dokodemo failed to listen on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
||||
return err
|
||||
@ -101,9 +101,15 @@ func (this *DokodemoDoor) ListenUDP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, dest v2net.Destination) {
|
||||
this.udpServer.Dispatch(
|
||||
&proxy.SessionInfo{Source: dest, Destination: v2net.UDPDestination(this.address, this.port)}, payload, this.handleUDPResponse)
|
||||
func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, session *proxy.SessionInfo) {
|
||||
if session.Destination == nil && this.address != nil && this.port > 0 {
|
||||
session.Destination = v2net.UDPDestination(this.address, this.port)
|
||||
}
|
||||
if session.Destination == nil {
|
||||
log.Info("Dokodemo: Unknown destination, stop forwarding...")
|
||||
return
|
||||
}
|
||||
this.udpServer.Dispatch(session, payload, this.handleUDPResponse)
|
||||
}
|
||||
|
||||
func (this *DokodemoDoor) handleUDPResponse(dest v2net.Destination, payload *alloc.Buffer) {
|
||||
|
@ -71,7 +71,7 @@ func (this *Server) Start() error {
|
||||
|
||||
if this.config.UDP {
|
||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, this.handlerUDPPayload)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, udp.ListenOption{Callback: this.handlerUDPPayload})
|
||||
if err != nil {
|
||||
log.Error("Shadowsocks: Failed to listen UDP on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
||||
return err
|
||||
@ -84,9 +84,10 @@ func (this *Server) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Server) handlerUDPPayload(payload *alloc.Buffer, source v2net.Destination) {
|
||||
func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.SessionInfo) {
|
||||
defer payload.Release()
|
||||
|
||||
source := session.Source
|
||||
ivLen := this.config.Cipher.IVSize()
|
||||
iv := payload.Value[:ivLen]
|
||||
key := this.config.Key
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
func (this *Server) listenUDP() error {
|
||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, this.handleUDPPayload)
|
||||
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, udp.ListenOption{Callback: this.handleUDPPayload})
|
||||
if err != nil {
|
||||
log.Error("Socks: Failed to listen on udp ", this.meta.Address, ":", this.meta.Port)
|
||||
return err
|
||||
@ -23,7 +23,8 @@ func (this *Server) listenUDP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Server) handleUDPPayload(payload *alloc.Buffer, source v2net.Destination) {
|
||||
func (this *Server) handleUDPPayload(payload *alloc.Buffer, session *proxy.SessionInfo) {
|
||||
source := session.Source
|
||||
log.Info("Socks: Client UDP connection from ", source)
|
||||
request, err := protocol.ReadUDPRequest(payload.Value)
|
||||
payload.Release()
|
||||
|
25
transport/internet/internal/sysfd.go
Normal file
25
transport/internet/internal/sysfd.go
Normal file
@ -0,0 +1,25 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidConn = errors.New("Invalid Connection.")
|
||||
)
|
||||
|
||||
func GetSysFd(conn net.Conn) (int, error) {
|
||||
cv := reflect.ValueOf(conn)
|
||||
switch ce := cv.Elem(); ce.Kind() {
|
||||
case reflect.Struct:
|
||||
netfd := ce.FieldByName("conn").FieldByName("fd")
|
||||
switch fe := netfd.Elem(); fe.Kind() {
|
||||
case reflect.Struct:
|
||||
fd := fe.FieldByName("sysfd")
|
||||
return int(fd.Int()), nil
|
||||
}
|
||||
}
|
||||
return 0, ErrInvalidConn
|
||||
}
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
"github.com/v2ray/v2ray-core/proxy"
|
||||
"github.com/v2ray/v2ray-core/transport/internet"
|
||||
"github.com/v2ray/v2ray-core/transport/internet/udp"
|
||||
)
|
||||
@ -39,7 +40,7 @@ func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
|
||||
},
|
||||
running: true,
|
||||
}
|
||||
hub, err := udp.ListenUDP(address, port, l.OnReceive)
|
||||
hub, err := udp.ListenUDP(address, port, udp.ListenOption{Callback: l.OnReceive})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -48,9 +49,11 @@ func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (this *Listener) OnReceive(payload *alloc.Buffer, src v2net.Destination) {
|
||||
func (this *Listener) OnReceive(payload *alloc.Buffer, session *proxy.SessionInfo) {
|
||||
defer payload.Release()
|
||||
|
||||
src := session.Source
|
||||
|
||||
if valid := this.authenticator.Open(payload); !valid {
|
||||
log.Info("KCP|Listener: discarding invalid payload from ", src)
|
||||
return
|
||||
|
@ -1,15 +1,11 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidConn = errors.New("Invalid Connection.")
|
||||
"github.com/v2ray/v2ray-core/transport/internet/internal"
|
||||
)
|
||||
|
||||
type ConnectionManager interface {
|
||||
@ -27,7 +23,7 @@ func (this *RawConnection) Reusable() bool {
|
||||
func (this *RawConnection) SetReusable(b bool) {}
|
||||
|
||||
func (this *RawConnection) SysFd() (int, error) {
|
||||
return getSysFd(&this.TCPConn)
|
||||
return internal.GetSysFd(&this.TCPConn)
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
@ -106,19 +102,5 @@ func (this *Connection) Reusable() bool {
|
||||
}
|
||||
|
||||
func (this *Connection) SysFd() (int, error) {
|
||||
return getSysFd(this.conn)
|
||||
}
|
||||
|
||||
func getSysFd(conn net.Conn) (int, error) {
|
||||
cv := reflect.ValueOf(conn)
|
||||
switch ce := cv.Elem(); ce.Kind() {
|
||||
case reflect.Struct:
|
||||
netfd := ce.FieldByName("conn").FieldByName("fd")
|
||||
switch fe := netfd.Elem(); fe.Kind() {
|
||||
case reflect.Struct:
|
||||
fd := fe.FieldByName("sysfd")
|
||||
return int(fd.Int()), nil
|
||||
}
|
||||
}
|
||||
return 0, ErrInvalidConn
|
||||
return internal.GetSysFd(this.conn)
|
||||
}
|
||||
|
34
transport/internet/udp/hub_linux.go
Normal file
34
transport/internet/udp/hub_linux.go
Normal file
@ -0,0 +1,34 @@
|
||||
// +build linux
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
func SetOriginalDestOptions(fd int) error {
|
||||
if err := syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RetrieveOriginalDest(oob []byte) v2net.Destination {
|
||||
msgs, err := syscall.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_ORIGDSTADDR {
|
||||
ip := v2net.IPAddress(msg.Data[4:8])
|
||||
port := v2net.PortFromBytes(msg.Data[2:4])
|
||||
return v2net.UDPDestination(ip, port)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
15
transport/internet/udp/hub_other.go
Normal file
15
transport/internet/udp/hub_other.go
Normal file
@ -0,0 +1,15 @@
|
||||
// +build !linux
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
func SetOriginalDestOptions(fd int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RetrieveOriginalDest(oob []byte) v2net.Destination {
|
||||
return nil
|
||||
}
|
@ -5,19 +5,27 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/alloc"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/proxy"
|
||||
"github.com/v2ray/v2ray-core/transport/internet/internal"
|
||||
)
|
||||
|
||||
type UDPPayloadHandler func(*alloc.Buffer, v2net.Destination)
|
||||
type UDPPayloadHandler func(*alloc.Buffer, *proxy.SessionInfo)
|
||||
|
||||
type UDPHub struct {
|
||||
sync.RWMutex
|
||||
conn *net.UDPConn
|
||||
callback UDPPayloadHandler
|
||||
option ListenOption
|
||||
accepting bool
|
||||
}
|
||||
|
||||
func ListenUDP(address v2net.Address, port v2net.Port, callback UDPPayloadHandler) (*UDPHub, error) {
|
||||
type ListenOption struct {
|
||||
Callback UDPPayloadHandler
|
||||
ReceiveOriginalDest bool
|
||||
}
|
||||
|
||||
func ListenUDP(address v2net.Address, port v2net.Port, option ListenOption) (*UDPHub, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||
IP: address.IP(),
|
||||
Port: int(port),
|
||||
@ -25,9 +33,21 @@ func ListenUDP(address v2net.Address, port v2net.Port, callback UDPPayloadHandle
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if option.ReceiveOriginalDest {
|
||||
fd, err := internal.GetSysFd(udpConn)
|
||||
if err != nil {
|
||||
log.Warning("UDP|Listener: Failed to get fd: ", err)
|
||||
return nil, err
|
||||
}
|
||||
err = SetOriginalDestOptions(fd)
|
||||
if err != nil {
|
||||
log.Warning("UDP|Listener: Failed to set socket options: ", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
hub := &UDPHub{
|
||||
conn: udpConn,
|
||||
callback: callback,
|
||||
conn: udpConn,
|
||||
option: option,
|
||||
}
|
||||
go hub.start()
|
||||
return hub, nil
|
||||
@ -53,16 +73,22 @@ func (this *UDPHub) start() {
|
||||
this.accepting = true
|
||||
this.Unlock()
|
||||
|
||||
oobBytes := make([]byte, 256)
|
||||
for this.Running() {
|
||||
buffer := alloc.NewBuffer()
|
||||
nBytes, addr, err := this.conn.ReadFromUDP(buffer.Value)
|
||||
nBytes, noob, _, addr, err := this.conn.ReadMsgUDP(buffer.Value, oobBytes)
|
||||
if err != nil {
|
||||
buffer.Release()
|
||||
continue
|
||||
}
|
||||
buffer.Slice(0, nBytes)
|
||||
dest := v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port))
|
||||
go this.callback(buffer, dest)
|
||||
|
||||
session := new(proxy.SessionInfo)
|
||||
session.Source = v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port))
|
||||
if this.option.ReceiveOriginalDest && noob > 0 {
|
||||
session.Destination = RetrieveOriginalDest(oobBytes[:noob])
|
||||
}
|
||||
go this.option.Callback(buffer, session)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user