Skip to content

Commit

Permalink
Merge branch 'Alpha' into Meta
Browse files Browse the repository at this point in the history
  • Loading branch information
Larvan2 committed Sep 25, 2023
2 parents 65071ea + fdd327d commit ffaa40c
Show file tree
Hide file tree
Showing 108 changed files with 2,185 additions and 801 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:
if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }}
id: setup-ndk
with:
ndk-version: r25b
ndk-version: r26
add-to-path: false
local-cache: true

Expand Down Expand Up @@ -204,7 +204,7 @@ jobs:

Upload-Prerelease:
permissions: write-all
if: ${{ github.ref_type=='branch' }}
if: ${{ github.ref_type=='branch' && github.event_name != 'pull_request' }}
needs: [Build]
runs-on: ubuntu-latest
steps:
Expand Down
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,22 @@
- 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.
- 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 providers, allowing users to get node lists remotely instead of hardcoding in config
- 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 hard-coding in config
- Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`.
- Comprehensive HTTP RESTful API controller

## Dashboard

We made an official web dashboard providing first class support for this project, check it out
at [metacubexd](https://github.com/MetaCubeX/metacubexd)

## Wiki
Configuration examples can be found at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be found [Clash.Meta Wiki](https://clash-meta.wiki).

Configuration examples can be found
at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be
found [Clash.Meta Wiki](https://clash-meta.wiki).

## Build

Expand All @@ -43,7 +52,7 @@ git clone https://github.com/MetaCubeX/Clash.Meta.git
cd Clash.Meta && go mod download
```

If you can't visit github,you should set proxy first:
If you can't visit GitHub, you should set proxy first:

```shell
go env -w GOPROXY=https://goproxy.io,direct
Expand Down Expand Up @@ -324,36 +333,27 @@ ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta
WantedBy=multi-user.target
```

Launch clashd on system startup with:
Launch clash-meta daemon on system startup with:

```shell
$ systemctl enable Clash-Meta
```

Launch clashd immediately with:
Launch clash-meta daemon immediately with:

```shell
$ systemctl start Clash-Meta
```

### Display Process name

Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`.

To display process name in GUI please use [Razord-meta](https://github.com/MetaCubeX/Razord-meta).

### Dashboard

We also made a custom fork of yacd provide better support for this project, check it out at [Yacd-meta](https://github.com/MetaCubeX/Yacd-meta)

## Development

If you want to build an application that uses clash as a library, check out the
If you want to build an application that uses clash as a library, check out
the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)

## Debugging
Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug API.

Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug
API.

## Credits

Expand Down
87 changes: 48 additions & 39 deletions adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"

"github.com/puzpuzpuz/xsync/v2"
)

var UnifiedDelay = atomic.NewBool(false)
Expand All @@ -36,7 +38,7 @@ type Proxy struct {
history *queue.Queue[C.DelayHistory]
alive *atomic.Bool
url string
extra map[string]*extraProxyState
extra *xsync.MapOf[string, *extraProxyState]
}

// Alive implements C.Proxy
Expand All @@ -46,10 +48,8 @@ func (p *Proxy) Alive() bool {

// AliveForTestUrl implements C.Proxy
func (p *Proxy) AliveForTestUrl(url string) bool {
if p.extra != nil {
if state, ok := p.extra[url]; ok {
return state.alive.Load()
}
if state, ok := p.extra.Load(url); ok {
return state.alive.Load()
}

return p.alive.Load()
Expand Down Expand Up @@ -88,16 +88,16 @@ func (p *Proxy) DelayHistory() []C.DelayHistory {
for _, item := range queueM {
histories = append(histories, item)
}

return histories
}

// DelayHistoryForTestUrl implements C.Proxy
func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory {
var queueM []C.DelayHistory
if p.extra != nil {
if state, ok := p.extra[url]; ok {
queueM = state.history.Copy()
}

if state, ok := p.extra.Load(url); ok {
queueM = state.history.Copy()
}

if queueM == nil {
Expand All @@ -112,19 +112,25 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory {
}

func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory {
extra := map[string][]C.DelayHistory{}
if p.extra != nil && len(p.extra) != 0 {
for testUrl, option := range p.extra {
histories := []C.DelayHistory{}
queueM := option.history.Copy()
for _, item := range queueM {
histories = append(histories, item)
}
extraHistory := map[string][]C.DelayHistory{}

extra[testUrl] = histories
p.extra.Range(func(k string, v *extraProxyState) bool {

testUrl := k
state := v

histories := []C.DelayHistory{}
queueM := state.history.Copy()

for _, item := range queueM {
histories = append(histories, item)
}
}
return extra

extraHistory[testUrl] = histories

return true
})
return extraHistory
}

// LastDelay return last history record. if proxy is not alive, return the max value of uint16.
Expand All @@ -149,11 +155,9 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) {
alive := p.alive.Load()
history := p.history.Last()

if p.extra != nil {
if state, ok := p.extra[url]; ok {
alive = state.alive.Load()
history = state.history.Last()
}
if state, ok := p.extra.Load(url); ok {
alive = state.alive.Load()
history = state.history.Last()
}

if !alive {
Expand Down Expand Up @@ -213,18 +217,18 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In
if alive {
record.Delay = t
}

if p.extra == nil {
p.extra = map[string]*extraProxyState{}
p.history.Put(record)
if p.history.Len() > defaultHistoriesNum {
p.history.Pop()
}

state, ok := p.extra[url]
state, ok := p.extra.Load(url)
if !ok {
state = &extraProxyState{
history: queue.New[C.DelayHistory](defaultHistoriesNum),
alive: atomic.NewBool(true),
}
p.extra[url] = state
p.extra.Store(url, state)
}

state.alive.Store(alive)
Expand Down Expand Up @@ -307,7 +311,12 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In
}

func NewProxy(adapter C.ProxyAdapter) *Proxy {
return &Proxy{adapter, queue.New[C.DelayHistory](defaultHistoriesNum), atomic.NewBool(true), "", map[string]*extraProxyState{}}
return &Proxy{
ProxyAdapter: adapter,
history: queue.New[C.DelayHistory](defaultHistoriesNum),
alive: atomic.NewBool(true),
url: "",
extra: xsync.NewMapOf[*extraProxyState]()}
}

func urlToMetadata(rawURL string) (addr C.Metadata, err error) {
Expand Down Expand Up @@ -350,14 +359,14 @@ func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url strin
return C.OriginalHistory
}

if p.extra == nil {
store = C.ExtraHistory
} else {
if _, ok := p.extra[url]; ok {
store = C.ExtraHistory
} else if len(p.extra) < 2*C.DefaultMaxHealthCheckUrlNum {
store = C.ExtraHistory
}
if p.extra.Size() < 2*C.DefaultMaxHealthCheckUrlNum {
return C.ExtraHistory
}

_, ok := p.extra.Load(url)
if ok {
return C.ExtraHistory
}

return store
}
27 changes: 25 additions & 2 deletions adapter/outbound/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package outbound
import (
"context"
"errors"
"net/netip"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
Expand All @@ -12,14 +15,19 @@ type Direct struct {
*Base
}

type DirectOption struct {
BasicOption
Name string `proxy:"name"`
}

// DialContext implements C.ProxyAdapter
func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
opts = append(opts, dialer.WithResolver(resolver.DefaultResolver))
c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
return NewConn(c, d), nil
}

Expand All @@ -33,13 +41,28 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
}
metadata.DstIP = ip
}
pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", metadata.DstIP), "", d.Base.DialOptions(opts...)...)
pc, err := dialer.NewDialer(d.Base.DialOptions(opts...)...).ListenPacket(ctx, "udp", "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort))
if err != nil {
return nil, err
}
return newPacketConn(pc, d), nil
}

func NewDirectWithOption(option DirectOption) *Direct {
return &Direct{
Base: &Base{
name: option.Name,
tp: C.Direct,
udp: true,
tfo: option.TFO,
mpTcp: option.MPTCP,
iface: option.Interface,
rmark: option.RoutingMark,
prefer: C.NewDNSPrefer(option.IPVersion),
},
}
}

func NewDirect() *Direct {
return &Direct{
Base: &Base{
Expand Down
26 changes: 11 additions & 15 deletions adapter/outbound/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import (
"encoding/base64"
"errors"
"fmt"

"io"
"net"
"net/http"
"strconv"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/ca"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/proxydialer"
tlsC "github.com/Dreamacro/clash/component/tls"
C "github.com/Dreamacro/clash/constant"
)

Expand Down Expand Up @@ -74,7 +76,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", h.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down Expand Up @@ -155,19 +157,13 @@ func NewHttp(option HttpOption) (*Http, error) {
if option.SNI != "" {
sni = option.SNI
}
if len(option.Fingerprint) == 0 {
tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
ServerName: sni,
})
} else {
var err error
if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(&tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
ServerName: sni,
}, option.Fingerprint); err != nil {
return nil, err
}
var err error
tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
ServerName: sni,
}, option.Fingerprint)
if err != nil {
return nil, err
}
}

Expand Down
Loading

0 comments on commit ffaa40c

Please sign in to comment.