Add http support for sslocal

This commit is contained in:
世界 2022-04-07 20:49:20 +08:00
parent 542fa4f975
commit 26e13e7beb
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
30 changed files with 1355 additions and 194 deletions

View file

@ -11,8 +11,8 @@ import (
type Cipher interface {
KeySize() int
SaltSize() int
CreateReader(key []byte, iv []byte, reader io.Reader) io.Reader
CreateWriter(key []byte, iv []byte, writer io.Writer) (io.Writer, int)
CreateReader(key []byte, salt []byte, reader io.Reader) io.Reader
CreateWriter(key []byte, salt []byte, writer io.Writer) io.Writer
EncodePacket(key []byte, buffer *buf.Buffer) error
DecodePacket(key []byte, buffer *buf.Buffer) error
}

View file

@ -92,9 +92,9 @@ func (c *AEADCipher) CreateReader(key []byte, salt []byte, reader io.Reader) io.
return NewAEADReader(reader, c.Constructor(Kdf(key, salt, c.KeyLength)))
}
func (c *AEADCipher) CreateWriter(key []byte, salt []byte, writer io.Writer) (io.Writer, int) {
func (c *AEADCipher) CreateWriter(key []byte, salt []byte, writer io.Writer) io.Writer {
protocolWriter := NewAEADWriter(writer, c.Constructor(Kdf(key, salt, c.KeyLength)))
return protocolWriter, protocolWriter.maxDataSize
return protocolWriter
}
func (c *AEADCipher) EncodePacket(key []byte, buffer *buf.Buffer) error {
@ -132,12 +132,6 @@ func (c *AEADConn) Write(p []byte) (n int, err error) {
return c.Writer.Write(p)
}
func (c *AEADConn) Close() error {
c.Reader.Close()
c.Writer.Close()
return c.Conn.Close()
}
type AEADReader struct {
upstream io.Reader
cipher cipher.AEAD
@ -151,7 +145,7 @@ func NewAEADReader(upstream io.Reader, cipher cipher.AEAD) *AEADReader {
return &AEADReader{
upstream: upstream,
cipher: cipher,
data: buf.GetBytes(),
data: make([]byte, MaxPacketSize+PacketLengthBufferSize+cipher.Overhead()*2),
nonce: make([]byte, cipher.NonceSize()),
}
}
@ -160,6 +154,52 @@ func (r *AEADReader) Upstream() io.Reader {
return r.upstream
}
func (r *AEADReader) Replaceable() bool {
return false
}
func (r *AEADReader) SetUpstream(reader io.Reader) {
r.upstream = reader
}
func (r *AEADReader) WriteTo(writer io.Writer) (n int64, err error) {
if r.cached > 0 {
writeN, writeErr := writer.Write(r.data[r.index : r.index+r.cached])
if writeErr != nil {
return int64(writeN), writeErr
}
n += int64(writeN)
}
for {
start := PacketLengthBufferSize + r.cipher.Overhead()
_, err = io.ReadFull(r.upstream, r.data[:start])
if err != nil {
return
}
_, err = r.cipher.Open(r.data[:0], r.nonce, r.data[:start], nil)
if err != nil {
return
}
increaseNonce(r.nonce)
length := int(binary.BigEndian.Uint16(r.data[:PacketLengthBufferSize]))
end := length + r.cipher.Overhead()
_, err = io.ReadFull(r.upstream, r.data[:end])
if err != nil {
return
}
_, err = r.cipher.Open(r.data[:0], r.nonce, r.data[:end], nil)
if err != nil {
return
}
increaseNonce(r.nonce)
writeN, writeErr := writer.Write(r.data[:length])
if writeErr != nil {
return int64(writeN), writeErr
}
n += int64(writeN)
}
}
func (r *AEADReader) Read(b []byte) (n int, err error) {
if r.cached > 0 {
n = copy(b, r.data[r.index:r.index+r.cached])
@ -209,29 +249,19 @@ func (r *AEADReader) Read(b []byte) (n int, err error) {
}
}
func (r *AEADReader) Close() error {
if r.data != nil {
buf.PutBytes(r.data)
r.data = nil
}
return nil
}
type AEADWriter struct {
upstream io.Writer
cipher cipher.AEAD
data []byte
nonce []byte
maxDataSize int
upstream io.Writer
cipher cipher.AEAD
data []byte
nonce []byte
}
func NewAEADWriter(upstream io.Writer, cipher cipher.AEAD) *AEADWriter {
return &AEADWriter{
upstream: upstream,
cipher: cipher,
data: buf.GetBytes(),
nonce: make([]byte, cipher.NonceSize()),
maxDataSize: MaxPacketSize - PacketLengthBufferSize - cipher.Overhead()*2,
upstream: upstream,
cipher: cipher,
data: make([]byte, MaxPacketSize+PacketLengthBufferSize+cipher.Overhead()*2),
nonce: make([]byte, cipher.NonceSize()),
}
}
@ -239,47 +269,47 @@ func (w *AEADWriter) Upstream() io.Writer {
return w.upstream
}
func (w *AEADWriter) Process(p []byte) (n int, buffer *buf.Buffer, flush bool, err error) {
if len(p) > w.maxDataSize {
n, err = w.Write(p)
err = &rw.DirectException{
Suppressed: err,
func (w *AEADWriter) Replaceable() bool {
return false
}
func (w *AEADWriter) SetWriter(writer io.Writer) {
w.upstream = writer
}
func (w *AEADWriter) ReadFrom(r io.Reader) (n int64, err error) {
for {
offset := w.cipher.Overhead() + PacketLengthBufferSize
readN, readErr := r.Read(w.data[offset : offset+MaxPacketSize])
if readErr != nil {
return 0, readErr
}
return
}
binary.BigEndian.PutUint16(w.data[:PacketLengthBufferSize], uint16(len(p)))
encryptedLength := w.cipher.Seal(w.data[:0], w.nonce, w.data[:PacketLengthBufferSize], nil)
increaseNonce(w.nonce)
start := len(encryptedLength)
/*
no usage
if cap(p) > len(p)+PacketLengthBufferSize+2*w.cipher.Overhead() {
packet := w.cipher.Seal(p[:start], w.nonce, p, nil)
increaseNonce(w.nonce)
copy(p[:start], encryptedLength)
n = start + len(packet)
binary.BigEndian.PutUint16(w.data[:PacketLengthBufferSize], uint16(readN))
w.cipher.Seal(w.data[:0], w.nonce, w.data[:PacketLengthBufferSize], nil)
increaseNonce(w.nonce)
packet := w.cipher.Seal(w.data[offset:offset], w.nonce, w.data[offset:offset+readN], nil)
increaseNonce(w.nonce)
_, err = w.upstream.Write(w.data[:offset+len(packet)])
if err != nil {
return
}
*/
packet := w.cipher.Seal(w.data[:start], w.nonce, p, nil)
increaseNonce(w.nonce)
return 0, buf.As(packet), false, err
err = common.FlushVar(&w.upstream)
if err != nil {
return
}
n += int64(readN)
}
}
func (w *AEADWriter) Write(p []byte) (n int, err error) {
for _, data := range buf.ForeachN(p, w.maxDataSize) {
for _, data := range buf.ForeachN(p, MaxPacketSize) {
binary.BigEndian.PutUint16(w.data[:PacketLengthBufferSize], uint16(len(data)))
w.cipher.Seal(w.data[:0], w.nonce, w.data[:PacketLengthBufferSize], nil)
increaseNonce(w.nonce)
start := w.cipher.Overhead() + PacketLengthBufferSize
packet := w.cipher.Seal(w.data[:start], w.nonce, data, nil)
offset := w.cipher.Overhead() + PacketLengthBufferSize
packet := w.cipher.Seal(w.data[offset:offset], w.nonce, data, nil)
increaseNonce(w.nonce)
_, err = w.upstream.Write(packet)
_, err = w.upstream.Write(w.data[:offset+len(packet)])
if err != nil {
return
}
@ -289,14 +319,6 @@ func (w *AEADWriter) Write(p []byte) (n int, err error) {
return
}
func (w *AEADWriter) Close() error {
if w.data != nil {
buf.PutBytes(w.data)
w.data = nil
}
return nil
}
func increaseNonce(nonce []byte) {
for i := range nonce {
nonce[i]++

View file

@ -26,8 +26,8 @@ func (c *NoneCipher) CreateReader(_ []byte, _ []byte, reader io.Reader) io.Reade
return reader
}
func (c *NoneCipher) CreateWriter(_ []byte, _ []byte, writer io.Writer) (io.Writer, int) {
return writer, 0
func (c *NoneCipher) CreateWriter(key []byte, iv []byte, writer io.Writer) io.Writer {
return writer
}
func (c *NoneCipher) EncodePacket([]byte, *buf.Buffer) error {

View file

@ -0,0 +1,168 @@
package shadowsocks
import (
"context"
"github.com/sagernet/sing/protocol/socks"
"io"
"net"
"strconv"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/common/socksaddr"
)
var (
ErrBadKey = exceptions.New("bad key")
ErrMissingPassword = exceptions.New("password not specified")
)
type ClientConfig struct {
Server string `json:"server"`
ServerPort uint16 `json:"server_port"`
Method string `json:"method"`
Password []byte `json:"password"`
Key []byte `json:"key"`
}
type Client struct {
dialer *net.Dialer
cipher Cipher
server string
key []byte
}
func NewClient(dialer *net.Dialer, config *ClientConfig) (*Client, error) {
cipher, err := CreateCipher(config.Method)
if err != nil {
return nil, err
}
client := &Client{
dialer: dialer,
cipher: cipher,
server: net.JoinHostPort(config.Server, strconv.Itoa(int(config.ServerPort))),
}
if keyLen := len(config.Key); keyLen > 0 {
if keyLen == cipher.KeySize() {
client.key = config.Key
} else {
return nil, ErrBadKey
}
} else if len(config.Password) > 0 {
client.key = Key(config.Password, cipher.KeySize())
} else {
return nil, ErrMissingPassword
}
return client, nil
}
func (c *Client) DialContextTCP(ctx context.Context, addr socksaddr.Addr, port uint16) (net.Conn, error) {
conn, err := c.dialer.DialContext(ctx, "tcp", c.server)
if err != nil {
return nil, exceptions.Cause(err, "connect to server")
}
return c.DialConn(conn, addr, port), nil
}
func (c *Client) DialConn(conn net.Conn, addr socksaddr.Addr, port uint16) net.Conn {
header := buf.New()
header.WriteRandom(c.cipher.SaltSize())
writer := &buf.BufferedWriter{
Writer: conn,
Buffer: header,
}
protocolWriter := c.cipher.CreateWriter(c.key, header.Bytes(), writer)
requestBuffer := buf.New()
contentWriter := &buf.BufferedWriter{
Writer: protocolWriter,
Buffer: requestBuffer,
}
common.Must(AddressSerializer.WriteAddressAndPort(contentWriter, addr, port))
return &shadowsocksConn{
Client: c,
Conn: conn,
Writer: &common.FlushOnceWriter{Writer: contentWriter},
}
}
type shadowsocksConn struct {
*Client
net.Conn
io.Writer
reader io.Reader
}
func (c *shadowsocksConn) Read(p []byte) (n int, err error) {
if c.reader == nil {
buffer := buf.Or(p, c.cipher.SaltSize())
defer buffer.Release()
_, err = buffer.ReadFullFrom(c.Conn, c.cipher.SaltSize())
if err != nil {
return
}
c.reader = c.cipher.CreateReader(c.key, buffer.Bytes(), c.Conn)
}
return c.reader.Read(p)
}
func (c *shadowsocksConn) WriteTo(w io.Writer) (n int64, err error) {
if c.reader == nil {
buffer := buf.NewSize(c.cipher.SaltSize())
defer buffer.Release()
_, err = buffer.ReadFullFrom(c.Conn, c.cipher.SaltSize())
if err != nil {
return
}
c.reader = c.cipher.CreateReader(c.key, buffer.Bytes(), c.Conn)
}
return c.reader.(io.WriterTo).WriteTo(w)
}
func (c *shadowsocksConn) Write(p []byte) (n int, err error) {
return c.Writer.Write(p)
}
func (c *shadowsocksConn) ReadFrom(r io.Reader) (n int64, err error) {
return rw.ReadFromVar(&c.Writer, r)
}
func (c *Client) DialContextUDP(ctx context.Context) socks.PacketConn {
conn, err := c.dialer.DialContext(ctx, "udp", c.server)
if err != nil {
return nil
}
return &shadowsocksPacketConn{c, conn}
}
type shadowsocksPacketConn struct {
*Client
net.Conn
}
func (c *shadowsocksPacketConn) WritePacket(buffer *buf.Buffer, addr socksaddr.Addr, port uint16) error {
defer buffer.Release()
header := buf.New()
header.WriteRandom(c.cipher.SaltSize())
common.Must(AddressSerializer.WriteAddressAndPort(header, addr, port))
buffer = buffer.WriteBufferAtFirst(header)
err := c.cipher.EncodePacket(c.key, buffer)
if err != nil {
return err
}
return common.Error(c.Conn.Write(buffer.Bytes()))
}
func (c *shadowsocksPacketConn) ReadPacket(buffer *buf.Buffer) (socksaddr.Addr, uint16, error) {
n, err := c.Read(buffer.FreeBytes())
if err != nil {
return nil, 0, err
}
buffer.Truncate(n)
err = c.cipher.DecodePacket(c.key, buffer)
if err != nil {
return nil, 0, err
}
return AddressSerializer.ReadAddressAndPort(buffer)
}

View file

@ -0,0 +1 @@
package shadowsocks

78
protocol/socks/conn.go Normal file
View file

@ -0,0 +1,78 @@
package socks
import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/socksaddr"
"net"
"time"
)
type PacketConn interface {
ReadPacket(buffer *buf.Buffer) (socksaddr.Addr, uint16, error)
WritePacket(buffer *buf.Buffer, addr socksaddr.Addr, port uint16) error
Close() error
LocalAddr() net.Addr
RemoteAddr() net.Addr
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
}
func CopyPacketConn(dest PacketConn, conn PacketConn, onAction func(size int)) error {
for {
buffer := buf.New()
addr, port, err := conn.ReadPacket(buffer)
if err != nil {
buffer.Release()
return err
}
size := buffer.Len()
err = dest.WritePacket(buffer, addr, port)
if err != nil {
return err
}
if onAction != nil {
onAction(size)
}
buffer.Reset()
}
}
type associatePacketConn struct {
net.PacketConn
conn net.Conn
addr net.Addr
}
func NewPacketConn(conn net.Conn, packetConn net.PacketConn) PacketConn {
return &associatePacketConn{
PacketConn: packetConn,
conn: conn,
}
}
func (c *associatePacketConn) RemoteAddr() net.Addr {
return c.addr
}
func (c *associatePacketConn) ReadPacket(buffer *buf.Buffer) (socksaddr.Addr, uint16, error) {
n, addr, err := c.PacketConn.ReadFrom(buffer.FreeBytes())
if err != nil {
return nil, 0, err
}
c.addr = addr
buffer.Truncate(n)
buffer.Advance(3)
return AddressSerializer.ReadAddressAndPort(buffer)
}
func (c *associatePacketConn) WritePacket(buffer *buf.Buffer, addr socksaddr.Addr, port uint16) error {
defer buffer.Release()
header := buf.New()
common.Must(header.WriteZeroN(3))
common.Must(AddressSerializer.WriteAddressAndPort(header, addr, port))
buffer = buffer.WriteBufferAtFirst(header)
return common.Error(c.PacketConn.WriteTo(buffer.Bytes(), c.addr))
}

View file

@ -49,7 +49,7 @@ func ReadAuthRequest(reader io.Reader) (*AuthRequest, error) {
}
methods, err := rw.ReadBytes(reader, int(methodLen))
if err != nil {
return nil, exceptions.Cause(err, "read socks auth methods, length ", methodLen)
return nil, exceptions.CauseF(err, "read socks auth methods, length ", methodLen)
}
request := &AuthRequest{
version,