mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-04 04:17:38 +03:00
Add http support for sslocal
This commit is contained in:
parent
542fa4f975
commit
26e13e7beb
30 changed files with 1355 additions and 194 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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]++
|
||||
|
|
|
@ -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 {
|
||||
|
|
168
protocol/shadowsocks/client.go
Normal file
168
protocol/shadowsocks/client.go
Normal 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)
|
||||
}
|
1
protocol/shadowsocks/config.go
Normal file
1
protocol/shadowsocks/config.go
Normal file
|
@ -0,0 +1 @@
|
|||
package shadowsocks
|
78
protocol/socks/conn.go
Normal file
78
protocol/socks/conn.go
Normal 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))
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue