Merge from remote branch

This commit is contained in:
yaling888 2021-09-22 22:11:51 +08:00 committed by GitHub
commit 8be1d5effb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 59 additions and 68 deletions

View file

@ -12,9 +12,13 @@
<a href="https://goreportcard.com/report/github.com/Dreamacro/clash"> <a href="https://goreportcard.com/report/github.com/Dreamacro/clash">
<img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square"> <img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square">
</a> </a>
<img src="https://img.shields.io/github/go-mod/go-version/Dreamacro/clash?style=flat-square">
<a href="https://github.com/Dreamacro/clash/releases"> <a href="https://github.com/Dreamacro/clash/releases">
<img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square"> <img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square">
</a> </a>
<a href="https://github.com/Dreamacro/clash/releases/tag/premium">
<img src="https://img.shields.io/badge/release-Premium-00b4f0?style=flat-square">
</a>
</p> </p>
## Features ## Features
@ -22,7 +26,7 @@
- Local HTTP/HTTPS/SOCKS server with authentication support - Local HTTP/HTTPS/SOCKS server with authentication support
- VMess, Shadowsocks, Trojan, Snell protocol support for remote connections - VMess, Shadowsocks, Trojan, Snell protocol support for remote connections
- Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP. - Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP.
- Rules based off domains, GEOIP, IP CIDR or ports to forward packets to different nodes - Rules based off domains, GEOIP, IPCIDR or Process to forward packets to different nodes
- Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency - Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency
- Remote providers, allowing users to get node lists remotely instead of hardcoding in config - Remote providers, allowing users to get node lists remotely instead of hardcoding in config
- Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`. - Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`.
@ -214,16 +218,10 @@ If you want to build an application that uses clash as a library, check out the
* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2) * [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2)
* [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core) * [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core)
* [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go)
## License ## License
This software is released under the GPL-3.0 license. This software is released under the GPL-3.0 license.
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large)
## TODO
- [x] Complementing the necessary rule operators
- [x] Redir proxy
- [x] UDP support
- [x] Connection manager

17
common/pool/buffer.go Normal file
View file

@ -0,0 +1,17 @@
package pool
import (
"bytes"
"sync"
)
var bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
func GetBuffer() *bytes.Buffer {
return bufferPool.Get().(*bytes.Buffer)
}
func PutBuffer(buf *bytes.Buffer) {
buf.Reset()
bufferPool.Put(buf)
}

View file

@ -5,7 +5,6 @@ package gun
import ( import (
"bufio" "bufio"
"bytes"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
"errors" "errors"
@ -17,6 +16,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/Dreamacro/clash/common/pool"
"go.uber.org/atomic" "go.uber.org/atomic"
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
@ -31,7 +32,6 @@ var (
"content-type": []string{"application/grpc"}, "content-type": []string{"application/grpc"},
"user-agent": []string{"grpc-go/1.36.0"}, "user-agent": []string{"grpc-go/1.36.0"},
} }
bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
) )
type DialFn = func(network, addr string) (net.Conn, error) type DialFn = func(network, addr string) (net.Conn, error)
@ -127,9 +127,8 @@ func (g *Conn) Write(b []byte) (n int, err error) {
grpcPayloadLen := uint32(varuintSize + 1 + len(b)) grpcPayloadLen := uint32(varuintSize + 1 + len(b))
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen) binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
buf := bufferPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer bufferPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
buf.Write(grpcHeader) buf.Write(grpcHeader)
buf.Write(protobufHeader[:varuintSize+1]) buf.Write(protobufHeader[:varuintSize+1])
buf.Write(b) buf.Write(b)

View file

@ -102,7 +102,8 @@ func (to *TLSObfs) write(b []byte) (int, error) {
return len(b), err return len(b), err
} }
buf := &bytes.Buffer{} buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
buf.Write([]byte{0x17, 0x03, 0x03}) buf.Write([]byte{0x17, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint16(len(b))) binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b) buf.Write(b)

View file

@ -1,13 +1,13 @@
package snell package snell
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net" "net"
"sync"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/go-shadowsocks2/shadowaead" "github.com/Dreamacro/go-shadowsocks2/shadowaead"
) )
@ -31,7 +31,6 @@ const (
) )
var ( var (
bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
endSignal = []byte{} endSignal = []byte{}
) )
@ -79,9 +78,8 @@ func (s *Snell) Read(b []byte) (int, error) {
} }
func WriteHeader(conn net.Conn, host string, port uint, version int) error { func WriteHeader(conn net.Conn, host string, port uint, version int) error {
buf := bufferPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
buf.Reset() defer pool.PutBuffer(buf)
defer bufferPool.Put(buf)
buf.WriteByte(Version) buf.WriteByte(Version)
if version == Version2 { if version == Version2 {
buf.WriteByte(CommandConnectV2) buf.WriteByte(CommandConnectV2)

View file

@ -10,7 +10,6 @@ import (
"strings" "strings"
"github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/ssr/tools"
) )
func init() { func init() {
@ -102,9 +101,8 @@ func (c *httpConn) Write(b []byte) (int, error) {
hosts := strings.Split(host, ",") hosts := strings.Split(host, ",")
host = hosts[rand.Intn(len(hosts))] host = hosts[rand.Intn(len(hosts))]
buf := tools.BufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer tools.BufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
if c.post { if c.post {
buf.WriteString("POST /") buf.WriteString("POST /")
} else { } else {

View file

@ -87,9 +87,8 @@ func (c *tls12TicketConn) Read(b []byte) (int, error) {
func (c *tls12TicketConn) Write(b []byte) (int, error) { func (c *tls12TicketConn) Write(b []byte) (int, error) {
length := len(b) length := len(b)
if c.handshakeStatus == 8 { if c.handshakeStatus == 8 {
buf := tools.BufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer tools.BufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
for len(b) > 2048 { for len(b) > 2048 {
size := rand.Intn(4096) + 100 size := rand.Intn(4096) + 100
if len(b) < size { if len(b) < size {
@ -115,9 +114,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
if c.handshakeStatus == 0 { if c.handshakeStatus == 0 {
c.handshakeStatus = 1 c.handshakeStatus = 1
data := tools.BufPool.Get().(*bytes.Buffer) data := pool.GetBuffer()
defer tools.BufPool.Put(data) defer pool.PutBuffer(data)
defer data.Reset()
data.Write([]byte{3, 3}) data.Write([]byte{3, 3})
c.packAuthData(data) c.packAuthData(data)
@ -126,9 +124,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a}) data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a})
data.Write([]byte{0x1, 0x0}) data.Write([]byte{0x1, 0x0})
ext := tools.BufPool.Get().(*bytes.Buffer) ext := pool.GetBuffer()
defer tools.BufPool.Put(ext) defer pool.PutBuffer(ext)
defer ext.Reset()
host := c.getHost() host := c.getHost()
ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00}) ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00})
@ -145,9 +142,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
binary.Write(data, binary.BigEndian, uint16(ext.Len())) binary.Write(data, binary.BigEndian, uint16(ext.Len()))
data.ReadFrom(ext) data.ReadFrom(ext)
ret := tools.BufPool.Get().(*bytes.Buffer) ret := pool.GetBuffer()
defer tools.BufPool.Put(ret) defer pool.PutBuffer(ret)
defer ret.Reset()
ret.Write([]byte{0x16, 3, 1}) ret.Write([]byte{0x16, 3, 1})
binary.Write(ret, binary.BigEndian, uint16(data.Len()+4)) binary.Write(ret, binary.BigEndian, uint16(data.Len()+4))
@ -161,9 +157,8 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) {
} }
return length, nil return length, nil
} else if c.handshakeStatus == 1 && len(b) == 0 { } else if c.handshakeStatus == 1 && len(b) == 0 {
buf := tools.BufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer tools.BufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20}) buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20})
tools.AppendRandBytes(buf, 22) tools.AppendRandBytes(buf, 22)

View file

@ -1,10 +1,9 @@
package protocol package protocol
import ( import (
"bytes"
"net" "net"
"github.com/Dreamacro/clash/transport/ssr/tools" "github.com/Dreamacro/clash/common/pool"
) )
type PacketConn struct { type PacketConn struct {
@ -13,9 +12,8 @@ type PacketConn struct {
} }
func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
buf := tools.BufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer tools.BufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
err := c.EncodePacket(buf, b) err := c.EncodePacket(buf, b)
if err != nil { if err != nil {
return 0, err return 0, err

View file

@ -5,7 +5,6 @@ import (
"net" "net"
"github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/ssr/tools"
) )
type Conn struct { type Conn struct {
@ -37,9 +36,8 @@ func (c *Conn) Read(b []byte) (int, error) {
func (c *Conn) Write(b []byte) (int, error) { func (c *Conn) Write(b []byte) (int, error) {
bLength := len(b) bLength := len(b)
buf := tools.BufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer tools.BufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
err := c.Encode(buf, b) err := c.Encode(buf, b)
if err != nil { if err != nil {
return 0, err return 0, err

View file

@ -2,17 +2,10 @@ package tools
import ( import (
"bytes" "bytes"
"math/rand" "crypto/rand"
"sync" "io"
"github.com/Dreamacro/clash/common/pool"
) )
var BufPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
func AppendRandBytes(b *bytes.Buffer, length int) { func AppendRandBytes(b *bytes.Buffer, length int) {
randBytes := pool.Get(length) b.ReadFrom(io.LimitReader(rand.Reader, int64(length)))
defer pool.Put(randBytes)
rand.Read(randBytes)
b.Write(randBytes)
} }

View file

@ -1,7 +1,6 @@
package trojan package trojan
import ( import (
"bytes"
"crypto/sha256" "crypto/sha256"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
@ -11,6 +10,7 @@ import (
"net" "net"
"sync" "sync"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
) )
@ -22,8 +22,6 @@ const (
var ( var (
defaultALPN = []string{"h2", "http/1.1"} defaultALPN = []string{"h2", "http/1.1"}
crlf = []byte{'\r', '\n'} crlf = []byte{'\r', '\n'}
bufPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
) )
type Command = byte type Command = byte
@ -67,9 +65,8 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
} }
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error { func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
buf := bufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer bufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
buf.Write(t.hexPassword) buf.Write(t.hexPassword)
buf.Write(crlf) buf.Write(crlf)
@ -89,9 +86,8 @@ func (t *Trojan) PacketConn(conn net.Conn) net.PacketConn {
} }
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) { func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
buf := bufPool.Get().(*bytes.Buffer) buf := pool.GetBuffer()
defer bufPool.Put(buf) defer pool.PutBuffer(buf)
defer buf.Reset()
buf.Write(socks5Addr) buf.Write(socks5Addr)
binary.Write(buf, binary.BigEndian, uint16(len(payload))) binary.Write(buf, binary.BigEndian, uint16(len(payload)))