github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/transport/hysteria2/salamander.go (about)

     1  package hysteria2
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/sagernet/sing/common"
     7  	"github.com/sagernet/sing/common/buf"
     8  	"github.com/sagernet/sing/common/bufio"
     9  	E "github.com/sagernet/sing/common/exceptions"
    10  	M "github.com/sagernet/sing/common/metadata"
    11  	N "github.com/sagernet/sing/common/network"
    12  
    13  	"golang.org/x/crypto/blake2b"
    14  )
    15  
    16  const salamanderSaltLen = 8
    17  
    18  const ObfsTypeSalamander = "salamander"
    19  
    20  type Salamander struct {
    21  	net.PacketConn
    22  	password []byte
    23  }
    24  
    25  func NewSalamanderConn(conn net.PacketConn, password []byte) net.PacketConn {
    26  	writer, isVectorised := bufio.CreateVectorisedPacketWriter(conn)
    27  	if isVectorised {
    28  		return &VectorisedSalamander{
    29  			Salamander: Salamander{
    30  				PacketConn: conn,
    31  				password:   password,
    32  			},
    33  			writer: writer,
    34  		}
    35  	} else {
    36  		return &Salamander{
    37  			PacketConn: conn,
    38  			password:   password,
    39  		}
    40  	}
    41  }
    42  
    43  func (s *Salamander) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
    44  	n, addr, err = s.PacketConn.ReadFrom(p)
    45  	if err != nil {
    46  		return
    47  	}
    48  	if n <= salamanderSaltLen {
    49  		return 0, nil, E.New("salamander: packet too short")
    50  	}
    51  	key := blake2b.Sum256(append(s.password, p[:salamanderSaltLen]...))
    52  	for index, c := range p[salamanderSaltLen:n] {
    53  		p[index] = c ^ key[index%blake2b.Size256]
    54  	}
    55  	return n - salamanderSaltLen, addr, nil
    56  }
    57  
    58  func (s *Salamander) WriteTo(p []byte, addr net.Addr) (n int, err error) {
    59  	buffer := buf.NewSize(len(p) + salamanderSaltLen)
    60  	defer buffer.Release()
    61  	buffer.WriteRandom(salamanderSaltLen)
    62  	key := blake2b.Sum256(append(s.password, buffer.Bytes()...))
    63  	for index, c := range p {
    64  		common.Must(buffer.WriteByte(c ^ key[index%blake2b.Size256]))
    65  	}
    66  	_, err = s.PacketConn.WriteTo(buffer.Bytes(), addr)
    67  	if err != nil {
    68  		return
    69  	}
    70  	return len(p), nil
    71  }
    72  
    73  type VectorisedSalamander struct {
    74  	Salamander
    75  	writer N.VectorisedPacketWriter
    76  }
    77  
    78  func (s *VectorisedSalamander) WriteTo(p []byte, addr net.Addr) (n int, err error) {
    79  	buffer := buf.NewSize(salamanderSaltLen)
    80  	buffer.WriteRandom(salamanderSaltLen)
    81  	key := blake2b.Sum256(append(s.password, buffer.Bytes()...))
    82  	for i := range p {
    83  		p[i] ^= key[i%blake2b.Size256]
    84  	}
    85  	err = s.writer.WriteVectorisedPacket([]*buf.Buffer{buffer, buf.As(p)}, M.SocksaddrFromNet(addr))
    86  	if err != nil {
    87  		return
    88  	}
    89  	return len(p), nil
    90  }
    91  
    92  func (s *VectorisedSalamander) WriteVectorisedPacket(buffers []*buf.Buffer, destination M.Socksaddr) error {
    93  	header := buf.NewSize(salamanderSaltLen)
    94  	defer header.Release()
    95  	header.WriteRandom(salamanderSaltLen)
    96  	key := blake2b.Sum256(append(s.password, header.Bytes()...))
    97  	var bufferIndex int
    98  	for _, buffer := range buffers {
    99  		content := buffer.Bytes()
   100  		for index, c := range content {
   101  			content[bufferIndex+index] = c ^ key[bufferIndex+index%blake2b.Size256]
   102  		}
   103  		bufferIndex += len(content)
   104  	}
   105  	return s.writer.WriteVectorisedPacket(append([]*buf.Buffer{header}, buffers...), destination)
   106  }