mirror of
https://github.com/daeuniverse/dae.git
synced 2024-12-22 16:24:40 +07:00
Merge remote-tracking branch 'origin/main' into fix_refine_dns_ttl
This commit is contained in:
commit
2d96b3c59c
6
.github/ISSUE_TEMPLATE/bug-report.md
vendored
6
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -8,15 +8,15 @@ labels: kind/bug
|
||||
Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!
|
||||
-->
|
||||
|
||||
## What happened:
|
||||
## What happened
|
||||
|
||||
## What you expected to happen:
|
||||
## What you expected to happen
|
||||
|
||||
## How to reproduce it (as minimally and precisely as possible):
|
||||
|
||||
## Anything else we need to know
|
||||
|
||||
## Environment:
|
||||
## Environment
|
||||
|
||||
- Dae version (use `dae --version`):
|
||||
- OS (e.g `cat /etc/os-release`):
|
||||
|
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@ -16,4 +16,4 @@ You may also post your idea on the Discussions or the Dae Telegram channel (http
|
||||
|
||||
## What feature you would like us to integrate into the dae project
|
||||
|
||||
## Why is this needed:
|
||||
## Why is this needed
|
||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -4,8 +4,6 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- fix*
|
||||
- feat*
|
||||
paths:
|
||||
- "**/*.go"
|
||||
- "**/*.c"
|
||||
|
14
.github/workflows/check-docs.yml
vendored
14
.github/workflows/check-docs.yml
vendored
@ -1,17 +1,13 @@
|
||||
name: Check document
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'docs/**'
|
||||
- 'package.json'
|
||||
- '.autocorrectrc'
|
||||
- '.markdownlint-cli2.jsonc'
|
||||
- '.github/workflows/check-docs.yml'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'docs/**'
|
||||
|
110
.github/workflows/sync-docs.yml
vendored
Normal file
110
.github/workflows/sync-docs.yml
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
name: Synchronize document
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'ci/**'
|
||||
- 'release/**'
|
||||
tags:
|
||||
- 'v*'
|
||||
paths:
|
||||
- "README*.md"
|
||||
- "docs/**"
|
||||
- "example.dae"
|
||||
- "package.json"
|
||||
- ".autocorrectrc"
|
||||
- ".markdownlint-cli2.jsonc"
|
||||
- '.github/workflows/sync-docs.yml'
|
||||
|
||||
jobs:
|
||||
check-docs:
|
||||
name: Check document
|
||||
uses: ./.github/workflows/check-docs.yml
|
||||
|
||||
replicate-config:
|
||||
needs: [check-docs]
|
||||
name: Replicate relevant document
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
git_sha_long: ${{ steps.export.outputs.git_sha_long }}
|
||||
git_sha_short: ${{ steps.export.outputs.git_sha_short }}
|
||||
git_commit_msg: ${{ steps.export.outputs.git_commit_msg }}
|
||||
git_run_number: ${{ steps.export.outputs.git_run_number }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get metadata from HEAD sha
|
||||
id: export
|
||||
run: |
|
||||
echo "git_sha_long=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||
echo "git_sha_short=$(echo ${{ github.sha }} | cut -c1-6)" >> $GITHUB_OUTPUT
|
||||
echo "git_commit_msg=$(git log --format=%s -n 1 ${{ github.sha }})" >> $GITHUB_OUTPUT
|
||||
echo "git_run_number=${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate artifacts
|
||||
run: |
|
||||
python3 hack/ci/config-doc-generator.py
|
||||
|
||||
- name: Export artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pre_flight_artifacts
|
||||
path: |
|
||||
./docs/sync/*.md
|
||||
|
||||
sync-to-dae-docs:
|
||||
needs: [replicate-config]
|
||||
name: Synchronize changes to dae-docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout to daeuniverse/dae-docs
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: daeuniverse/dae-docs
|
||||
fetch-depth: 0
|
||||
ref: master
|
||||
|
||||
- name: Copy artifacts from build job to local path
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: pre_flight_artifacts
|
||||
path: docs/
|
||||
|
||||
- name: Create commits
|
||||
run: |
|
||||
git config user.name 'daebot'
|
||||
git config user.email 'daebot@users.noreply.github.com'
|
||||
git ls-files --others --exclude-standard -- "*.md"
|
||||
git add "*.md"
|
||||
git commit -m "ci(auto-release): push proposed documentation changes from upstream dae project"
|
||||
|
||||
- name: Create Pull Request
|
||||
id: create_pr
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
author: daebot <dae@v2raya.org>
|
||||
committer: daebot <dae@v2raya.org>
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
signoff: false
|
||||
branch: automated-pr-sync
|
||||
delete-branch: true
|
||||
title: 'ci(auto-release): sync changes from upstream'
|
||||
body: |
|
||||
## Summary
|
||||
|
||||
Update documentation - Auto-generated by [${{ github.repository }} #${{ needs.replicate-config.outputs.git_run_number }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) @daebot
|
||||
|
||||
Commit message: ${{ needs.replicate-config.outputs.git_commit_msg }}
|
||||
|
||||
## Context
|
||||
|
||||
🏗 daeuniverse/dae(${{ needs.replicate-config.outputs.git_sha_short }}): Build [#${{ needs.replicate-config.outputs.git_run_number }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) succeeded!
|
||||
|
||||
labels: |
|
||||
automated-pr
|
||||
assignees: daebot
|
||||
team-reviewers: |
|
||||
docs
|
||||
draft: false
|
||||
|
@ -12,9 +12,9 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.
|
||||
|
||||
## Releases
|
||||
|
||||
- [0.1.10rc1 (Pre-release)](#0110rc1-pre-release)
|
||||
- [0.1.10rc (Pre-release)](#0110rc-pre-release)
|
||||
- [0.1.9-patch.1 (Current)](#019-patch1-current)
|
||||
- [0.2.0rc1 (Pre-release)](#020rc1-pre-release)
|
||||
- [0.1.10 (Current)](#0110-current)
|
||||
- [0.1.9-patch.1](#019-patch1)
|
||||
- [0.1.9](#019)
|
||||
- [0.1.8](#018)
|
||||
- [0.1.7](#017)
|
||||
@ -26,29 +26,68 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.
|
||||
- [0.1.1](#011)
|
||||
- [0.1.0](#010)
|
||||
|
||||
### 0.1.10rc1 (Pre-release)
|
||||
### 0.2.0rc1 (Pre-release)
|
||||
|
||||
> Release date: 2023/05/15
|
||||
> Release date: 2023/06/04
|
||||
|
||||
#### 功能变更
|
||||
|
||||
- patch(geodata): 修复由 #84 导致的错误的 geodata 搜索路径 `/etc/dae/dae` by @mzz2017 in https://github.com/daeuniverse/dae/pull/90
|
||||
- feat: 支持 iptables/nftables 的 mangle 表 tproxy by @mzz2017 in https://github.com/daeuniverse/dae/pull/80
|
||||
- feat: 支持 uTLS by @AkinoKaede in https://github.com/daeuniverse/dae/pull/94
|
||||
- feat: 支持在 geosite 使用属性标签 `@` 符号 by @mzz2017 in https://github.com/daeuniverse/dae/pull/98
|
||||
- feat(dns): 支持为特定域名设定固定的 ttl,这对 DDNS 场景较为有用 by @mzz2017 in https://github.com/daeuniverse/dae/pull/100
|
||||
- fix(dns): 修复 DNS 中 qname 匹配规则失效的问题 by @mzz2017 in https://github.com/daeuniverse/dae/pull/99
|
||||
- fix: 修复启动时网络检查链接列表的随机排布问题 by @mzz2017 in https://github.com/daeuniverse/dae/pull/106
|
||||
- fix(config_parser): 修复配置文件格式错误时潜在的崩溃问题 by @mzz2017 in https://github.com/daeuniverse/dae/pull/108
|
||||
- fix(trojan): 修复 trojan 崩溃问题,该问题由 ReadFrom 返回的 n 可能不正确导致 by @mzz2017 in https://github.com/daeuniverse/dae/pull/109
|
||||
|
||||
#### 其他变更
|
||||
|
||||
- ci: 添加文档格式检查工作流 by @yqlbu in https://github.com/daeuniverse/dae/pull/93
|
||||
- refactor: 将 insert.sh 移动至 ./hack/test by @yqlbu in https://github.com/daeuniverse/dae/pull/95
|
||||
- ci(hack): 添加 config-doc-generator by @yqlbu in https://github.com/daeuniverse/dae/pull/101
|
||||
- fix(test): 修复 domain_matcher/benchmark_test.go in https://github.com/daeuniverse/dae/pull/107
|
||||
- ci: 添加文档自动同步至 dae-docs 项目 by @yqlbu in https://github.com/daeuniverse/dae/pull/103
|
||||
- docs(routing.md): 修订 fwmark 一节的文档 by @mzz2017 in https://github.com/daeuniverse/dae/pull/113
|
||||
|
||||
#### Changes
|
||||
|
||||
- patch(geodata): fix incorrect geodata search path `/etc/dae/dae` caused by #84 by @mzz2017 in https://github.com/daeuniverse/dae/pull/90
|
||||
- feat: support iptables tproxy by @mzz2017 in https://github.com/daeuniverse/dae/pull/80
|
||||
- feat: add uTLS support by @AkinoKaede in https://github.com/daeuniverse/dae/pull/94
|
||||
- feat: support geosite attr by @mzz2017 in https://github.com/daeuniverse/dae/pull/98
|
||||
- fix(dns): mismatched qname matching rules by @mzz2017 in https://github.com/daeuniverse/dae/pull/99
|
||||
- feat(dns): support fixed domain ttl by @mzz2017 in https://github.com/daeuniverse/dae/pull/100
|
||||
- fix: rand seed for network check by @mzz2017 in https://github.com/daeuniverse/dae/pull/106
|
||||
- fix(config_parser): potential panic due to out of index by @mzz2017 in https://github.com/daeuniverse/dae/pull/108
|
||||
- fix(trojan): potential panic due to incorrect n returned by ReadFrom by @mzz2017 in https://github.com/daeuniverse/dae/pull/109
|
||||
|
||||
**Full Changelog**: https://github.com/daeuniverse/dae/compare/v0.1.10rc...v0.1.10rc1
|
||||
#### Other Changes
|
||||
|
||||
### 0.1.10rc (Pre-release)
|
||||
- ci: add check-docs workflow by @yqlbu in https://github.com/daeuniverse/dae/pull/93
|
||||
- refactor: move insert.sh to ./hack/test by @yqlbu in https://github.com/daeuniverse/dae/pull/95
|
||||
- ci(hack): add config-doc-generator by @yqlbu in https://github.com/daeuniverse/dae/pull/101
|
||||
- fix(test): domain_matcher/benchmark_test.go in https://github.com/daeuniverse/dae/pull/107
|
||||
- ci: docs synchronization by @yqlbu in https://github.com/daeuniverse/dae/pull/103
|
||||
- docs(routing.md): revise fwmark section by @mzz2017 in https://github.com/daeuniverse/dae/pull/113
|
||||
|
||||
> Release date: 2023/05/14
|
||||
#### New Contributors
|
||||
|
||||
- @AkinoKaede made their first contribution in https://github.com/daeuniverse/dae/pull/94
|
||||
|
||||
**Full Changelog**: https://github.com/daeuniverse/dae/compare/v0.1.10...v0.2.0rc1
|
||||
|
||||
**Example Config**: https://github.com/daeuniverse/dae/blob/v0.2.0rc1/example.dae
|
||||
|
||||
### 0.1.10 (Current)
|
||||
|
||||
> Release date: 2023/06/04
|
||||
|
||||
#### 功能变更
|
||||
|
||||
- feat: 支持 `tcp_check_http_method` by @mzz2017 in https://github.com/daeuniverse/dae/pull/77
|
||||
- patch: 现在会优先在配置文件同目录搜索 geodata by @mzz2017 in https://github.com/daeuniverse/dae/pull/84
|
||||
- fix(dns): 修复 0.1.8 版本中 PR #63 导致的 DNS 缓存不会过期的问题 by @mzz2017 in https://github.com/daeuniverse/dae/pull/87
|
||||
- patch(geodata): 修复由 #84 导致的错误的 geodata 搜索路径 `/etc/dae/dae` by @mzz2017 in https://github.com/daeuniverse/dae/pull/90
|
||||
|
||||
#### 其他变更
|
||||
|
||||
@ -61,6 +100,7 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.
|
||||
- feat: support `tcp_check_http_method` by @mzz2017 in https://github.com/daeuniverse/dae/pull/77
|
||||
- patch: search geodata at same dir with config first by @mzz2017 in https://github.com/daeuniverse/dae/pull/84
|
||||
- fix(dns): cache would never expire caused by #63 by accident by @mzz2017 in https://github.com/daeuniverse/dae/pull/87
|
||||
- patch(geodata): fix incorrect geodata search path `/etc/dae/dae` caused by #84 by @mzz2017 in https://github.com/daeuniverse/dae/pull/90
|
||||
|
||||
#### Other Changes
|
||||
|
||||
@ -68,9 +108,11 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.
|
||||
- chore: add editorconfig by @yqlbu in https://github.com/daeuniverse/dae/pull/85
|
||||
- chore: add pull_request_template by @yqlbu in https://github.com/daeuniverse/dae/pull/86
|
||||
|
||||
**Full Changelog**: https://github.com/daeuniverse/dae/compare/v0.1.9...v0.1.10rc
|
||||
**Full Changelog**: https://github.com/daeuniverse/dae/compare/v0.1.9...v0.1.10
|
||||
|
||||
### 0.1.9-patch.1 (Current)
|
||||
**Example Config**: https://github.com/daeuniverse/dae/blob/v0.1.10/example.dae
|
||||
|
||||
### 0.1.9-patch.1
|
||||
|
||||
> Release date: 2023/05/14
|
||||
|
||||
|
3
Makefile
3
Makefile
@ -23,6 +23,7 @@ else
|
||||
STRIP_FLAG := -strip=$(STRIP_PATH)
|
||||
endif
|
||||
|
||||
# Do NOT remove the line below. This line is for CI.
|
||||
#export GOMODCACHE=$(PWD)/go-mod
|
||||
|
||||
# Get version from .git.
|
||||
@ -41,7 +42,7 @@ dae: export GOOS=linux
|
||||
dae: ebpf
|
||||
go build -o $(OUTPUT) -trimpath -ldflags "-s -w -X github.com/daeuniverse/dae/cmd.Version=$(VERSION) -X github.com/daeuniverse/dae/common/consts.MaxMatchSetLen_=$(MAX_MATCH_SET_LEN)" .
|
||||
|
||||
clean-ebpf:
|
||||
clean-ebpf:
|
||||
@rm -f control/bpf_bpf*.go && \
|
||||
rm -f control/bpf_bpf*.o
|
||||
fmt:
|
||||
|
@ -5,7 +5,7 @@
|
||||
<p align="left">
|
||||
<img src="https://custom-icon-badges.herokuapp.com/github/license/daeuniverse/dae?logo=law&color=orange" alt="License"/>
|
||||
<img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fdaeuniverse%2Fdae&count_bg=%235C3DC8&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false"/>
|
||||
<img src="https://custom-icon-badges.herokuapp.com/badge/version-v0.1.9-blue.svg?logo=semanticrelease&logoColor=white" alt="version">
|
||||
<img src="https://custom-icon-badges.herokuapp.com/badge/version-v0.2.0rc1-blue.svg?logo=semanticrelease&logoColor=white" alt="version">
|
||||
<img src="https://custom-icon-badges.herokuapp.com/github/issues-pr-closed/daeuniverse/dae?color=purple&logo=git-pull-request&logoColor=white"/>
|
||||
<img src="https://custom-icon-badges.herokuapp.com/github/last-commit/daeuniverse/dae?logo=history&logoColor=white" alt="lastcommit"/>
|
||||
</p>
|
||||
|
36
cmd/run.go
36
cmd/run.go
@ -1,9 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mzz2017/softwind/netproxy"
|
||||
"github.com/mzz2017/softwind/pkg/fastrand"
|
||||
"github.com/mzz2017/softwind/protocol/direct"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -247,6 +250,20 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
if !conf.Global.DisableWaitingNetwork && len(conf.Subscription) > 0 {
|
||||
epo := 5 * time.Second
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) {
|
||||
cd := netproxy.ContextDialer{Dialer: direct.SymmetricDirect}
|
||||
conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae), addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netproxy.FakeNetConn{
|
||||
Conn: conn,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
Timeout: epo,
|
||||
}
|
||||
log.Infoln("Waiting for network...")
|
||||
@ -274,8 +291,25 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
|
||||
if len(conf.Subscription) > 0 {
|
||||
log.Infoln("Fetching subscriptions...")
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) {
|
||||
cd := netproxy.ContextDialer{Dialer: direct.SymmetricDirect}
|
||||
conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae), addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netproxy.FakeNetConn{
|
||||
Conn: conn,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
for _, sub := range conf.Subscription {
|
||||
tag, nodes, err := subscription.ResolveSubscription(log, filepath.Dir(cfgFile), string(sub))
|
||||
tag, nodes, err := subscription.ResolveSubscription(log, &client, filepath.Dir(cfgFile), string(sub))
|
||||
if err != nil {
|
||||
log.Warnf(`failed to resolve subscription "%v": %v`, sub, err)
|
||||
resolvingfailed = true
|
||||
|
@ -146,6 +146,7 @@ var (
|
||||
|
||||
const (
|
||||
TproxyMark uint32 = 0x8000000
|
||||
Recognize uint16 = 0x2017
|
||||
LoopbackIfIndex = 1
|
||||
)
|
||||
|
||||
|
@ -19,7 +19,6 @@ import (
|
||||
"github.com/mzz2017/softwind/netproxy"
|
||||
"github.com/mzz2017/softwind/pkg/fastrand"
|
||||
"github.com/mzz2017/softwind/pool"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
@ -91,8 +90,8 @@ func SystemDns() (dns netip.AddrPort, err error) {
|
||||
return systemDns, nil
|
||||
}
|
||||
|
||||
func ResolveNetip(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, typ dnsmessage.Type, tcp bool) (addrs []netip.Addr, err error) {
|
||||
resources, err := resolve(ctx, d, dns, host, typ, tcp)
|
||||
func ResolveNetip(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, typ dnsmessage.Type, network string) (addrs []netip.Addr, err error) {
|
||||
resources, err := resolve(ctx, d, dns, host, typ, network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -118,16 +117,14 @@ func ResolveNetip(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, ho
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
func ResolveNS(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, tcp bool) (records []string, err error) {
|
||||
func ResolveNS(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, network string) (records []string, err error) {
|
||||
typ := dnsmessage.TypeNS
|
||||
resources, err := resolve(ctx, d, dns, host, typ, tcp)
|
||||
resources, err := resolve(ctx, d, dns, host, typ, network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Println(host, len(resources))
|
||||
for _, ans := range resources {
|
||||
if ans.Header.Type != typ {
|
||||
logrus.Println(host, ans.Header.Type)
|
||||
continue
|
||||
}
|
||||
ns, ok := ans.Body.(*dnsmessage.NSResource)
|
||||
@ -139,7 +136,7 @@ func ResolveNS(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, typ dnsmessage.Type, tcp bool) (ans []dnsmessage.Resource, err error) {
|
||||
func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, typ dnsmessage.Type, network string) (ans []dnsmessage.Resource, err error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
fqdn := host
|
||||
@ -202,7 +199,11 @@ func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host st
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tcp {
|
||||
magicNetwork, err := netproxy.ParseMagicNetwork(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if magicNetwork.Network == "tcp" {
|
||||
// Put DNS request length
|
||||
buf := pool.Get(2 + len(b))
|
||||
defer pool.Put(buf)
|
||||
@ -213,12 +214,7 @@ func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host st
|
||||
|
||||
// Dial and write.
|
||||
cd := &netproxy.ContextDialer{Dialer: d}
|
||||
var c netproxy.Conn
|
||||
if tcp {
|
||||
c, err = cd.DialTcpContext(ctx, dns.String())
|
||||
} else {
|
||||
c, err = cd.DialUdpContext(ctx, dns.String())
|
||||
}
|
||||
c, err := cd.DialContext(ctx, network, dns.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -228,7 +224,7 @@ func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host st
|
||||
return nil, err
|
||||
}
|
||||
ch := make(chan error, 2)
|
||||
if !tcp {
|
||||
if magicNetwork.Network == "udp" {
|
||||
go func() {
|
||||
// Resend every 3 seconds for UDP.
|
||||
for {
|
||||
@ -249,7 +245,7 @@ func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host st
|
||||
go func() {
|
||||
buf := pool.Get(512)
|
||||
defer pool.Put(buf)
|
||||
if tcp {
|
||||
if magicNetwork.Network == "tcp" {
|
||||
// Read DNS response length
|
||||
_, err := io.ReadFull(c, buf[:2])
|
||||
if err != nil {
|
||||
|
@ -22,7 +22,7 @@ type Ip46 struct {
|
||||
Ip6 netip.Addr
|
||||
}
|
||||
|
||||
func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort, host string, tcp bool, race bool) (ipv46 *Ip46, err error) {
|
||||
func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort, host string, network string, race bool) (ipv46 *Ip46, err error) {
|
||||
var log *logrus.Logger
|
||||
if _log := ctx.Value("logger"); _log != nil {
|
||||
log = _log.(*logrus.Logger)
|
||||
@ -49,7 +49,7 @@ func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort
|
||||
}
|
||||
}()
|
||||
var e error
|
||||
addrs4, e = ResolveNetip(ctx4, dialer, dns, host, dnsmessage.TypeA, tcp)
|
||||
addrs4, e = ResolveNetip(ctx4, dialer, dns, host, dnsmessage.TypeA, network)
|
||||
if err != nil && !errors.Is(e, context.Canceled) {
|
||||
err4 = e
|
||||
return
|
||||
@ -67,7 +67,7 @@ func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort
|
||||
}
|
||||
}()
|
||||
var e error
|
||||
addrs6, e = ResolveNetip(ctx6, dialer, dns, host, dnsmessage.TypeAAAA, tcp)
|
||||
addrs6, e = ResolveNetip(ctx6, dialer, dns, host, dnsmessage.TypeAAAA, network)
|
||||
if err != nil && !errors.Is(e, context.Canceled) {
|
||||
err6 = e
|
||||
return
|
||||
|
@ -137,7 +137,7 @@ func ResolveFile(u *url.URL, configDir string) (b []byte, err error) {
|
||||
return bytes.TrimSpace(b), err
|
||||
}
|
||||
|
||||
func ResolveSubscription(log *logrus.Logger, configDir string, subscription string) (tag string, nodes []string, err error) {
|
||||
func ResolveSubscription(log *logrus.Logger, client *http.Client, configDir string, subscription string) (tag string, nodes []string, err error) {
|
||||
/// Get tag.
|
||||
tag, subscription = common.GetTagFromLinkLikePlaintext(subscription)
|
||||
|
||||
@ -160,7 +160,7 @@ func ResolveSubscription(log *logrus.Logger, configDir string, subscription stri
|
||||
goto resolve
|
||||
default:
|
||||
}
|
||||
resp, err = http.Get(subscription)
|
||||
resp, err = client.Get(subscription)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mzz2017/softwind/netproxy"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
@ -221,25 +222,25 @@ func FuzzyDecode(to interface{}, val string) bool {
|
||||
v := reflect.Indirect(reflect.ValueOf(to))
|
||||
switch v.Kind() {
|
||||
case reflect.Int:
|
||||
i, err := strconv.ParseInt(val, 10, strconv.IntSize)
|
||||
i, err := strconv.ParseInt(val, 0, strconv.IntSize)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetInt(i)
|
||||
case reflect.Int8:
|
||||
i, err := strconv.ParseInt(val, 10, 8)
|
||||
i, err := strconv.ParseInt(val, 0, 8)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetInt(i)
|
||||
case reflect.Int16:
|
||||
i, err := strconv.ParseInt(val, 10, 16)
|
||||
i, err := strconv.ParseInt(val, 0, 16)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetInt(i)
|
||||
case reflect.Int32:
|
||||
i, err := strconv.ParseInt(val, 10, 32)
|
||||
i, err := strconv.ParseInt(val, 0, 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -253,38 +254,38 @@ func FuzzyDecode(to interface{}, val string) bool {
|
||||
}
|
||||
v.Set(reflect.ValueOf(duration))
|
||||
default:
|
||||
i, err := strconv.ParseInt(val, 10, 64)
|
||||
i, err := strconv.ParseInt(val, 0, 64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetInt(i)
|
||||
}
|
||||
case reflect.Uint:
|
||||
i, err := strconv.ParseUint(val, 10, strconv.IntSize)
|
||||
i, err := strconv.ParseUint(val, 0, strconv.IntSize)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetUint(i)
|
||||
case reflect.Uint8:
|
||||
i, err := strconv.ParseUint(val, 10, 8)
|
||||
i, err := strconv.ParseUint(val, 0, 8)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetUint(i)
|
||||
case reflect.Uint16:
|
||||
i, err := strconv.ParseUint(val, 10, 16)
|
||||
i, err := strconv.ParseUint(val, 0, 16)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetUint(i)
|
||||
case reflect.Uint32:
|
||||
i, err := strconv.ParseUint(val, 10, 32)
|
||||
i, err := strconv.ParseUint(val, 0, 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
v.SetUint(i)
|
||||
case reflect.Uint64:
|
||||
i, err := strconv.ParseUint(val, 10, 64)
|
||||
i, err := strconv.ParseUint(val, 0, 64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -458,6 +459,17 @@ nextLink:
|
||||
return Deduplicate(defaultIfs), nil
|
||||
}
|
||||
|
||||
func MagicNetwork(network string, mark uint32) string {
|
||||
if mark == 0 {
|
||||
return network
|
||||
} else {
|
||||
return netproxy.MagicNetwork{
|
||||
Network: network,
|
||||
Mark: mark,
|
||||
}.Encode()
|
||||
}
|
||||
}
|
||||
|
||||
func IsValidHttpMethod(method string) bool {
|
||||
switch method {
|
||||
case "GET", "POST", "PUT", "PATCH", "DELETE", "COPY", "HEAD", "OPTIONS", "LINK", "UNLINK", "PURGE", "LOCK", "UNLOCK", "PROPFIND", "CONNECT", "TRACE":
|
||||
|
@ -32,9 +32,10 @@ type Dns struct {
|
||||
}
|
||||
|
||||
type NewOption struct {
|
||||
Logger *logrus.Logger
|
||||
LocationFinder *assets.LocationFinder
|
||||
UpstreamReadyCallback func(dnsUpstream *Upstream) (err error)
|
||||
Logger *logrus.Logger
|
||||
LocationFinder *assets.LocationFinder
|
||||
UpstreamReadyCallback func(dnsUpstream *Upstream) (err error)
|
||||
UpstreamResolverNetwork string
|
||||
}
|
||||
|
||||
func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
|
||||
@ -62,7 +63,8 @@ func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
|
||||
return nil, fmt.Errorf("%w: %v", BadUpstreamFormatError, err)
|
||||
}
|
||||
r := &UpstreamResolver{
|
||||
Raw: u,
|
||||
Raw: u,
|
||||
Network: opt.UpstreamResolverNetwork,
|
||||
FinishInitCallback: func(i int) func(raw *url.URL, upstream *Upstream) (err error) {
|
||||
return func(raw *url.URL, upstream *Upstream) (err error) {
|
||||
if opt != nil && opt.UpstreamReadyCallback != nil {
|
||||
@ -77,6 +79,9 @@ func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
|
||||
return nil
|
||||
}
|
||||
}(i),
|
||||
mu: sync.Mutex{},
|
||||
upstream: nil,
|
||||
init: false,
|
||||
}
|
||||
upstreamName2Id[tag] = uint8(len(s.upstream))
|
||||
s.upstream = append(s.upstream, r)
|
||||
|
@ -72,7 +72,7 @@ type Upstream struct {
|
||||
*netutils.Ip46
|
||||
}
|
||||
|
||||
func NewUpstream(ctx context.Context, upstream *url.URL) (up *Upstream, err error) {
|
||||
func NewUpstream(ctx context.Context, upstream *url.URL, resolverNetwork string) (up *Upstream, err error) {
|
||||
scheme, hostname, port, err := ParseRawUpstream(upstream)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", FormatError, err)
|
||||
@ -88,7 +88,7 @@ func NewUpstream(ctx context.Context, upstream *url.URL) (up *Upstream, err erro
|
||||
}
|
||||
}()
|
||||
|
||||
ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, hostname, false, false)
|
||||
ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, hostname, resolverNetwork, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve dns_upstream: %w", err)
|
||||
}
|
||||
@ -131,7 +131,8 @@ func (u *Upstream) String() string {
|
||||
}
|
||||
|
||||
type UpstreamResolver struct {
|
||||
Raw *url.URL
|
||||
Raw *url.URL
|
||||
Network string
|
||||
// FinishInitCallback may be invoked again if err is not nil
|
||||
FinishInitCallback func(raw *url.URL, upstream *Upstream) (err error)
|
||||
mu sync.Mutex
|
||||
@ -154,7 +155,7 @@ func (u *UpstreamResolver) GetUpstream() (_ *Upstream, err error) {
|
||||
}()
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
|
||||
defer cancel()
|
||||
if u.upstream, err = NewUpstream(ctx, u.Raw); err != nil {
|
||||
if u.upstream, err = NewUpstream(ctx, u.Raw, u.Network); err != nil {
|
||||
return nil, fmt.Errorf("failed to init dns upstream: %w", err)
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/daeuniverse/dae/common"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
@ -121,7 +122,7 @@ type TcpCheckOption struct {
|
||||
Method string
|
||||
}
|
||||
|
||||
func ParseTcpCheckOption(ctx context.Context, rawURL []string, method string) (opt *TcpCheckOption, err error) {
|
||||
func ParseTcpCheckOption(ctx context.Context, rawURL []string, method string, resolverNetwork string) (opt *TcpCheckOption, err error) {
|
||||
if method == "" {
|
||||
method = http.MethodGet
|
||||
}
|
||||
@ -146,7 +147,7 @@ func ParseTcpCheckOption(ctx context.Context, rawURL []string, method string) (o
|
||||
if len(rawURL) > 1 {
|
||||
ip46 = parseIp46FromList(rawURL[1:])
|
||||
} else {
|
||||
ip46, err = netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, u.Hostname(), false, false)
|
||||
ip46, err = netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, u.Hostname(), resolverNetwork, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -164,7 +165,7 @@ type CheckDnsOption struct {
|
||||
*netutils.Ip46
|
||||
}
|
||||
|
||||
func ParseCheckDnsOption(ctx context.Context, dnsHostPort []string) (opt *CheckDnsOption, err error) {
|
||||
func ParseCheckDnsOption(ctx context.Context, dnsHostPort []string, resolverNetwork string) (opt *CheckDnsOption, err error) {
|
||||
systemDns, err := netutils.SystemDns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -191,7 +192,7 @@ func ParseCheckDnsOption(ctx context.Context, dnsHostPort []string) (opt *CheckD
|
||||
if len(dnsHostPort) > 1 {
|
||||
ip46 = parseIp46FromList(dnsHostPort[1:])
|
||||
} else {
|
||||
ip46, err = netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, host, false, false)
|
||||
ip46, err = netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, host, resolverNetwork, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -204,11 +205,12 @@ func ParseCheckDnsOption(ctx context.Context, dnsHostPort []string) (opt *CheckD
|
||||
}
|
||||
|
||||
type TcpCheckOptionRaw struct {
|
||||
opt *TcpCheckOption
|
||||
mu sync.Mutex
|
||||
Log *logrus.Logger
|
||||
Raw []string
|
||||
Method string
|
||||
opt *TcpCheckOption
|
||||
mu sync.Mutex
|
||||
Log *logrus.Logger
|
||||
Raw []string
|
||||
ResolverNetwork string
|
||||
Method string
|
||||
}
|
||||
|
||||
func (c *TcpCheckOptionRaw) Option() (opt *TcpCheckOption, err error) {
|
||||
@ -218,7 +220,7 @@ func (c *TcpCheckOptionRaw) Option() (opt *TcpCheckOption, err error) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
|
||||
defer cancel()
|
||||
ctx = context.WithValue(ctx, "logger", c.Log)
|
||||
tcpCheckOption, err := ParseTcpCheckOption(ctx, c.Raw, c.Method)
|
||||
tcpCheckOption, err := ParseTcpCheckOption(ctx, c.Raw, c.Method, c.ResolverNetwork)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse tcp_check_url: %w", err)
|
||||
}
|
||||
@ -228,9 +230,10 @@ func (c *TcpCheckOptionRaw) Option() (opt *TcpCheckOption, err error) {
|
||||
}
|
||||
|
||||
type CheckDnsOptionRaw struct {
|
||||
opt *CheckDnsOption
|
||||
mu sync.Mutex
|
||||
Raw []string
|
||||
opt *CheckDnsOption
|
||||
mu sync.Mutex
|
||||
Raw []string
|
||||
ResolverNetwork string
|
||||
}
|
||||
|
||||
func (c *CheckDnsOptionRaw) Option() (opt *CheckDnsOption, err error) {
|
||||
@ -239,7 +242,7 @@ func (c *CheckDnsOptionRaw) Option() (opt *CheckDnsOption, err error) {
|
||||
if c.opt == nil {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
|
||||
defer cancel()
|
||||
udpCheckOption, err := ParseCheckDnsOption(ctx, c.Raw)
|
||||
udpCheckOption, err := ParseCheckDnsOption(ctx, c.Raw, c.ResolverNetwork)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse tcp_check_url: %w", err)
|
||||
}
|
||||
@ -266,6 +269,10 @@ func (d *Dialer) ActivateCheck() {
|
||||
func (d *Dialer) aliveBackground() {
|
||||
timeout := 10 * time.Second
|
||||
cycle := d.CheckInterval
|
||||
var tcpSomark uint32
|
||||
if network, err := netproxy.ParseMagicNetwork(d.TcpCheckOptionRaw.ResolverNetwork); err == nil {
|
||||
tcpSomark = network.Mark
|
||||
}
|
||||
tcp4CheckOpt := &CheckOption{
|
||||
networkType: &NetworkType{
|
||||
L4Proto: consts.L4ProtoStr_TCP,
|
||||
@ -285,7 +292,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.HttpCheck(ctx, opt.Url, opt.Ip4, opt.Method)
|
||||
return d.HttpCheck(ctx, opt.Url, opt.Ip4, opt.Method, tcpSomark)
|
||||
},
|
||||
}
|
||||
tcp6CheckOpt := &CheckOption{
|
||||
@ -307,7 +314,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.HttpCheck(ctx, opt.Url, opt.Ip6, opt.Method)
|
||||
return d.HttpCheck(ctx, opt.Url, opt.Ip6, opt.Method, tcpSomark)
|
||||
},
|
||||
}
|
||||
tcp4CheckDnsOpt := &CheckOption{
|
||||
@ -329,7 +336,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip4, opt.DnsPort), true)
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip4, opt.DnsPort), d.CheckDnsOptionRaw.ResolverNetwork)
|
||||
},
|
||||
}
|
||||
tcp6CheckDnsOpt := &CheckOption{
|
||||
@ -351,7 +358,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip6, opt.DnsPort), true)
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip6, opt.DnsPort), d.CheckDnsOptionRaw.ResolverNetwork)
|
||||
},
|
||||
}
|
||||
udp4CheckDnsOpt := &CheckOption{
|
||||
@ -372,7 +379,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip4, opt.DnsPort), false)
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip4, opt.DnsPort), d.CheckDnsOptionRaw.ResolverNetwork)
|
||||
},
|
||||
}
|
||||
udp6CheckDnsOpt := &CheckOption{
|
||||
@ -393,7 +400,7 @@ func (d *Dialer) aliveBackground() {
|
||||
}).Debugln("Skip check due to no DNS record.")
|
||||
return false, nil
|
||||
}
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip6, opt.DnsPort), false)
|
||||
return d.DnsCheck(ctx, netip.AddrPortFrom(opt.Ip6, opt.DnsPort), d.CheckDnsOptionRaw.ResolverNetwork)
|
||||
},
|
||||
}
|
||||
var CheckOpts = []*CheckOption{
|
||||
@ -535,7 +542,7 @@ func (d *Dialer) Check(timeout time.Duration,
|
||||
return ok, err
|
||||
}
|
||||
|
||||
func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr, method string) (ok bool, err error) {
|
||||
func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr, method string, soMark uint32) (ok bool, err error) {
|
||||
// HTTP(S) check.
|
||||
if method == "" {
|
||||
method = http.MethodGet
|
||||
@ -545,7 +552,7 @@ func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr,
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) {
|
||||
// Force to dial "ip".
|
||||
conn, err := cd.DialTcpContext(ctx, net.JoinHostPort(ip.String(), u.Port()))
|
||||
conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", soMark), net.JoinHostPort(ip.String(), u.Port()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -584,8 +591,8 @@ func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dialer) DnsCheck(ctx context.Context, dns netip.AddrPort, tcp bool) (ok bool, err error) {
|
||||
addrs, err := netutils.ResolveNetip(ctx, d, dns, consts.UdpCheckLookupHost, dnsmessage.TypeA, tcp)
|
||||
func (d *Dialer) DnsCheck(ctx context.Context, dns netip.AddrPort, network string) (ok bool, err error) {
|
||||
addrs, err := netutils.ResolveNetip(ctx, d, dns, consts.UdpCheckLookupHost, dnsmessage.TypeA, network)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package trojan
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/daeuniverse/dae/component/outbound/transport/tls"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@ -9,7 +10,6 @@ import (
|
||||
|
||||
"github.com/daeuniverse/dae/common"
|
||||
"github.com/daeuniverse/dae/component/outbound/dialer"
|
||||
"github.com/daeuniverse/dae/component/outbound/transport/tls"
|
||||
"github.com/daeuniverse/dae/component/outbound/transport/ws"
|
||||
"github.com/mzz2017/softwind/netproxy"
|
||||
"github.com/mzz2017/softwind/protocol"
|
||||
|
@ -63,38 +63,28 @@ func (s *SimpleObfs) Dial(network, addr string) (c netproxy.Conn, err error) {
|
||||
}
|
||||
switch magicNetwork.Network {
|
||||
case "tcp":
|
||||
return s.DialTcp(addr)
|
||||
rc, err := s.dialer.Dial(network, s.addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[simpleobfs]: dial to %s: %w", s.addr, err)
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(s.addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.host != "" {
|
||||
host = s.host
|
||||
}
|
||||
switch s.obfstype {
|
||||
case HTTP:
|
||||
c = NewHTTPObfs(rc, host, port, s.path)
|
||||
case TLS:
|
||||
c = NewTLSObfs(rc, host)
|
||||
}
|
||||
return c, err
|
||||
case "udp":
|
||||
return s.DialUdp(addr)
|
||||
return nil, fmt.Errorf("%w: simpleobfs+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: %v", netproxy.UnsupportedTunnelTypeError, network)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleObfs) DialUdp(addr string) (conn netproxy.PacketConn, err error) {
|
||||
return nil, fmt.Errorf("%w: simpleobfs+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
}
|
||||
|
||||
// DialTcp connects to the address addr on the network net via the proxy.
|
||||
func (s *SimpleObfs) DialTcp(addr string) (c netproxy.Conn, err error) {
|
||||
|
||||
rc, err := s.dialer.DialTcp(s.addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[simpleobfs]: dial to %s: %w", s.addr, err)
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(s.addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.host != "" {
|
||||
host = s.host
|
||||
}
|
||||
switch s.obfstype {
|
||||
case HTTP:
|
||||
c = NewHTTPObfs(rc, host, port, s.path)
|
||||
case TLS:
|
||||
c = NewTLSObfs(rc, host)
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
@ -61,55 +61,47 @@ func (s *Tls) Dial(network, addr string) (c netproxy.Conn, err error) {
|
||||
}
|
||||
switch magicNetwork.Network {
|
||||
case "tcp":
|
||||
return s.DialTcp(addr)
|
||||
rc, err := s.dialer.Dial(network, addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[Tls]: dial to %s: %w", s.addr, err)
|
||||
}
|
||||
|
||||
var tlsConn interface {
|
||||
netproxy.Conn
|
||||
Handshake() error
|
||||
}
|
||||
|
||||
switch s.tlsImplentation {
|
||||
case "tls":
|
||||
tlsConn = tls.Client(&netproxy.FakeNetConn{
|
||||
Conn: rc,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, s.tlsConfig)
|
||||
|
||||
case "utls":
|
||||
clientHelloID, err := nameToUtlsClientHelloID(s.utlsImitate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConn = utls.UClient(&netproxy.FakeNetConn{
|
||||
Conn: rc,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, uTLSConfigFromTLSConfig(s.tlsConfig), *clientHelloID)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown tls implementation: %v", s.tlsImplentation)
|
||||
}
|
||||
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tlsConn, err
|
||||
case "udp":
|
||||
return s.DialUdp(addr)
|
||||
return nil, fmt.Errorf("%w: tls+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: %v", netproxy.UnsupportedTunnelTypeError, network)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Tls) DialUdp(addr string) (conn netproxy.PacketConn, err error) {
|
||||
return nil, fmt.Errorf("%w: tls+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
}
|
||||
|
||||
func (s *Tls) DialTcp(addr string) (conn netproxy.Conn, err error) {
|
||||
rc, err := s.dialer.DialTcp(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[Tls]: dial to %s: %w", s.addr, err)
|
||||
}
|
||||
|
||||
var tlsConn interface {
|
||||
netproxy.Conn
|
||||
Handshake() error
|
||||
}
|
||||
|
||||
switch s.tlsImplentation {
|
||||
case "tls":
|
||||
tlsConn = tls.Client(&netproxy.FakeNetConn{
|
||||
Conn: rc,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, s.tlsConfig)
|
||||
|
||||
case "utls":
|
||||
clientHelloID, err := nameToUtlsClientHelloID(s.utlsImitate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConn = utls.UClient(&netproxy.FakeNetConn{
|
||||
Conn: rc,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, uTLSConfigFromTLSConfig(s.tlsConfig), *clientHelloID)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown tls implementation: %v", s.tlsImplentation)
|
||||
}
|
||||
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tlsConn, err
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ import (
|
||||
|
||||
// Ws is a base Ws struct
|
||||
type Ws struct {
|
||||
dialer netproxy.Dialer
|
||||
wsAddr string
|
||||
header http.Header
|
||||
wsDialer *websocket.Dialer
|
||||
dialer netproxy.Dialer
|
||||
wsAddr string
|
||||
header http.Header
|
||||
tlsClientConfig *tls.Config
|
||||
}
|
||||
|
||||
// NewWs returns a Ws infra.
|
||||
@ -43,23 +43,9 @@ func NewWs(s string, d netproxy.Dialer) (*Ws, error) {
|
||||
Host: u.Host,
|
||||
}
|
||||
t.wsAddr = wsUrl.String() + u.Path
|
||||
t.wsDialer = &websocket.Dialer{
|
||||
NetDial: func(network, addr string) (net.Conn, error) {
|
||||
c, err := d.DialTcp(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netproxy.FakeNetConn{
|
||||
Conn: c,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, nil
|
||||
},
|
||||
//Subprotocols: []string{"binary"},
|
||||
}
|
||||
if u.Scheme == "wss" {
|
||||
skipVerify, _ := strconv.ParseBool(u.Query().Get("allowInsecure"))
|
||||
t.wsDialer.TLSClientConfig = &tls.Config{
|
||||
t.tlsClientConfig = &tls.Config{
|
||||
ServerName: u.Query().Get("sni"),
|
||||
InsecureSkipVerify: skipVerify,
|
||||
}
|
||||
@ -74,23 +60,28 @@ func (s *Ws) Dial(network, addr string) (c netproxy.Conn, err error) {
|
||||
}
|
||||
switch magicNetwork.Network {
|
||||
case "tcp":
|
||||
return s.DialTcp(addr)
|
||||
wsDialer := &websocket.Dialer{
|
||||
NetDial: func(_, addr string) (net.Conn, error) {
|
||||
c, err := s.dialer.Dial(network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netproxy.FakeNetConn{
|
||||
Conn: c,
|
||||
LAddr: nil,
|
||||
RAddr: nil,
|
||||
}, nil
|
||||
},
|
||||
//Subprotocols: []string{"binary"},
|
||||
}
|
||||
rc, _, err := wsDialer.Dial(s.wsAddr, s.header)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[Ws]: dial to %s: %w", s.wsAddr, err)
|
||||
}
|
||||
return newConn(rc), err
|
||||
case "udp":
|
||||
return s.DialUdp(addr)
|
||||
return nil, fmt.Errorf("%w: ws+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: %v", netproxy.UnsupportedTunnelTypeError, network)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Ws) DialUdp(addr string) (netproxy.PacketConn, error) {
|
||||
return nil, fmt.Errorf("%w: ws+udp", netproxy.UnsupportedTunnelTypeError)
|
||||
}
|
||||
|
||||
// DialTcp connects to the address addr on the network net via the infra.
|
||||
func (s *Ws) DialTcp(addr string) (netproxy.Conn, error) {
|
||||
rc, _, err := s.wsDialer.Dial(s.wsAddr, s.header)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[Ws]: dial to %s: %w", s.wsAddr, err)
|
||||
}
|
||||
return newConn(rc), err
|
||||
}
|
||||
|
@ -14,8 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type Global struct {
|
||||
TproxyPort uint16 `mapstructure:"tproxy_port" default:"12345"`
|
||||
LogLevel string `mapstructure:"log_level" default:"info"`
|
||||
TproxyPort uint16 `mapstructure:"tproxy_port" default:"12345"`
|
||||
TproxyPortProtect bool `mapstructure:"tproxy_port_protect" default:"true"`
|
||||
SoMarkFromDae uint32 `mapstructure:"so_mark_from_dae"`
|
||||
LogLevel string `mapstructure:"log_level" default:"info"`
|
||||
// We use DirectTcpCheckUrl to check (tcp)*(ipv4/ipv6) connectivity for direct.
|
||||
//DirectTcpCheckUrl string `mapstructure:"direct_tcp_check_url" default:"http://www.qualcomm.cn/generate_204"`
|
||||
TcpCheckUrl []string `mapstructure:"tcp_check_url" default:"http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111"`
|
||||
|
@ -36,6 +36,8 @@ var SectionDescription = map[string]Desc{
|
||||
|
||||
var GlobalDesc = Desc{
|
||||
"tproxy_port": "tproxy port to listen on. It is NOT a HTTP/SOCKS port, and is just used by eBPF program.\nIn normal case, you do not need to use it.",
|
||||
"tproxy_port_protect": "Set it true to protect tproxy port from unsolicited traffic. Set it false to allow users to use self-managed iptables tproxy rules.",
|
||||
"so_mark_from_dae": "If not zero, traffic sent from dae will be set SO_MARK. It is useful to avoid traffic loop with iptables tproxy rules.",
|
||||
"log_level": "Log level: error, warn, info, debug, trace.",
|
||||
"tcp_check_url": "Node connectivity check.\nHost of URL should have both IPv4 and IPv6 if you have double stack in local.\nConsidering traffic consumption, it is recommended to choose a site with anycast IP and less response.",
|
||||
"tcp_check_http_method": "The HTTP request method to `tcp_check_url`. Use 'CONNECT' by default because some server implementations bypass accounting for this kind of traffic.",
|
||||
|
@ -67,7 +67,9 @@ type ControlPlane struct {
|
||||
wanInterface []string
|
||||
lanInterface []string
|
||||
|
||||
sniffingTimeout time.Duration
|
||||
sniffingTimeout time.Duration
|
||||
tproxyPortProtect bool
|
||||
soMarkFromDae uint32
|
||||
}
|
||||
|
||||
func NewControlPlane(
|
||||
@ -226,9 +228,17 @@ func NewControlPlane(
|
||||
log.Warnln("AllowInsecure is enabled, but it is not recommended. Please make sure you have to turn it on.")
|
||||
}
|
||||
option := &dialer.GlobalOption{
|
||||
Log: log,
|
||||
TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, Method: global.TcpCheckHttpMethod},
|
||||
CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns},
|
||||
Log: log,
|
||||
TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{
|
||||
Raw: global.TcpCheckUrl,
|
||||
Log: log,
|
||||
ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae),
|
||||
Method: global.TcpCheckHttpMethod,
|
||||
},
|
||||
CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{
|
||||
Raw: global.UdpCheckDns,
|
||||
ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae),
|
||||
},
|
||||
CheckInterval: global.CheckInterval,
|
||||
CheckTolerance: global.CheckTolerance,
|
||||
CheckDnsTcp: true,
|
||||
@ -337,23 +347,25 @@ func NewControlPlane(
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
plane := &ControlPlane{
|
||||
log: log,
|
||||
core: core,
|
||||
deferFuncs: deferFuncs,
|
||||
listenIp: "0.0.0.0",
|
||||
outbounds: outbounds,
|
||||
dnsController: nil,
|
||||
onceNetworkReady: sync.Once{},
|
||||
dialMode: dialMode,
|
||||
routingMatcher: routingMatcher,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
ready: make(chan struct{}),
|
||||
muRealDomainSet: sync.Mutex{},
|
||||
realDomainSet: bloom.NewWithEstimates(2048, 0.001),
|
||||
lanInterface: global.LanInterface,
|
||||
wanInterface: global.WanInterface,
|
||||
sniffingTimeout: sniffingTimeout,
|
||||
log: log,
|
||||
core: core,
|
||||
deferFuncs: deferFuncs,
|
||||
listenIp: "0.0.0.0",
|
||||
outbounds: outbounds,
|
||||
dnsController: nil,
|
||||
onceNetworkReady: sync.Once{},
|
||||
dialMode: dialMode,
|
||||
routingMatcher: routingMatcher,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
ready: make(chan struct{}),
|
||||
muRealDomainSet: sync.Mutex{},
|
||||
realDomainSet: bloom.NewWithEstimates(2048, 0.001),
|
||||
lanInterface: global.LanInterface,
|
||||
wanInterface: global.WanInterface,
|
||||
sniffingTimeout: sniffingTimeout,
|
||||
tproxyPortProtect: global.TproxyPortProtect,
|
||||
soMarkFromDae: global.SoMarkFromDae,
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@ -363,9 +375,10 @@ func NewControlPlane(
|
||||
|
||||
/// DNS upstream.
|
||||
dnsUpstream, err := dns.New(dnsConfig, &dns.NewOption{
|
||||
Logger: log,
|
||||
LocationFinder: locationFinder,
|
||||
UpstreamReadyCallback: plane.dnsUpstreamReadyCallback,
|
||||
Logger: log,
|
||||
LocationFinder: locationFinder,
|
||||
UpstreamReadyCallback: plane.dnsUpstreamReadyCallback,
|
||||
UpstreamResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -559,7 +572,7 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip
|
||||
// TODO: use DNS controller and re-route by control plane.
|
||||
systemDns, err := netutils.SystemDns()
|
||||
if err == nil {
|
||||
if ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, domain, false, true); err == nil && (ip46.Ip4.IsValid() || ip46.Ip6.IsValid()) {
|
||||
if ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, domain, common.MagicNetwork("udp", c.soMarkFromDae), true); err == nil && (ip46.Ip4.IsValid() || ip46.Ip6.IsValid()) {
|
||||
// Has A/AAAA records. It is a real domain.
|
||||
dialMode = consts.DialMode_Domain
|
||||
// Add it to real-domain set.
|
||||
@ -717,8 +730,21 @@ func (c *ControlPlane) Serve(readyChan chan<- bool, listener *Listener) (err err
|
||||
lastErr := err
|
||||
addrHdr, dataOffset, err := ParseAddrHdr(data)
|
||||
if err != nil {
|
||||
c.log.Warnf("No AddrPort presented: %v, %v", lastErr, err)
|
||||
return
|
||||
if c.tproxyPortProtect {
|
||||
c.log.Warnf("No AddrPort presented: %v, %v", lastErr, err)
|
||||
return
|
||||
} else {
|
||||
routingResult = &bpfRoutingResult{
|
||||
Mark: 0,
|
||||
Must: 0,
|
||||
Mac: [6]uint8{},
|
||||
Outbound: uint8(consts.OutboundControlPlaneRouting),
|
||||
Pname: [16]uint8{},
|
||||
Pid: 0,
|
||||
}
|
||||
realDst = pktDst
|
||||
goto destRetrieved
|
||||
}
|
||||
}
|
||||
n := copy(data, data[dataOffset:])
|
||||
data = data[:n]
|
||||
@ -731,6 +757,7 @@ func (c *ControlPlane) Serve(readyChan chan<- bool, listener *Listener) (err err
|
||||
} else {
|
||||
realDst = pktDst
|
||||
}
|
||||
destRetrieved:
|
||||
if e := c.handlePkt(udpConn, data, common.ConvergeAddrPort(src), common.ConvergeAddrPort(pktDst), common.ConvergeAddrPort(realDst), routingResult); e != nil {
|
||||
c.log.Warnln("handlePkt:", e)
|
||||
}
|
||||
@ -814,6 +841,9 @@ func (c *ControlPlane) chooseBestDnsDialer(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mark == 0 {
|
||||
mark = c.soMarkFromDae
|
||||
}
|
||||
if int(outboundIndex) >= len(c.outbounds) {
|
||||
return nil, fmt.Errorf("bad outbound index: %v", outboundIndex)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/daeuniverse/dae/common"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
@ -645,7 +646,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte
|
||||
|
||||
// TODO: connection pool.
|
||||
conn, err = dialArgument.bestDialer.Dial(
|
||||
MagicNetwork("udp", dialArgument.mark),
|
||||
common.MagicNetwork("udp", dialArgument.mark),
|
||||
dialArgument.bestTarget.String(),
|
||||
)
|
||||
if err != nil {
|
||||
@ -707,7 +708,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte
|
||||
case consts.L4ProtoStr_TCP:
|
||||
// We can block here because we are in a coroutine.
|
||||
|
||||
conn, err = dialArgument.bestDialer.Dial(MagicNetwork("tcp", dialArgument.mark), dialArgument.bestTarget.String())
|
||||
conn, err = dialArgument.bestDialer.Dial(common.MagicNetwork("tcp", dialArgument.mark), dialArgument.bestTarget.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial proxy to tcp: %w", err)
|
||||
}
|
||||
|
@ -64,6 +64,7 @@
|
||||
#define IS_LAN 1
|
||||
|
||||
#define TPROXY_MARK 0x8000000
|
||||
#define RECOGNIZE 0x2017
|
||||
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
|
||||
@ -139,6 +140,7 @@ struct routing_result {
|
||||
struct dst_routing_result {
|
||||
__be32 ip[4];
|
||||
__be16 port;
|
||||
__u16 recognize;
|
||||
struct routing_result routing_result;
|
||||
};
|
||||
|
||||
@ -1751,6 +1753,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
||||
__builtin_memset(&new_hdr, 0, sizeof(new_hdr));
|
||||
__builtin_memcpy(new_hdr.ip, &tuples.dip, IPV6_BYTE_LENGTH);
|
||||
new_hdr.port = udph.dest;
|
||||
new_hdr.recognize = RECOGNIZE;
|
||||
new_hdr.routing_result.outbound = s64_ret;
|
||||
new_hdr.routing_result.mark = s64_ret >> 8;
|
||||
new_hdr.routing_result.must = (s64_ret >> 40) & 1;
|
||||
|
@ -50,7 +50,19 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
||||
Ip: struct{ U6Addr8 [16]uint8 }{U6Addr8: ip6},
|
||||
Port: common.Htons(src.Port()),
|
||||
}, &value); e != nil {
|
||||
return fmt.Errorf("failed to retrieve target info %v: %v, %v", src.String(), err, e)
|
||||
if c.tproxyPortProtect {
|
||||
return fmt.Errorf("failed to retrieve target info %v: %v, %v", src.String(), err, e)
|
||||
} else {
|
||||
routingResult = &bpfRoutingResult{
|
||||
Mark: 0,
|
||||
Must: 0,
|
||||
Mac: [6]uint8{},
|
||||
Outbound: uint8(consts.OutboundControlPlaneRouting),
|
||||
Pname: [16]uint8{},
|
||||
Pid: 0,
|
||||
}
|
||||
goto destRetrieved
|
||||
}
|
||||
}
|
||||
routingResult = &value.RoutingResult
|
||||
|
||||
@ -60,6 +72,7 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
||||
}
|
||||
dst = netip.AddrPortFrom(dstAddr, common.Htons(value.Port))
|
||||
}
|
||||
destRetrieved:
|
||||
src = common.ConvergeAddrPort(src)
|
||||
dst = common.ConvergeAddrPort(dst)
|
||||
|
||||
@ -92,6 +105,9 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
||||
dialTarget, _ = c.ChooseDialTarget(outboundIndex, dst, domain)
|
||||
default:
|
||||
}
|
||||
if routingResult.Mark == 0 {
|
||||
routingResult.Mark = c.soMarkFromDae
|
||||
}
|
||||
// TODO: Set-up ip to domain mapping and show domain if possible.
|
||||
if outboundIndex < 0 || int(outboundIndex) >= len(c.outbounds) {
|
||||
return fmt.Errorf("outbound id from bpf is out of range: %v not in [0, %v]", outboundIndex, len(c.outbounds)-1)
|
||||
@ -122,7 +138,7 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
|
||||
}
|
||||
|
||||
// Dial and relay.
|
||||
rConn, err := d.Dial(MagicNetwork("tcp", routingResult.Mark), dialTarget)
|
||||
rConn, err := d.Dial(common.MagicNetwork("tcp", routingResult.Mark), dialTarget)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial %v: %w", dst, err)
|
||||
}
|
||||
|
@ -48,6 +48,9 @@ func ParseAddrHdr(data []byte) (hdr *bpfDstRoutingResult, dataOffset int, err er
|
||||
return nil, 0, fmt.Errorf("data is too short to parse AddrHdr")
|
||||
}
|
||||
_hdr := *(*bpfDstRoutingResult)(unsafe.Pointer(&data[0]))
|
||||
if _hdr.Recognize != consts.Recognize {
|
||||
return nil, 0, fmt.Errorf("bad recognize")
|
||||
}
|
||||
_hdr.Port = common.Ntohs(_hdr.Port)
|
||||
return &_hdr, dataOffset, nil
|
||||
}
|
||||
@ -173,6 +176,9 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
|
||||
dialTarget, _ = c.ChooseDialTarget(outboundIndex, realDst, domain)
|
||||
default:
|
||||
}
|
||||
if routingResult.Mark == 0 {
|
||||
routingResult.Mark = c.soMarkFromDae
|
||||
}
|
||||
if isDns {
|
||||
return c.dnsController.Handle_(dnsMessage, &udpRequest{
|
||||
lanWanFlag: lanWanFlag,
|
||||
@ -226,7 +232,7 @@ getNew:
|
||||
},
|
||||
NatTimeout: natTimeout,
|
||||
Dialer: dialerForNew,
|
||||
Network: MagicNetwork("udp", routingResult.Mark),
|
||||
Network: common.MagicNetwork("udp", routingResult.Mark),
|
||||
Target: dialTarget,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
|
||||
"github.com/daeuniverse/dae/common"
|
||||
"github.com/daeuniverse/dae/common/consts"
|
||||
"github.com/mzz2017/softwind/netproxy"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@ -160,17 +159,6 @@ func SetSendRedirects(ifname string, val string) {
|
||||
_ = setSendRedirects(ifname, consts.IpVersionStr_4, val)
|
||||
}
|
||||
|
||||
func MagicNetwork(network string, mark uint32) string {
|
||||
if mark == 0 {
|
||||
return network
|
||||
} else {
|
||||
return netproxy.MagicNetwork{
|
||||
Network: network,
|
||||
Mark: mark,
|
||||
}.Encode()
|
||||
}
|
||||
}
|
||||
|
||||
func ProcessName2String(pname []uint8) string {
|
||||
return string(bytes.TrimRight(pname[:], string([]byte{0})))
|
||||
}
|
||||
|
@ -90,6 +90,18 @@ sudo systemctl start dae
|
||||
sudo systemctl enable dae
|
||||
```
|
||||
|
||||
### Gentoo Linux
|
||||
|
||||
dae has been released on [gentoo-zh](https://github.com/microcai/gentoo-zh)
|
||||
|
||||
use `app-eselect/eselect-repository` to enable this overlay:
|
||||
|
||||
```shell
|
||||
eselect repository enable gentoo-zh
|
||||
emaint sync -r gentoo-zh
|
||||
emerge -a net-proxy/dae
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
We provide a hacky way to run dae on your macOS. See [run on macOS](run-on-macos.md).
|
||||
|
@ -86,6 +86,16 @@ sudo systemctl start dae
|
||||
sudo systemctl enable dae
|
||||
```
|
||||
|
||||
### Gentoo Linux
|
||||
|
||||
dae 已发布于 [gentoo-zh](https://github.com/microcai/gentoo-zh),可以使用 `app-eselect/eselect-repository` 启用此 overlay:
|
||||
|
||||
```shell
|
||||
eselect repository enable gentoo-zh
|
||||
emaint sync -r gentoo-zh
|
||||
emerge -a net-proxy/dae
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
我们提供了一种比较 hacky 的方式在 macOS 上运行 dae,见 [run on macOS](run-on-macos.md)。
|
||||
|
@ -84,10 +84,8 @@ domain(geosite:geolocation-!cn) &&
|
||||
domain(ext:"yourdatfile.dat:yourtag")->direct
|
||||
dip(ext:"yourdatfile.dat:yourtag")->direct
|
||||
|
||||
### Mark for direct/must_direct outbound
|
||||
# Mark is useful when you want to redirect traffic to specific interface (such as wireguard) or other advanced uses.
|
||||
# Traffic from LAN will not be forwarded by dae to archive higher performance if lan_nat_direct is off (you can set it
|
||||
# off only if you are sure dae is on a bridge device).
|
||||
### Set fwmark
|
||||
# Mark is useful when you want to redirect traffic to specific interface (such as wireguard) or for other advanced uses.
|
||||
|
||||
# An example of redirecting Disney traffic to wg0 is given here.
|
||||
# You need set ip rule and ip table like this:
|
||||
|
@ -5,6 +5,14 @@ global {
|
||||
# In normal case, you do not need to use it.
|
||||
tproxy_port: 12345
|
||||
|
||||
# Set it true to protect tproxy port from unsolicited traffic. Set it false to allow users to use self-managed
|
||||
# iptables tproxy rules.
|
||||
tproxy_port_protect: true
|
||||
|
||||
# If not zero, traffic sent from dae will be set SO_MARK. It is useful to avoid traffic loop with iptables tproxy
|
||||
# rules.
|
||||
so_mark_from_dae: 0
|
||||
|
||||
# Log level: error, warn, info, debug, trace.
|
||||
log_level: info
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -11,7 +11,7 @@ require (
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/mzz2017/softwind v0.0.0-20230501115403-98d9a7116d72
|
||||
github.com/mzz2017/softwind v0.0.0-20230530150701-b78490a65b9f
|
||||
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
|
||||
github.com/safchain/ethtool v0.0.0-20230116090318-67cc41908669
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
|
4
go.sum
4
go.sum
@ -78,8 +78,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/mzz2017/disk-bloom v1.0.1 h1:rEF9MiXd9qMW3ibRpqcerLXULoTgRlM21yqqJl1B90M=
|
||||
github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI=
|
||||
github.com/mzz2017/softwind v0.0.0-20230501115403-98d9a7116d72 h1:h6xMzLtz5pW24T8E+GSdNJ9lRYh5cDpgL85d5c3/om0=
|
||||
github.com/mzz2017/softwind v0.0.0-20230501115403-98d9a7116d72/go.mod h1:V8GFOtdpTgzCJtCVXRqjmdDsY+PIhCCx4JpD0zq8Z7I=
|
||||
github.com/mzz2017/softwind v0.0.0-20230530150701-b78490a65b9f h1:wrOAYscIeug7HZHS7LoOY+hBs4qk48twIxormhOD/Rc=
|
||||
github.com/mzz2017/softwind v0.0.0-20230530150701-b78490a65b9f/go.mod h1:1hn+ZsP9fLm17yEx0jyqxHkIKm5u2gBXVGIrnKsE1fY=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
|
@ -86,10 +86,18 @@ func (w *Walker) parseFunctionPrototype(ctx *dae_config.FunctionPrototypeContext
|
||||
children := ctx.GetChildren()
|
||||
not := false
|
||||
offset := 0
|
||||
if len(children) == 0 {
|
||||
w.ReportError(ctx, ErrorType_Unsupported, "bad function prototype expression")
|
||||
return nil
|
||||
}
|
||||
if children[0].(*antlr.TerminalNodeImpl).GetText() == "!" {
|
||||
offset++
|
||||
not = true
|
||||
}
|
||||
if len(children) <= offset+2 {
|
||||
w.ReportError(ctx, ErrorType_Unsupported, "bad function prototype expression")
|
||||
return nil
|
||||
}
|
||||
funcName := children[offset+0].(*antlr.TerminalNodeImpl).GetText()
|
||||
paramList := children[offset+2].(*dae_config.OptParameterListContext)
|
||||
children = paramList.GetChildren()
|
||||
@ -151,6 +159,10 @@ func (p *literalExpressionParser) Parse(ctx *dae_config.LiteralExpressionContext
|
||||
|
||||
func (w *Walker) parseDeclaration(ctx dae_config.IDeclarationContext) *Param {
|
||||
children := ctx.GetChildren()
|
||||
if len(children) < 3 {
|
||||
w.ReportError(ctx, ErrorType_Unsupported, "bad declaration expression")
|
||||
return nil
|
||||
}
|
||||
key := children[0].(*antlr.TerminalNodeImpl).GetText()
|
||||
switch valueCtx := children[2].(type) {
|
||||
case *dae_config.LiteralExpressionContext:
|
||||
@ -202,6 +214,10 @@ func (w *Walker) parseFunctionPrototypeExpression(ctx dae_config.IFunctionProtot
|
||||
|
||||
func (w *Walker) parseRoutingRule(ctx dae_config.IRoutingRuleContext) *RoutingRule {
|
||||
children := ctx.GetChildren()
|
||||
if len(children) < 3 {
|
||||
w.ReportError(ctx, ErrorType_Unsupported, "bad routing rule expression")
|
||||
return nil
|
||||
}
|
||||
//logrus.Debugln(ctx.GetText(), children)
|
||||
functionList, ok := children[0].(*dae_config.FunctionPrototypeExpressionContext)
|
||||
if !ok {
|
||||
|
Loading…
Reference in New Issue
Block a user