c1be3debfd
* Refactor ssr stream cipher to expose iv and key References: https://github.com/Dreamacro/go-shadowsocks2 https://github.com/sh4d0wfiend/go-shadowsocksr2 * Implement ssr obfs Reference: https://github.com/mzz2017/shadowsocksR * Implement ssr protocol References: https://github.com/mzz2017/shadowsocksR https://github.com/shadowsocksRb/shadowsocksr-libev https://github.com/shadowsocksr-backup/shadowsocksr
75 lines
1.3 KiB
Go
75 lines
1.3 KiB
Go
package obfs
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"hash/crc32"
|
|
"math/rand"
|
|
)
|
|
|
|
type randomHead struct {
|
|
*Base
|
|
firstRequest bool
|
|
firstResponse bool
|
|
headerSent bool
|
|
buffer []byte
|
|
}
|
|
|
|
func init() {
|
|
register("random_head", newRandomHead)
|
|
}
|
|
|
|
func newRandomHead(b *Base) Obfs {
|
|
return &randomHead{Base: b}
|
|
}
|
|
|
|
func (r *randomHead) initForConn() Obfs {
|
|
return &randomHead{
|
|
Base: r.Base,
|
|
firstRequest: true,
|
|
firstResponse: true,
|
|
}
|
|
}
|
|
|
|
func (r *randomHead) GetObfsOverhead() int {
|
|
return 0
|
|
}
|
|
|
|
func (r *randomHead) Encode(b []byte) (encoded []byte, err error) {
|
|
if !r.firstRequest {
|
|
return b, nil
|
|
}
|
|
|
|
bSize := len(b)
|
|
if r.headerSent {
|
|
if bSize > 0 {
|
|
d := make([]byte, len(r.buffer)+bSize)
|
|
copy(d, r.buffer)
|
|
copy(d[len(r.buffer):], b)
|
|
r.buffer = d
|
|
} else {
|
|
encoded = r.buffer
|
|
r.buffer = nil
|
|
r.firstRequest = false
|
|
}
|
|
} else {
|
|
size := rand.Intn(96) + 8
|
|
encoded = make([]byte, size)
|
|
rand.Read(encoded)
|
|
crc := (0xFFFFFFFF - crc32.ChecksumIEEE(encoded[:size-4])) & 0xFFFFFFFF
|
|
binary.LittleEndian.PutUint32(encoded[size-4:], crc)
|
|
|
|
d := make([]byte, bSize)
|
|
copy(d, b)
|
|
r.buffer = d
|
|
}
|
|
r.headerSent = true
|
|
return encoded, nil
|
|
}
|
|
|
|
func (r *randomHead) Decode(b []byte) ([]byte, bool, error) {
|
|
if r.firstResponse {
|
|
r.firstResponse = false
|
|
return b, true, nil
|
|
}
|
|
return b, false, nil
|
|
}
|