Documentation
¶
Index ¶
- Variables
- func NewPacketListener(endpoint transport.PacketEndpoint, key *EncryptionKey) (transport.PacketListener, error)
- func Pack(dst, plaintext []byte, key *EncryptionKey) ([]byte, error)
- func Unpack(dst, pkt []byte, key *EncryptionKey) ([]byte, error)
- type EncryptionKey
- type ErrUnsupportedCipher
- type Reader
- type SaltGenerator
- type StreamDialer
- type Writer
Constants ¶
This section is empty.
Variables ¶
var ( CHACHA20IETFPOLY1305 = "AEAD_CHACHA20_POLY1305" AES256GCM = "AEAD_AES_256_GCM" AES192GCM = "AEAD_AES_192_GCM" AES128GCM = "AEAD_AES_128_GCM" )
List of supported AEAD ciphers, as specified at https://shadowsocks.org/guide/aead.html
var ErrShortPacket = errors.New("short packet")
ErrShortPacket indicates the destination packet given to Unpack is too short.
Functions ¶
func NewPacketListener ¶
func NewPacketListener(endpoint transport.PacketEndpoint, key *EncryptionKey) (transport.PacketListener, error)
func Pack ¶
func Pack(dst, plaintext []byte, key *EncryptionKey) ([]byte, error)
Pack encrypts a Shadowsocks-UDP packet and returns a slice containing the encrypted packet. dst must be big enough to hold the encrypted packet. If plaintext and dst overlap but are not aligned for in-place encryption, this function will panic.
func Unpack ¶
func Unpack(dst, pkt []byte, key *EncryptionKey) ([]byte, error)
Unpack decrypts a Shadowsocks-UDP packet in the format [salt][cipherText][AEAD tag] and returns a slice containing the decrypted payload or an error. If dst is present, it is used to store the plaintext, and must have enough capacity. If dst is nil, decryption proceeds in-place.
Types ¶
type EncryptionKey ¶
type EncryptionKey struct {
// contains filtered or unexported fields
}
EncryptionKey encapsulates a Shadowsocks AEAD spec and a secret
func NewEncryptionKey ¶
func NewEncryptionKey(cipherName string, secretText string) (*EncryptionKey, error)
NewEncryptionKey creates a Cipher given a cipher name and a secret. The cipher name must be the IETF name (as per https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml) or the Shadowsocks alias from https://shadowsocks.org/guide/aead.html.
func (*EncryptionKey) NewAEAD ¶
func (c *EncryptionKey) NewAEAD(salt []byte) (cipher.AEAD, error)
NewAEAD creates the AEAD for this cipher
func (*EncryptionKey) SaltSize ¶
func (c *EncryptionKey) SaltSize() int
SaltSize is the size of the salt for this Cipher
func (*EncryptionKey) TagSize ¶
func (c *EncryptionKey) TagSize() int
TagSize is the size of the AEAD tag for this Cipher
type ErrUnsupportedCipher ¶
type ErrUnsupportedCipher struct { // The name of the requested [Cipher] Name string }
ErrUnsupportedCipher is returned by [CypherByName] when the named cipher is not supported.
func (ErrUnsupportedCipher) Error ¶
func (err ErrUnsupportedCipher) Error() string
type Reader ¶
Reader is an io.Reader that also implements io.WriterTo to allow for piping the data without extra allocations and copies.
type SaltGenerator ¶
SaltGenerator generates unique salts to use in Shadowsocks connections.
var RandomSaltGenerator SaltGenerator = randomSaltGenerator{}
RandomSaltGenerator is a basic SaltGenerator.
func NewPrefixSaltGenerator ¶
func NewPrefixSaltGenerator(prefix []byte) SaltGenerator
NewPrefixSaltGenerator returns a SaltGenerator whose output consists of the provided prefix, followed by random bytes. This is useful to change how shadowsocks traffic is classified by middleboxes.
Note: Prefixes steal entropy from the initialization vector. This weakens security by increasing the likelihood that the same IV is used in two different connections (which becomes likely once 2^(N/2) connections are made, due to the birthday attack). If an IV is reused, the attacker can not only decrypt the ciphertext of those two connections; they can also easily recover the shadowsocks key and decrypt all other connections to this server. Use with care!
type StreamDialer ¶
type StreamDialer struct { // SaltGenerator is used by Shadowsocks to generate the connection salts. // `SaltGenerator` may be `nil`, which defaults to [shadowsocks.RandomSaltGenerator]. SaltGenerator SaltGenerator // ClientDataWait specifies the amount of time to wait for client data before sending // the Shadowsocks connection request to the proxy server. It's 10 milliseconds by default. // // StreamDialer has an optimization to send the initial client payload along with // the Shadowsocks connection request. This saves one packet during connection, and also // reduces the distinctiveness of the connection pattern. // // Normally, the initial payload will be sent as soon as the socket is connected, // except for delays due to inter-process communication. However, some protocols // expect the server to send data first, in which case there is no client payload. // We therefore use a short delay by default (10ms), longer than any reasonable IPC but shorter than // typical network latency. (In an Android emulator, the 90th percentile delay // was ~1 ms.) If no client payload is received by this time, we connect without it. ClientDataWait time.Duration // contains filtered or unexported fields }
func NewStreamDialer ¶
func NewStreamDialer(endpoint transport.StreamEndpoint, key *EncryptionKey) (*StreamDialer, error)
NewStreamDialer creates a client that routes connections to a Shadowsocks proxy listening at the given StreamEndpoint, with `key` as the Shadowsocks encyption key.
func (*StreamDialer) Dial ¶
func (c *StreamDialer) Dial(ctx context.Context, remoteAddr string) (transport.StreamConn, error)
Dial implements StreamDialer.Dial via a Shadowsocks server.
The Shadowsocks StreamDialer returns a connection after the connection to the proxy is established, but before the connection to the target is established. That means we cannot signal "connection refused" or "connection timeout" errors from the target to the application.
This behavior breaks IPv6 Happy Eyeballs because the application IPv6 socket will connect successfully, even if the proxy fails to connect to the IPv6 destination. The broken Happy Eyeballs behavior makes IPv6 unusable if the proxy cannot use IPv6.
We can't easily fix that issue because Shadowsocks, unlike SOCKS, does not have a way to indicate whether the target connection is successful. Even if that was possible, we want to wait until we have initial data from the application in order to send the Shadowsocks salt, SOCKS address and initial data all in one packet. This makes the size of the initial packet hard to predict, avoiding packet size fingerprinting. We can only get the application initial data if we return a connection first.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer is an io.Writer that also implements io.ReaderFrom to allow for piping the data without extra allocations and copies. The LazyWrite and Flush methods allow a header to be added but delayed until the first write, for concatenation. All methods except Flush must be called from a single thread.
func NewWriter ¶
func NewWriter(writer io.Writer, key *EncryptionKey) *Writer
NewWriter creates a Writer that encrypts the given io.Writer using the shadowsocks protocol with the given encryption key.
func (*Writer) LazyWrite ¶
LazyWrite queues p to be written, but doesn't send it until Flush() is called, a non-lazy write is made, or the buffer is filled.
func (*Writer) ReadFrom ¶
ReadFrom implements the io.ReaderFrom interface.
func (*Writer) SetSaltGenerator ¶
func (sw *Writer) SetSaltGenerator(saltGenerator SaltGenerator)
SetSaltGenerator sets the salt generator to be used. Must be called before the first write.