123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- package shadowsocks_2022
- import (
- "context"
- "runtime"
- "time"
- "github.com/sagernet/sing-shadowsocks"
- "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
- C "github.com/sagernet/sing/common"
- B "github.com/sagernet/sing/common/buf"
- "github.com/sagernet/sing/common/bufio"
- M "github.com/sagernet/sing/common/metadata"
- N "github.com/sagernet/sing/common/network"
- "github.com/sagernet/sing/common/uot"
- "github.com/xtls/xray-core/common"
- "github.com/xtls/xray-core/common/buf"
- "github.com/xtls/xray-core/common/net"
- "github.com/xtls/xray-core/common/session"
- "github.com/xtls/xray-core/common/singbridge"
- "github.com/xtls/xray-core/transport"
- "github.com/xtls/xray-core/transport/internet"
- )
- func init() {
- common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
- return NewClient(ctx, config.(*ClientConfig))
- }))
- }
- type Outbound struct {
- ctx context.Context
- server net.Destination
- method shadowsocks.Method
- uot bool
- }
- func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
- o := &Outbound{
- ctx: ctx,
- server: net.Destination{
- Address: config.Address.AsAddress(),
- Port: net.Port(config.Port),
- Network: net.Network_TCP,
- },
- uot: config.UdpOverTcp,
- }
- if C.Contains(shadowaead_2022.List, config.Method) {
- if config.Key == "" {
- return nil, newError("missing psk")
- }
- method, err := shadowaead_2022.NewWithPassword(config.Method, config.Key)
- if err != nil {
- return nil, newError("create method").Base(err)
- }
- o.method = method
- } else {
- return nil, newError("unknown method ", config.Method)
- }
- return o, nil
- }
- func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
- var inboundConn net.Conn
- inbound := session.InboundFromContext(ctx)
- if inbound != nil {
- inboundConn = inbound.Conn
- }
- outbound := session.OutboundFromContext(ctx)
- if outbound == nil || !outbound.Target.IsValid() {
- return newError("target not specified")
- }
- destination := outbound.Target
- network := destination.Network
- newError("tunneling request to ", destination, " via ", o.server.NetAddr()).WriteToLog(session.ExportIDToError(ctx))
- serverDestination := o.server
- if o.uot {
- serverDestination.Network = net.Network_TCP
- } else {
- serverDestination.Network = network
- }
- connection, err := dialer.Dial(ctx, serverDestination)
- if err != nil {
- return newError("failed to connect to server").Base(err)
- }
- if network == net.Network_TCP {
- serverConn := o.method.DialEarlyConn(connection, singbridge.ToSocksaddr(destination))
- var handshake bool
- if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
- mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100)
- if err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
- return newError("read payload").Base(err)
- }
- _payload := B.StackNew()
- payload := C.Dup(_payload)
- defer payload.Release()
- for {
- payload.FullReset()
- nb, n := buf.SplitBytes(mb, payload.FreeBytes())
- if n > 0 {
- payload.Truncate(n)
- _, err = serverConn.Write(payload.Bytes())
- if err != nil {
- return newError("write payload").Base(err)
- }
- handshake = true
- }
- if nb.IsEmpty() {
- break
- } else {
- mb = nb
- }
- }
- runtime.KeepAlive(_payload)
- }
- if !handshake {
- _, err = serverConn.Write(nil)
- if err != nil {
- return newError("client handshake").Base(err)
- }
- }
- return singbridge.CopyConn(ctx, inboundConn, link, serverConn)
- } else {
- var packetConn N.PacketConn
- if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn {
- packetConn = pc
- } else if nc, isNetPacket := inboundConn.(net.PacketConn); isNetPacket {
- packetConn = bufio.NewPacketConn(nc)
- } else {
- packetConn = &packetConnWrapper{
- Reader: link.Reader,
- Writer: link.Writer,
- Conn: inboundConn,
- Dest: destination,
- }
- }
- if o.uot {
- serverConn := o.method.DialEarlyConn(connection, M.Socksaddr{Fqdn: uot.UOTMagicAddress})
- return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn)))
- } else {
- serverConn := o.method.DialPacketConn(connection)
- return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
- }
- }
- }
|