sing-box/common/mux/protocol.go

241 lines
4.7 KiB
Go
Raw Normal View History

2022-07-30 00:29:22 +08:00
package mux
import (
"encoding/binary"
"io"
2022-07-30 09:57:02 +08:00
"net"
2022-07-30 00:29:22 +08:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
2022-08-12 12:13:57 +08:00
"github.com/sagernet/smux"
2022-07-30 00:29:22 +08:00
"github.com/hashicorp/yamux"
)
var Destination = M.Socksaddr{
Fqdn: "sp.mux.sing-box.arpa",
Port: 444,
}
2022-08-03 21:51:34 +08:00
const (
2022-08-04 09:11:39 +08:00
ProtocolSMux Protocol = iota
ProtocolYAMux
2022-08-03 21:51:34 +08:00
)
type Protocol byte
func ParseProtocol(name string) (Protocol, error) {
switch name {
2022-08-04 09:11:39 +08:00
case "", "smux":
2022-08-03 21:51:34 +08:00
return ProtocolSMux, nil
2022-08-04 09:11:39 +08:00
case "yamux":
return ProtocolYAMux, nil
2022-08-03 21:51:34 +08:00
default:
return ProtocolYAMux, E.New("unknown multiplex protocol: ", name)
}
}
func (p Protocol) newServer(conn net.Conn) (abstractSession, error) {
switch p {
case ProtocolSMux:
2022-11-08 16:45:19 +08:00
session, err := smux.Server(conn, smuxConfig())
2022-08-03 21:51:34 +08:00
if err != nil {
return nil, err
}
return &smuxSession{session}, nil
2022-08-04 09:11:39 +08:00
case ProtocolYAMux:
return yamux.Server(conn, yaMuxConfig())
2022-08-03 21:51:34 +08:00
default:
panic("unknown protocol")
}
}
func (p Protocol) newClient(conn net.Conn) (abstractSession, error) {
switch p {
case ProtocolSMux:
2022-11-08 16:45:19 +08:00
session, err := smux.Client(conn, smuxConfig())
2022-08-03 21:51:34 +08:00
if err != nil {
return nil, err
}
return &smuxSession{session}, nil
2022-08-04 09:11:39 +08:00
case ProtocolYAMux:
return yamux.Client(conn, yaMuxConfig())
2022-08-03 21:51:34 +08:00
default:
panic("unknown protocol")
}
}
2022-11-08 16:45:19 +08:00
func smuxConfig() *smux.Config {
config := smux.DefaultConfig()
config.KeepAliveDisabled = true
return config
}
2022-08-03 21:51:34 +08:00
func yaMuxConfig() *yamux.Config {
2022-07-30 00:29:22 +08:00
config := yamux.DefaultConfig()
config.LogOutput = io.Discard
config.StreamCloseTimeout = C.TCPTimeout
config.StreamOpenTimeout = C.TCPTimeout
return config
}
2022-08-03 21:51:34 +08:00
func (p Protocol) String() string {
switch p {
case ProtocolSMux:
return "smux"
2022-08-04 09:11:39 +08:00
case ProtocolYAMux:
return "yamux"
2022-08-03 21:51:34 +08:00
default:
return "unknown"
}
}
2022-07-30 00:29:22 +08:00
const (
2022-08-03 21:51:34 +08:00
version0 = 0
2022-07-30 00:29:22 +08:00
)
type Request struct {
2022-08-03 21:51:34 +08:00
Protocol Protocol
2022-07-30 00:29:22 +08:00
}
func ReadRequest(reader io.Reader) (*Request, error) {
version, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
if version != version0 {
return nil, E.New("unsupported version: ", version)
}
2022-08-03 21:51:34 +08:00
protocol, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
2022-08-04 10:38:20 +08:00
if protocol > byte(ProtocolYAMux) {
2022-08-03 21:51:34 +08:00
return nil, E.New("unsupported protocol: ", protocol)
}
return &Request{Protocol: Protocol(protocol)}, nil
}
func EncodeRequest(buffer *buf.Buffer, request Request) {
buffer.WriteByte(version0)
buffer.WriteByte(byte(request.Protocol))
}
const (
flagUDP = 1
flagAddr = 2
statusSuccess = 0
statusError = 1
)
type StreamRequest struct {
Network string
Destination M.Socksaddr
PacketAddr bool
}
func ReadStreamRequest(reader io.Reader) (*StreamRequest, error) {
2022-07-30 00:29:22 +08:00
var flags uint16
2022-08-03 21:51:34 +08:00
err := binary.Read(reader, binary.BigEndian, &flags)
2022-07-30 00:29:22 +08:00
if err != nil {
return nil, err
}
destination, err := M.SocksaddrSerializer.ReadAddrPort(reader)
if err != nil {
return nil, err
}
var network string
var udpAddr bool
if flags&flagUDP == 0 {
network = N.NetworkTCP
} else {
network = N.NetworkUDP
udpAddr = flags&flagAddr != 0
}
2022-08-03 21:51:34 +08:00
return &StreamRequest{network, destination, udpAddr}, nil
2022-07-30 00:29:22 +08:00
}
2022-08-03 21:51:34 +08:00
func requestLen(request StreamRequest) int {
2022-07-30 00:29:22 +08:00
var rLen int
rLen += 1 // version
rLen += 2 // flags
rLen += M.SocksaddrSerializer.AddrPortLen(request.Destination)
return rLen
}
2022-08-03 21:51:34 +08:00
func EncodeStreamRequest(request StreamRequest, buffer *buf.Buffer) {
2022-07-30 00:29:22 +08:00
destination := request.Destination
var flags uint16
if request.Network == N.NetworkUDP {
flags |= flagUDP
}
if request.PacketAddr {
flags |= flagAddr
if !destination.IsValid() {
destination = Destination
}
}
common.Must(
binary.Write(buffer, binary.BigEndian, flags),
M.SocksaddrSerializer.WriteAddrPort(buffer, destination),
)
}
2022-08-03 21:51:34 +08:00
type StreamResponse struct {
2022-07-30 00:29:22 +08:00
Status uint8
Message string
}
2022-08-03 21:51:34 +08:00
func ReadStreamResponse(reader io.Reader) (*StreamResponse, error) {
var response StreamResponse
2022-07-30 00:29:22 +08:00
status, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
response.Status = status
if status == statusError {
response.Message, err = rw.ReadVString(reader)
if err != nil {
return nil, err
}
}
return &response, nil
}
2022-07-30 09:57:02 +08:00
type wrapStream struct {
net.Conn
}
func (w *wrapStream) Read(p []byte) (n int, err error) {
n, err = w.Conn.Read(p)
err = wrapError(err)
return
}
func (w *wrapStream) Write(p []byte) (n int, err error) {
n, err = w.Conn.Write(p)
err = wrapError(err)
return
}
2022-08-04 00:00:07 +08:00
func (w *wrapStream) WriteIsThreadUnsafe() {
}
func (w *wrapStream) Upstream() any {
return w.Conn
}
2022-07-30 09:57:02 +08:00
func wrapError(err error) error {
switch err {
case yamux.ErrStreamClosed:
return io.EOF
default:
return err
}
}