sing/common/uot/server.go
2022-05-04 19:34:55 +08:00

107 lines
2.1 KiB
Go

package uot
import (
"encoding/binary"
"io"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
)
type ServerConn struct {
net.PacketConn
inputReader, outputReader *io.PipeReader
inputWriter, outputWriter *io.PipeWriter
}
func NewServerConn(packetConn net.PacketConn) net.Conn {
c := &ServerConn{
PacketConn: packetConn,
}
c.inputReader, c.inputWriter = io.Pipe()
c.outputReader, c.outputWriter = io.Pipe()
go c.loopInput()
go c.loopOutput()
return c
}
func (c *ServerConn) Read(b []byte) (n int, err error) {
return c.outputReader.Read(b)
}
func (c *ServerConn) Write(b []byte) (n int, err error) {
return c.inputWriter.Write(b)
}
func (c *ServerConn) RemoteAddr() net.Addr {
return &common.DummyAddr{}
}
func (c *ServerConn) loopInput() {
_buffer := buf.StackNew()
buffer := common.Dup(_buffer)
for {
destination, err := AddrParser.ReadAddrPort(c.inputReader)
if err != nil {
break
}
if destination.Family().IsFqdn() {
ip, err := LookupAddress(destination.Fqdn)
if err != nil {
break
}
destination.Addr = M.AddrFromIP(ip)
}
var length uint16
err = binary.Read(c.inputReader, binary.BigEndian, &length)
if err != nil {
break
}
buffer.FullReset()
_, err = buffer.ReadFullFrom(c.inputReader, int(length))
if err != nil {
break
}
_, err = c.WriteTo(buffer.Bytes(), destination.UDPAddr())
if err != nil {
break
}
}
c.Close()
}
func (c *ServerConn) loopOutput() {
_buffer := buf.StackNew()
buffer := common.Dup(_buffer)
for {
buffer.FullReset()
n, addr, err := buffer.ReadPacketFrom(c)
if err != nil {
break
}
err = AddrParser.WriteAddrPort(c.outputWriter, M.SocksaddrFromNet(addr))
if err != nil {
break
}
err = binary.Write(c.outputWriter, binary.BigEndian, uint16(n))
if err != nil {
break
}
_, err = buffer.WriteTo(c.outputWriter)
if err != nil {
break
}
}
c.Close()
}
func (c *ServerConn) Close() error {
c.inputReader.Close()
c.inputWriter.Close()
c.outputReader.Close()
c.outputWriter.Close()
c.PacketConn.Close()
return nil
}