mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-11-19 02:46:33 -05:00
104 lines
3.2 KiB
Go
104 lines
3.2 KiB
Go
package tunsorter
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/app/tun/packetparse"
|
|
"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"
|
|
vudp "github.com/v2fly/v2ray-core/v5/common/protocol/udp"
|
|
"github.com/v2fly/v2ray-core/v5/features/routing"
|
|
"github.com/v2fly/v2ray-core/v5/transport/internet/udp"
|
|
)
|
|
|
|
//go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
|
|
|
|
func NewTunSorter(tunWriter io.Writer, dispatcher routing.Dispatcher, packetAddrType packetaddr.PacketAddrType, ctx context.Context) *TunSorter {
|
|
return &TunSorter{
|
|
tunWriter: tunWriter,
|
|
dispatcher: dispatcher,
|
|
packetAddrType: packetAddrType,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
type TunSorter struct {
|
|
tunWriter io.Writer
|
|
dispatcher routing.Dispatcher
|
|
packetAddrType packetaddr.PacketAddrType
|
|
|
|
trackedConnections sync.Map
|
|
ctx context.Context
|
|
}
|
|
|
|
func (t *TunSorter) OnPacketReceived(b []byte) (n int, err error) {
|
|
src, dst, data, err := packetparse.TryParseAsUDPPacket(b)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
conn := newTrackedUDPConnection(src, t)
|
|
trackedConnection, loaded := t.trackedConnections.LoadOrStore(src.String(), conn)
|
|
conn = trackedConnection.(*trackedUDPConnection)
|
|
if !loaded {
|
|
t.onNewConnection(conn)
|
|
}
|
|
conn.onNewPacket(dst, data)
|
|
return len(b), nil
|
|
}
|
|
|
|
func (t *TunSorter) onNewConnection(connection *trackedUDPConnection) {
|
|
udpDispatcherConstructor := udp.NewSplitDispatcher
|
|
switch t.packetAddrType { // nolint: gocritic
|
|
case packetaddr.PacketAddrType_Packet:
|
|
ctx := context.WithValue(t.ctx, udp.DispatcherConnectionTerminationSignalReceiverMark, connection) // nolint:staticcheck
|
|
packetAddrDispatcherFactory := udp.NewPacketAddrDispatcherCreator(ctx)
|
|
udpDispatcherConstructor = packetAddrDispatcherFactory.NewPacketAddrDispatcher
|
|
}
|
|
udpDispatcher := udpDispatcherConstructor(t.dispatcher, func(ctx context.Context, packet *vudp.Packet) {
|
|
connection.onWritePacket(packet.Source, packet.Payload.Bytes())
|
|
})
|
|
connection.packetDispatcher = udpDispatcher
|
|
}
|
|
|
|
func (t *TunSorter) onWritePacket(src net.Destination, dest net.Destination, data []byte) {
|
|
data, err := packetparse.TryConstructUDPPacket(src, dest, data)
|
|
if err != nil {
|
|
newError("failed to construct udp packet").Base(err).WriteToLog()
|
|
return
|
|
}
|
|
_, err = t.tunWriter.Write(data)
|
|
if err != nil {
|
|
newError("failed to write udp packet to tun").Base(err).WriteToLog()
|
|
return
|
|
}
|
|
}
|
|
|
|
func newTrackedUDPConnection(src net.Destination, tunSorter *TunSorter) *trackedUDPConnection {
|
|
return &trackedUDPConnection{
|
|
tunSorter: tunSorter,
|
|
src: src,
|
|
}
|
|
}
|
|
|
|
type trackedUDPConnection struct {
|
|
packetDispatcher udp.DispatcherI
|
|
tunSorter *TunSorter
|
|
src net.Destination
|
|
}
|
|
|
|
func (t *trackedUDPConnection) onNewPacket(dst net.Destination, data []byte) {
|
|
t.packetDispatcher.Dispatch(context.Background(), dst, buf.FromBytes(data))
|
|
}
|
|
|
|
func (t *trackedUDPConnection) onWritePacket(src net.Destination, data []byte) {
|
|
t.tunSorter.onWritePacket(src, t.src, data)
|
|
}
|
|
|
|
func (t *trackedUDPConnection) Close() error {
|
|
t.tunSorter.trackedConnections.Delete(t.src.String())
|
|
return nil
|
|
}
|