mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-02 15:36:41 -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 {
|
func (this *DokodemoDoor) ListenUDP() error {
|
||||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
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 {
|
if err != nil {
|
||||||
log.Error("Dokodemo failed to listen on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
log.Error("Dokodemo failed to listen on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
||||||
return err
|
return err
|
||||||
@ -101,9 +101,15 @@ func (this *DokodemoDoor) ListenUDP() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, dest v2net.Destination) {
|
func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, session *proxy.SessionInfo) {
|
||||||
this.udpServer.Dispatch(
|
if session.Destination == nil && this.address != nil && this.port > 0 {
|
||||||
&proxy.SessionInfo{Source: dest, Destination: v2net.UDPDestination(this.address, this.port)}, payload, this.handleUDPResponse)
|
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) {
|
func (this *DokodemoDoor) handleUDPResponse(dest v2net.Destination, payload *alloc.Buffer) {
|
||||||
|
@ -71,7 +71,7 @@ func (this *Server) Start() error {
|
|||||||
|
|
||||||
if this.config.UDP {
|
if this.config.UDP {
|
||||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
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 {
|
if err != nil {
|
||||||
log.Error("Shadowsocks: Failed to listen UDP on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
log.Error("Shadowsocks: Failed to listen UDP on ", this.meta.Address, ":", this.meta.Port, ": ", err)
|
||||||
return err
|
return err
|
||||||
@ -84,9 +84,10 @@ func (this *Server) Start() error {
|
|||||||
return nil
|
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()
|
defer payload.Release()
|
||||||
|
|
||||||
|
source := session.Source
|
||||||
ivLen := this.config.Cipher.IVSize()
|
ivLen := this.config.Cipher.IVSize()
|
||||||
iv := payload.Value[:ivLen]
|
iv := payload.Value[:ivLen]
|
||||||
key := this.config.Key
|
key := this.config.Key
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func (this *Server) listenUDP() error {
|
func (this *Server) listenUDP() error {
|
||||||
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
|
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 {
|
if err != nil {
|
||||||
log.Error("Socks: Failed to listen on udp ", this.meta.Address, ":", this.meta.Port)
|
log.Error("Socks: Failed to listen on udp ", this.meta.Address, ":", this.meta.Port)
|
||||||
return err
|
return err
|
||||||
@ -23,7 +23,8 @@ func (this *Server) listenUDP() error {
|
|||||||
return nil
|
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)
|
log.Info("Socks: Client UDP connection from ", source)
|
||||||
request, err := protocol.ReadUDPRequest(payload.Value)
|
request, err := protocol.ReadUDPRequest(payload.Value)
|
||||||
payload.Release()
|
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"
|
"github.com/v2ray/v2ray-core/common/log"
|
||||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||||
"github.com/v2ray/v2ray-core/common/serial"
|
"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"
|
||||||
"github.com/v2ray/v2ray-core/transport/internet/udp"
|
"github.com/v2ray/v2ray-core/transport/internet/udp"
|
||||||
)
|
)
|
||||||
@ -39,7 +40,7 @@ func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
|
|||||||
},
|
},
|
||||||
running: true,
|
running: true,
|
||||||
}
|
}
|
||||||
hub, err := udp.ListenUDP(address, port, l.OnReceive)
|
hub, err := udp.ListenUDP(address, port, udp.ListenOption{Callback: l.OnReceive})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -48,9 +49,11 @@ func NewListener(address v2net.Address, port v2net.Port) (*Listener, error) {
|
|||||||
return l, nil
|
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()
|
defer payload.Release()
|
||||||
|
|
||||||
|
src := session.Source
|
||||||
|
|
||||||
if valid := this.authenticator.Open(payload); !valid {
|
if valid := this.authenticator.Open(payload); !valid {
|
||||||
log.Info("KCP|Listener: discarding invalid payload from ", src)
|
log.Info("KCP|Listener: discarding invalid payload from ", src)
|
||||||
return
|
return
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
"github.com/v2ray/v2ray-core/transport/internet/internal"
|
||||||
ErrInvalidConn = errors.New("Invalid Connection.")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConnectionManager interface {
|
type ConnectionManager interface {
|
||||||
@ -27,7 +23,7 @@ func (this *RawConnection) Reusable() bool {
|
|||||||
func (this *RawConnection) SetReusable(b bool) {}
|
func (this *RawConnection) SetReusable(b bool) {}
|
||||||
|
|
||||||
func (this *RawConnection) SysFd() (int, error) {
|
func (this *RawConnection) SysFd() (int, error) {
|
||||||
return getSysFd(&this.TCPConn)
|
return internal.GetSysFd(&this.TCPConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
@ -106,19 +102,5 @@ func (this *Connection) Reusable() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *Connection) SysFd() (int, error) {
|
func (this *Connection) SysFd() (int, error) {
|
||||||
return getSysFd(this.conn)
|
return internal.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
|
|
||||||
}
|
}
|
||||||
|
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"
|
"sync"
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core/common/alloc"
|
"github.com/v2ray/v2ray-core/common/alloc"
|
||||||
|
"github.com/v2ray/v2ray-core/common/log"
|
||||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
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 {
|
type UDPHub struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
callback UDPPayloadHandler
|
option ListenOption
|
||||||
accepting bool
|
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{
|
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
IP: address.IP(),
|
IP: address.IP(),
|
||||||
Port: int(port),
|
Port: int(port),
|
||||||
@ -25,9 +33,21 @@ func ListenUDP(address v2net.Address, port v2net.Port, callback UDPPayloadHandle
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{
|
hub := &UDPHub{
|
||||||
conn: udpConn,
|
conn: udpConn,
|
||||||
callback: callback,
|
option: option,
|
||||||
}
|
}
|
||||||
go hub.start()
|
go hub.start()
|
||||||
return hub, nil
|
return hub, nil
|
||||||
@ -53,16 +73,22 @@ func (this *UDPHub) start() {
|
|||||||
this.accepting = true
|
this.accepting = true
|
||||||
this.Unlock()
|
this.Unlock()
|
||||||
|
|
||||||
|
oobBytes := make([]byte, 256)
|
||||||
for this.Running() {
|
for this.Running() {
|
||||||
buffer := alloc.NewBuffer()
|
buffer := alloc.NewBuffer()
|
||||||
nBytes, addr, err := this.conn.ReadFromUDP(buffer.Value)
|
nBytes, noob, _, addr, err := this.conn.ReadMsgUDP(buffer.Value, oobBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buffer.Release()
|
buffer.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buffer.Slice(0, nBytes)
|
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