| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- package hysteria
- import (
- "bytes"
- "encoding/binary"
- "io"
- "math/rand"
- "net"
- "os"
- "time"
- "github.com/sagernet/quic-go"
- "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"
- )
- const (
- MbpsToBps = 125000
- MinSpeedBPS = 16384
- DefaultStreamReceiveWindow = 15728640 // 15 MB/s
- DefaultConnectionReceiveWindow = 67108864 // 64 MB/s
- DefaultMaxIncomingStreams = 1024
- DefaultALPN = "hysteria"
- KeepAlivePeriod = 10 * time.Second
- )
- const Version = 3
- type ClientHello struct {
- SendBPS uint64
- RecvBPS uint64
- Auth []byte
- }
- func WriteClientHello(stream io.Writer, hello ClientHello) error {
- var requestLen int
- requestLen += 1 // version
- requestLen += 8 // sendBPS
- requestLen += 8 // recvBPS
- requestLen += 2 // auth len
- requestLen += len(hello.Auth)
- request := buf.NewSize(requestLen)
- defer request.Release()
- common.Must(
- request.WriteByte(Version),
- binary.Write(request, binary.BigEndian, hello.SendBPS),
- binary.Write(request, binary.BigEndian, hello.RecvBPS),
- binary.Write(request, binary.BigEndian, uint16(len(hello.Auth))),
- common.Error(request.Write(hello.Auth)),
- )
- return common.Error(stream.Write(request.Bytes()))
- }
- func ReadClientHello(reader io.Reader) (*ClientHello, error) {
- var version uint8
- err := binary.Read(reader, binary.BigEndian, &version)
- if err != nil {
- return nil, err
- }
- if version != Version {
- return nil, E.New("unsupported client version: ", version)
- }
- var clientHello ClientHello
- err = binary.Read(reader, binary.BigEndian, &clientHello.SendBPS)
- if err != nil {
- return nil, err
- }
- err = binary.Read(reader, binary.BigEndian, &clientHello.RecvBPS)
- if err != nil {
- return nil, err
- }
- var authLen uint16
- err = binary.Read(reader, binary.BigEndian, &authLen)
- if err != nil {
- return nil, err
- }
- clientHello.Auth = make([]byte, authLen)
- _, err = io.ReadFull(reader, clientHello.Auth)
- if err != nil {
- return nil, err
- }
- return &clientHello, nil
- }
- type ServerHello struct {
- OK bool
- SendBPS uint64
- RecvBPS uint64
- Message string
- }
- func ReadServerHello(stream io.Reader) (*ServerHello, error) {
- var responseLen int
- responseLen += 1 // ok
- responseLen += 8 // sendBPS
- responseLen += 8 // recvBPS
- responseLen += 2 // message len
- response := buf.NewSize(responseLen)
- defer response.Release()
- _, err := response.ReadFullFrom(stream, responseLen)
- if err != nil {
- return nil, err
- }
- var serverHello ServerHello
- serverHello.OK = response.Byte(0) == 1
- serverHello.SendBPS = binary.BigEndian.Uint64(response.Range(1, 9))
- serverHello.RecvBPS = binary.BigEndian.Uint64(response.Range(9, 17))
- messageLen := binary.BigEndian.Uint16(response.Range(17, 19))
- if messageLen == 0 {
- return &serverHello, nil
- }
- message := make([]byte, messageLen)
- _, err = io.ReadFull(stream, message)
- if err != nil {
- return nil, err
- }
- serverHello.Message = string(message)
- return &serverHello, nil
- }
- func WriteServerHello(stream io.Writer, hello ServerHello) error {
- var responseLen int
- responseLen += 1 // ok
- responseLen += 8 // sendBPS
- responseLen += 8 // recvBPS
- responseLen += 2 // message len
- responseLen += len(hello.Message)
- response := buf.NewSize(responseLen)
- defer response.Release()
- if hello.OK {
- common.Must(response.WriteByte(1))
- } else {
- common.Must(response.WriteByte(0))
- }
- common.Must(
- binary.Write(response, binary.BigEndian, hello.SendBPS),
- binary.Write(response, binary.BigEndian, hello.RecvBPS),
- binary.Write(response, binary.BigEndian, uint16(len(hello.Message))),
- common.Error(response.WriteString(hello.Message)),
- )
- return common.Error(stream.Write(response.Bytes()))
- }
- type ClientRequest struct {
- UDP bool
- Host string
- Port uint16
- }
- func ReadClientRequest(stream io.Reader) (*ClientRequest, error) {
- var clientRequest ClientRequest
- err := binary.Read(stream, binary.BigEndian, &clientRequest.UDP)
- if err != nil {
- return nil, err
- }
- var hostLen uint16
- err = binary.Read(stream, binary.BigEndian, &hostLen)
- if err != nil {
- return nil, err
- }
- host := make([]byte, hostLen)
- _, err = io.ReadFull(stream, host)
- if err != nil {
- return nil, err
- }
- clientRequest.Host = string(host)
- err = binary.Read(stream, binary.BigEndian, &clientRequest.Port)
- if err != nil {
- return nil, err
- }
- return &clientRequest, nil
- }
- func WriteClientRequest(stream io.Writer, request ClientRequest) error {
- var requestLen int
- requestLen += 1 // udp
- requestLen += 2 // host len
- requestLen += len(request.Host)
- requestLen += 2 // port
- buffer := buf.NewSize(requestLen)
- defer buffer.Release()
- if request.UDP {
- common.Must(buffer.WriteByte(1))
- } else {
- common.Must(buffer.WriteByte(0))
- }
- common.Must(
- binary.Write(buffer, binary.BigEndian, uint16(len(request.Host))),
- common.Error(buffer.WriteString(request.Host)),
- binary.Write(buffer, binary.BigEndian, request.Port),
- )
- return common.Error(stream.Write(buffer.Bytes()))
- }
- type ServerResponse struct {
- OK bool
- UDPSessionID uint32
- Message string
- }
- func ReadServerResponse(stream io.Reader) (*ServerResponse, error) {
- var responseLen int
- responseLen += 1 // ok
- responseLen += 4 // udp session id
- responseLen += 2 // message len
- response := buf.NewSize(responseLen)
- defer response.Release()
- _, err := response.ReadFullFrom(stream, responseLen)
- if err != nil {
- return nil, err
- }
- var serverResponse ServerResponse
- serverResponse.OK = response.Byte(0) == 1
- serverResponse.UDPSessionID = binary.BigEndian.Uint32(response.Range(1, 5))
- messageLen := binary.BigEndian.Uint16(response.Range(5, 7))
- if messageLen == 0 {
- return &serverResponse, nil
- }
- message := make([]byte, messageLen)
- _, err = io.ReadFull(stream, message)
- if err != nil {
- return nil, err
- }
- serverResponse.Message = string(message)
- return &serverResponse, nil
- }
- func WriteServerResponse(stream io.Writer, response ServerResponse) error {
- var responseLen int
- responseLen += 1 // ok
- responseLen += 4 // udp session id
- responseLen += 2 // message len
- responseLen += len(response.Message)
- buffer := buf.NewSize(responseLen)
- defer buffer.Release()
- if response.OK {
- common.Must(buffer.WriteByte(1))
- } else {
- common.Must(buffer.WriteByte(0))
- }
- common.Must(
- binary.Write(buffer, binary.BigEndian, response.UDPSessionID),
- binary.Write(buffer, binary.BigEndian, uint16(len(response.Message))),
- common.Error(buffer.WriteString(response.Message)),
- )
- return common.Error(stream.Write(buffer.Bytes()))
- }
- type UDPMessage struct {
- SessionID uint32
- Host string
- Port uint16
- MsgID uint16 // doesn't matter when not fragmented, but must not be 0 when fragmented
- FragID uint8 // doesn't matter when not fragmented, starts at 0 when fragmented
- FragCount uint8 // must be 1 when not fragmented
- Data []byte
- }
- func (m UDPMessage) HeaderSize() int {
- return 4 + 2 + len(m.Host) + 2 + 2 + 1 + 1 + 2
- }
- func (m UDPMessage) Size() int {
- return m.HeaderSize() + len(m.Data)
- }
- func ParseUDPMessage(packet []byte) (message UDPMessage, err error) {
- reader := bytes.NewReader(packet)
- err = binary.Read(reader, binary.BigEndian, &message.SessionID)
- if err != nil {
- return
- }
- var hostLen uint16
- err = binary.Read(reader, binary.BigEndian, &hostLen)
- if err != nil {
- return
- }
- _, err = reader.Seek(int64(hostLen), io.SeekCurrent)
- if err != nil {
- return
- }
- if 6+int(hostLen) > len(packet) {
- err = E.New("invalid host length")
- return
- }
- message.Host = string(packet[6 : 6+hostLen])
- err = binary.Read(reader, binary.BigEndian, &message.Port)
- if err != nil {
- return
- }
- err = binary.Read(reader, binary.BigEndian, &message.MsgID)
- if err != nil {
- return
- }
- err = binary.Read(reader, binary.BigEndian, &message.FragID)
- if err != nil {
- return
- }
- err = binary.Read(reader, binary.BigEndian, &message.FragCount)
- if err != nil {
- return
- }
- var dataLen uint16
- err = binary.Read(reader, binary.BigEndian, &dataLen)
- if err != nil {
- return
- }
- if reader.Len() != int(dataLen) {
- err = E.New("invalid data length")
- }
- dataOffset := int(reader.Size()) - reader.Len()
- message.Data = packet[dataOffset:]
- return
- }
- func WriteUDPMessage(conn quic.Connection, message UDPMessage) error {
- var messageLen int
- messageLen += 4 // session id
- messageLen += 2 // host len
- messageLen += len(message.Host)
- messageLen += 2 // port
- messageLen += 2 // msg id
- messageLen += 1 // frag id
- messageLen += 1 // frag count
- messageLen += 2 // data len
- messageLen += len(message.Data)
- buffer := buf.NewSize(messageLen)
- defer buffer.Release()
- err := writeUDPMessage(conn, message, buffer)
- if errSize, ok := err.(quic.ErrMessageTooLarge); ok {
- // need to frag
- message.MsgID = uint16(rand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1
- fragMsgs := FragUDPMessage(message, int(errSize))
- for _, fragMsg := range fragMsgs {
- buffer.FullReset()
- err = writeUDPMessage(conn, fragMsg, buffer)
- if err != nil {
- return err
- }
- }
- return nil
- }
- return err
- }
- func writeUDPMessage(conn quic.Connection, message UDPMessage, buffer *buf.Buffer) error {
- common.Must(
- binary.Write(buffer, binary.BigEndian, message.SessionID),
- binary.Write(buffer, binary.BigEndian, uint16(len(message.Host))),
- common.Error(buffer.WriteString(message.Host)),
- binary.Write(buffer, binary.BigEndian, message.Port),
- binary.Write(buffer, binary.BigEndian, message.MsgID),
- binary.Write(buffer, binary.BigEndian, message.FragID),
- binary.Write(buffer, binary.BigEndian, message.FragCount),
- binary.Write(buffer, binary.BigEndian, uint16(len(message.Data))),
- common.Error(buffer.Write(message.Data)),
- )
- return conn.SendMessage(buffer.Bytes())
- }
- var _ net.Conn = (*Conn)(nil)
- type Conn struct {
- quic.Stream
- destination M.Socksaddr
- needReadResponse bool
- }
- func NewConn(stream quic.Stream, destination M.Socksaddr, isClient bool) *Conn {
- return &Conn{
- Stream: stream,
- destination: destination,
- needReadResponse: isClient,
- }
- }
- func (c *Conn) Read(p []byte) (n int, err error) {
- if c.needReadResponse {
- var response *ServerResponse
- response, err = ReadServerResponse(c.Stream)
- if err != nil {
- c.Close()
- return
- }
- if !response.OK {
- c.Close()
- return 0, E.New("remote error: ", response.Message)
- }
- c.needReadResponse = false
- }
- return c.Stream.Read(p)
- }
- func (c *Conn) LocalAddr() net.Addr {
- return M.Socksaddr{}
- }
- func (c *Conn) RemoteAddr() net.Addr {
- return c.destination.TCPAddr()
- }
- func (c *Conn) ReaderReplaceable() bool {
- return !c.needReadResponse
- }
- func (c *Conn) WriterReplaceable() bool {
- return true
- }
- func (c *Conn) Upstream() any {
- return c.Stream
- }
- type PacketConn struct {
- session quic.Connection
- stream quic.Stream
- sessionId uint32
- destination M.Socksaddr
- msgCh <-chan *UDPMessage
- closer io.Closer
- }
- func NewPacketConn(session quic.Connection, stream quic.Stream, sessionId uint32, destination M.Socksaddr, msgCh <-chan *UDPMessage, closer io.Closer) *PacketConn {
- return &PacketConn{
- session: session,
- stream: stream,
- sessionId: sessionId,
- destination: destination,
- msgCh: msgCh,
- closer: closer,
- }
- }
- func (c *PacketConn) Hold() {
- // Hold the stream until it's closed
- buf := make([]byte, 1024)
- for {
- _, err := c.stream.Read(buf)
- if err != nil {
- break
- }
- }
- _ = c.Close()
- }
- func (c *PacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
- msg := <-c.msgCh
- if msg == nil {
- err = net.ErrClosed
- return
- }
- err = common.Error(buffer.Write(msg.Data))
- destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap()
- return
- }
- func (c *PacketConn) ReadPacketThreadSafe() (buffer *buf.Buffer, destination M.Socksaddr, err error) {
- msg := <-c.msgCh
- if msg == nil {
- err = net.ErrClosed
- return
- }
- buffer = buf.As(msg.Data)
- destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap()
- return
- }
- func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
- return WriteUDPMessage(c.session, UDPMessage{
- SessionID: c.sessionId,
- Host: destination.AddrString(),
- Port: destination.Port,
- FragCount: 1,
- Data: buffer.Bytes(),
- })
- }
- func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
- msg := <-c.msgCh
- if msg == nil {
- err = net.ErrClosed
- return
- }
- n = copy(p, msg.Data)
- destination := M.ParseSocksaddrHostPort(msg.Host, msg.Port)
- if destination.IsFqdn() {
- addr = destination
- } else {
- addr = destination.UDPAddr()
- }
- return
- }
- func (c *PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
- err = c.WritePacket(buf.As(p), M.SocksaddrFromNet(addr))
- if err == nil {
- n = len(p)
- }
- return
- }
- func (c *PacketConn) LocalAddr() net.Addr {
- return M.Socksaddr{}
- }
- func (c *PacketConn) RemoteAddr() net.Addr {
- return c.destination.UDPAddr()
- }
- func (c *PacketConn) SetDeadline(t time.Time) error {
- return os.ErrInvalid
- }
- func (c *PacketConn) SetReadDeadline(t time.Time) error {
- return os.ErrInvalid
- }
- func (c *PacketConn) SetWriteDeadline(t time.Time) error {
- return os.ErrInvalid
- }
- func (c *PacketConn) NeedAdditionalReadDeadline() bool {
- return true
- }
- func (c *PacketConn) Read(b []byte) (n int, err error) {
- n, _, err = c.ReadFrom(b)
- return
- }
- func (c *PacketConn) Write(b []byte) (n int, err error) {
- return c.WriteTo(b, c.destination)
- }
- func (c *PacketConn) Close() error {
- return common.Close(c.stream, c.closer)
- }
|