Skip to content

Commit

Permalink
shadowsockets fullcone outbound support
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaokangwang committed Jan 3, 2022
1 parent cdfef7e commit d068b60
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 2 deletions.
26 changes: 25 additions & 1 deletion proxy/shadowsocks/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/v2fly/v2ray-core/v5/common"
"github.com/v2fly/v2ray-core/v5/common/buf"
"github.com/v2fly/v2ray-core/v5/common/net"
"github.com/v2fly/v2ray-core/v5/common/net/packetaddr"
"github.com/v2fly/v2ray-core/v5/common/protocol"
"github.com/v2fly/v2ray-core/v5/common/retry"
"github.com/v2fly/v2ray-core/v5/common/session"
Expand All @@ -16,9 +17,10 @@ import (
"github.com/v2fly/v2ray-core/v5/features/policy"
"github.com/v2fly/v2ray-core/v5/transport"
"github.com/v2fly/v2ray-core/v5/transport/internet"
"github.com/v2fly/v2ray-core/v5/transport/internet/udp"
)

// Client is an inbound handler for Shadowsocks protocol
// Client is a inbound handler for Shadowsocks protocol
type Client struct {
serverPicker protocol.ServerPicker
policyManager policy.Manager
Expand Down Expand Up @@ -99,6 +101,28 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)

if packetConn, err := packetaddr.ToPacketAddrConn(link, destination); err == nil {
requestDone := func() error {
protocolWriter := &UDPWriter{
Writer: conn,
Request: request,
}
return udp.CopyPacketConn(protocolWriter, packetConn, udp.UpdateActivity(timer))
}
responseDone := func() error {
protocolReader := &UDPReader{
Reader: conn,
User: user,
}
return udp.CopyPacketConn(packetConn, protocolReader, udp.UpdateActivity(timer))
}
responseDoneAndCloseWriter := task.OnSuccess(responseDone, task.Close(link.Writer))
if err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {
return newError("connection ends").Base(err)
}
return nil
}

if request.Command == protocol.RequestCommandTCP {
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
Expand Down
33 changes: 33 additions & 0 deletions proxy/shadowsocks/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"crypto/sha256"
"hash/crc32"
"io"
gonet "net"

"github.com/v2fly/v2ray-core/v5/common"
"github.com/v2fly/v2ray-core/v5/common/buf"
Expand Down Expand Up @@ -253,6 +254,23 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buf.MultiBuffer{payload}, nil
}

func (v *UDPReader) ReadFrom(p []byte) (n int, addr gonet.Addr, err error) {
buffer := buf.New()
_, err = buffer.ReadFrom(v.Reader)
if err != nil {
buffer.Release()
return 0, nil, err
}
vaddr, payload, err := DecodeUDPPacket(v.User, buffer)
if err != nil {
buffer.Release()
return 0, nil, err
}
n = copy(p, payload.Bytes())
payload.Release()
return n, &gonet.UDPAddr{IP: vaddr.Address.IP(), Port: int(vaddr.Port)}, nil
}

type UDPWriter struct {
Writer io.Writer
Request *protocol.RequestHeader
Expand All @@ -268,3 +286,18 @@ func (w *UDPWriter) Write(payload []byte) (int, error) {
packet.Release()
return len(payload), err
}

func (w *UDPWriter) WriteTo(payload []byte, addr gonet.Addr) (n int, err error) {
request := *w.Request
udpAddr := addr.(*gonet.UDPAddr)
request.Command = protocol.RequestCommandUDP
request.Address = net.IPAddress(udpAddr.IP)
request.Port = net.Port(udpAddr.Port)
packet, err := EncodeUDPPacket(&request, payload)
if err != nil {
return 0, err
}
_, err = w.Writer.Write(packet.Bytes())
packet.Release()
return len(payload), err
}
22 changes: 21 additions & 1 deletion transport/internet/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,33 @@ package internet
import (
"net"

"github.com/v2fly/v2ray-core/v5/features/stats"
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/features/stats"
)

type Connection interface {
net.Conn
}

type AbstractPacketConnReader interface {
ReadFrom(p []byte) (n int, addr net.Addr, err error)
}

type AbstractPacketConnWriter interface {
WriteTo(p []byte, addr net.Addr) (n int, err error)
}

type AbstractPacketConn interface {
AbstractPacketConnReader
AbstractPacketConnWriter
common.Closable
}

type PacketConn interface {
AbstractPacketConn
net.PacketConn
}

type StatCouterConnection struct {
Connection
ReadCounter stats.Counter
Expand Down
47 changes: 47 additions & 0 deletions transport/internet/udp/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package udp

import (
gonet "net"

"github.com/v2fly/v2ray-core/v4/common/signal"
"github.com/v2fly/v2ray-core/v4/transport/internet"
)

type dataHandler func(content []byte, address gonet.Addr)

type copyHandler struct {
onData []dataHandler
}

type CopyOption func(*copyHandler)

func CopyPacketConn(dst internet.AbstractPacketConnWriter, src internet.AbstractPacketConnReader, options ...CopyOption) error {
var handler copyHandler
for _, option := range options {
option(&handler)
}
var buffer [2048]byte
for {
n, addr, err := src.ReadFrom(buffer[:])
if err != nil {
return err
}

for _, handler := range handler.onData {
handler(buffer[:n], addr)
}

n, err = dst.WriteTo(buffer[:n], addr)
if err != nil {
return err
}
}
}

func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
return func(handler *copyHandler) {
handler.onData = append(handler.onData, func(content []byte, address gonet.Addr) {
timer.Update()
})
}
}

0 comments on commit d068b60

Please sign in to comment.